Parcourir la source

Make companies a separate record in storage

jherve il y a 1 an
Parent
commit
2beda27e0c

+ 14 - 3
native/src/job_search/job_storage.py

@@ -71,9 +71,18 @@ class JobStorage:
                 f.write("%type: flexibility enum on_site hybrid full_remote\n")
                 f.write("%type: first_seen_date date\n")
                 f.write("%auto: first_seen_date\n")
+                f.write("\n")
+                f.write("%rec: company")
+                f.write("%key: name")
+                f.write("%allowed: kind url domain")
+                f.write("%type: kind enum regular head_hunter ssii start_up")
+                f.write("%unique: kind")
+                f.write("%unique: url")
+                f.write("%unique: domain")
+                f.write("\n")
 
     def read_all(self) -> dict[str, dict]:
-        return {r["id"]: r for r in self.select_all("job_offer")}
+        return {r["id"]: r for r in self.select_all("job_offer", "company")}
 
     def insert_record(self, type_, fields):
         cmd_args = [
@@ -97,6 +106,8 @@ class JobStorage:
                 raise ValueError(f"Found invalid enum value in {fields}")
             elif "error: duplicated key value in field 'id' in record" in first:
                 raise FileExistsError(f"Duplicate value {fields['id']}")
+            elif "error: duplicated key value in field 'name' in record" in first:
+                raise FileExistsError(f"Duplicate value {fields['name']}")
             else:
                 raise ValueError(
                     f"insert command failed with code {code} :\n{process.stderr}"
@@ -118,8 +129,8 @@ class JobStorage:
                 args += [(k, v)]
         return args
 
-    def select_all(self, type_):
-        cmd = ["recsel", "-t", type_, str(self.rec_file_path)]
+    def select_all(self, type_, join):
+        cmd = ["recsel", "-t", type_, "-j", join, str(self.rec_file_path)]
         process = subprocess.run(cmd, stdout=subprocess.PIPE, universal_newlines=True)
 
         if (code := process.returncode) != 0:

+ 31 - 1
native/src/job_search/messages.py

@@ -34,6 +34,8 @@ class BackgroundScriptMessage(Message):
                 return InitialConfigurationMessage(**values)
             case "NativeMessageAddJob":
                 return AddJobMessage(values=values)
+            case "NativeMessageAddCompany":
+                return AddCompanyMessage(values=values)
             case "NativeMessageListJobsRequest":
                 return ListJobsRequestMessage(**values)
             case _:
@@ -48,7 +50,7 @@ class NativeMessage(Message):
 @dataclass
 class AddJobMessage(BackgroundScriptMessage):
     """
-    Only for this message we trust the frontend to send data in an appropriate
+    For this message we trust the frontend to send data in an appropriate
     format.
     """
     values: dict
@@ -57,6 +59,18 @@ class AddJobMessage(BackgroundScriptMessage):
         return {"tag": "NativeMessageAddJob", "values": [self.values]}
 
 
+@dataclass
+class AddCompanyMessage(BackgroundScriptMessage):
+    """
+    For this message we trust the frontend to send data in an appropriate
+    format.
+    """
+    values: dict
+
+    def serialize(self):
+        return {"tag": "NativeMessageAddCompany", "values": [self.values]}
+
+
 @dataclass
 class ListJobsRequestMessage(BackgroundScriptMessage):
     pass
@@ -102,6 +116,22 @@ class JobAlreadyExistsMessage(NativeMessage):
         return {"tag": "NativeMessageJobAlreadyExists", "values": [asdict(self)]}
 
 
+@dataclass
+class CompanyAddedMessage(NativeMessage):
+    name: str
+
+    def serialize(self):
+        return {"tag": "NativeMessageCompanyAdded", "values": [asdict(self)]}
+
+
+@dataclass
+class CompanyAlreadyExistsMessage(NativeMessage):
+    name: str
+
+    def serialize(self):
+        return {"tag": "NativeMessageCompanyAlreadyExists", "values": [asdict(self)]}
+
+
 class LogLevel(Enum):
     DEBUG = "debug"
     INFO = "info"

+ 15 - 0
native/src/job_search/writer.py

@@ -9,6 +9,7 @@ from job_search.read_write import ReadWriter
 from job_search.job_storage import JobStorage
 from job_search.messages import (
     AddJobMessage,
+    AddCompanyMessage,
     InitialConfigurationMessage,
     StorageReadyMessage,
     StorageUpdatedMessage,
@@ -18,6 +19,8 @@ from job_search.messages import (
     Message,
     JobAddedMessage,
     JobAlreadyExistsMessage,
+    CompanyAddedMessage,
+    CompanyAlreadyExistsMessage,
 )
 
 
@@ -35,6 +38,13 @@ class Application:
                 except FileExistsError as e:
                     self.read_writer.send_message(JobAlreadyExistsMessage(values["id"]))
 
+            case AddCompanyMessage(values=values):
+                try:
+                    self.job_storage.insert_record("company", values)
+                    self.read_writer.send_message(CompanyAddedMessage(values["name"]))
+                except FileExistsError as e:
+                    self.read_writer.send_message(CompanyAlreadyExistsMessage(values["name"]))
+
             case ListJobsRequestMessage():
                 offers = list(self.job_storage.read_all().values())
                 self.read_writer.send_message(JobOfferListMessage(offers))
@@ -43,6 +53,11 @@ class Application:
                 self.job_storage = JobStorage(base_dir=Path(jobs_path))
                 self.read_writer.send_message(StorageReadyMessage())
 
+            case _:
+                self.read_writer.send_message(
+                    LogMessage.error(content=f"Received unhandled message : {message}")
+                )
+
     async def loop_on_messages(self):
         loop = asyncio.get_running_loop()
         while True:

+ 11 - 6
src/Background.purs

@@ -42,11 +42,12 @@ contentScriptMessageHandler
   port
   (RuntimeMessagePageContent (UrlJobOffer (JobOfferId jobId)) (OutJobOffer offer))
   (MessageSender {tab: Just {id, url}}) =
-    case maybeMsg offer of
-      Just msg -> do
-        sendMessageToNative port msg
+    case maybeMsg offer, maybeCompany offer of
+      Just msgJob, Just msgCompany -> do
+        sendMessageToNative port msgJob
+        sendMessageToNative port msgCompany
         displayBadgeUntilClick id "OK" "green"
-      Nothing -> do
+      _, _ -> do
         error "Job offer sent by content script could not be sent"
         displayBadgeUntilClick id "KO" "red"
 
@@ -60,12 +61,16 @@ contentScriptMessageHandler
         url,
         company: jo.companyName,
         location: jo.location,
-        company_domain: jo.companyDomain,
-        company_url: Just jo.companyLink,
         flexibility: jo.flexibility,
         application_process: Just $ if jo.hasSimplifiedApplicationProcess then ApplicationProcessLinkedInSimplified else ApplicationProcessRegular
       }
 
+    maybeCompany (JobOffer jo) = Just $ NativeMessageAddCompany {
+        name: jo.companyName,
+        domain: jo.companyDomain,
+        url: Just jo.companyLink
+      }
+
 contentScriptMessageHandler
   _
   (RuntimeMessageError err)

+ 11 - 3
src/NativeMessage.purs

@@ -28,10 +28,13 @@ data NativeMessage =
   | NativeMessageStorageReady
   | NativeMessageStorageUpdated
   | NativeMessageAddJob NewJobOffer
+  | NativeMessageAddCompany NewCompany
   | NativeMessageListJobsRequest
   | NativeMessageJobAlreadyExists {job_id :: String}
   | NativeMessageJobAdded {job_id :: String}
   | NativeMessageJobOfferList (Array NativePythonJobOffer)
+  | NativeMessageCompanyAlreadyExists {name :: String}
+  | NativeMessageCompanyAdded {name :: String}
 
 data ApplicationProcess
   = ApplicationProcessLinkedInSimplified
@@ -78,9 +81,10 @@ type NativePythonJobOffer = {
   title :: String,
   url :: String,
   alternate_url :: Maybe String,
-  company :: String,
+  company_name :: String,
   location :: Maybe String,
   company_domain :: Maybe String,
+  company_kind :: Maybe String,
   company_url :: Maybe String,
   flexibility :: Maybe JobFlexibility,
   comment :: Maybe String,
@@ -98,12 +102,16 @@ type NewJobOffer = {
   url :: String,
   company :: String,
   location :: Maybe String,
-  company_domain :: Maybe String,
-  company_url :: Maybe String,
   flexibility :: Maybe JobFlexibility,
   application_process :: Maybe ApplicationProcess
 }
 
+type NewCompany = {
+  name :: String,
+  domain :: Maybe String,
+  url :: Maybe String
+}
+
 derive instance Generic NativeMessage _
 instance Show NativeMessage where show a = genericShow a
 instance EncodeJson NativeMessage where encodeJson a = genericEncodeJson a

+ 1 - 1
src/sidebar.js

@@ -17,7 +17,7 @@ function createJob (job) {
     const li = document.createElement("li");
 
     li.appendChild(elWithText("h2", job.title));
-    li.appendChild(elWithText("h3", job.company));
+    li.appendChild(elWithText("h3", job.company_name));
     li.appendChild(link("Job offer link", job.url));
 
     if (job.company_url)