messages.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import re
  2. from datetime import date
  3. from dataclasses import dataclass, asdict
  4. from enum import Enum
  5. from typing import Optional, Any
  6. from job_search.job_storage import (
  7. JobOffer,
  8. ApplicationProcess,
  9. JobOfferOrigin,
  10. Flexibility,
  11. )
  12. def to_snake_case(string):
  13. return "".join("_" + c.lower() if c.isupper() else c for c in string)
  14. class Message:
  15. ...
  16. class BackgroundScriptMessage(Message):
  17. @staticmethod
  18. def interpret(message):
  19. if not isinstance(message, dict):
  20. raise TypeError(f"message should be a dict, got {type(message)}")
  21. try:
  22. tag = message.pop("tag")
  23. match message.pop("values"):
  24. case []:
  25. values = {}
  26. case [v]:
  27. values = v
  28. except KeyError:
  29. raise ValueError("messages from background script should contain a tag and values")
  30. values = {to_snake_case(k): v for k, v in values.items()}
  31. match tag:
  32. case "NativeMessageInitialConfiguration":
  33. return InitialConfigurationMessage(**values)
  34. case "NativeMessageAddJob":
  35. return AddJobMessage(**values)
  36. case "NativeMessageListJobsRequest":
  37. return ListJobsRequestMessage(**values)
  38. case _:
  39. raise ValueError(f"Got message with unknown tag {tag}")
  40. class NativeMessage(Message):
  41. def serialize(self):
  42. raise NotImplementedError(f"No tag was associated to {type(self)} for serialization")
  43. @dataclass
  44. class AddJobMessage(BackgroundScriptMessage):
  45. id: str
  46. origin: str
  47. title: str
  48. url: str
  49. company: str
  50. location: Optional[str] = None
  51. company_domain: Optional[str] = None
  52. company_url: Optional[str] = None
  53. flexibility: Optional[Flexibility] = None
  54. application_process: Optional[ApplicationProcess] = None
  55. application_considered: Optional[bool] = None
  56. application_date: Optional[str] = None
  57. application_rejection_date: Optional[str] = None
  58. def serialize(self):
  59. return {"tag": "NativeMessageAddJob", "values": [asdict(self)]}
  60. @dataclass
  61. class ListJobsRequestMessage(BackgroundScriptMessage):
  62. pass
  63. @dataclass
  64. class InitialConfigurationMessage(BackgroundScriptMessage):
  65. jobs_path: str
  66. @dataclass
  67. class JobOfferListMessage(NativeMessage):
  68. job_offers: list[JobOffer]
  69. def serialize(self):
  70. return {"tag": "NativeMessageJobOfferList", "values": [self.job_offers]}
  71. @dataclass
  72. class StorageReadyMessage(NativeMessage):
  73. def serialize(self):
  74. return {"tag": "NativeMessageStorageReady", "values": []}
  75. @dataclass
  76. class JobAddedMessage(NativeMessage):
  77. job_id: str
  78. def serialize(self):
  79. return {"tag": "NativeMessageJobAdded", "values": [asdict(self)]}
  80. @dataclass
  81. class JobAlreadyExistsMessage(NativeMessage):
  82. job_id: str
  83. def serialize(self):
  84. return {"tag": "NativeMessageJobAlreadyExists", "values": [asdict(self)]}
  85. class LogLevel(Enum):
  86. DEBUG = "debug"
  87. INFO = "info"
  88. ERROR = "error"
  89. @dataclass
  90. class LogMessage(NativeMessage):
  91. level: LogLevel
  92. content: Any
  93. @staticmethod
  94. def debug(**kwargs):
  95. return LogMessage(level=LogLevel.DEBUG, **kwargs)
  96. @staticmethod
  97. def info(**kwargs):
  98. return LogMessage(level=LogLevel.INFO, **kwargs)
  99. @staticmethod
  100. def error(**kwargs):
  101. return LogMessage(level=LogLevel.ERROR, **kwargs)
  102. def serialize(self):
  103. return {"tag": "NativeMessageLog", "values": [asdict(self)]}