From 28ea90d53765af12c167702e2ac960f5270595f3 Mon Sep 17 00:00:00 2001 From: Abdellahi Mezid <135601200+Abdellahitech@users.noreply.github.com> Date: Mon, 8 Jan 2024 14:19:49 +0100 Subject: [PATCH] feat: connector jobology --- README.md | 1 + manifest.json | 204 ++++++++++++++++++ src/hrflow_connectors/__init__.py | 2 + .../connectors/jobology/README.md | 72 +++++++ .../connectors/jobology/__init__.py | 1 + .../connectors/jobology/connector.py | 83 +++++++ .../connectors/jobology/docs/catch_profile.md | 61 ++++++ .../connectors/jobology/logo.jpeg | Bin 0 -> 4813 bytes .../connectors/jobology/schemas.py | 20 ++ .../connectors/jobology/test-config.yaml | 96 +++++++++ .../connectors/jobology/warehouse.py | 55 +++++ 11 files changed, 595 insertions(+) create mode 100644 src/hrflow_connectors/connectors/jobology/README.md create mode 100644 src/hrflow_connectors/connectors/jobology/__init__.py create mode 100644 src/hrflow_connectors/connectors/jobology/connector.py create mode 100644 src/hrflow_connectors/connectors/jobology/docs/catch_profile.md create mode 100644 src/hrflow_connectors/connectors/jobology/logo.jpeg create mode 100644 src/hrflow_connectors/connectors/jobology/schemas.py create mode 100644 src/hrflow_connectors/connectors/jobology/test-config.yaml create mode 100644 src/hrflow_connectors/connectors/jobology/warehouse.py diff --git a/README.md b/README.md index 732448708..6cd1af05b 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,7 @@ We invite developers to join us in our mission to bring AI and data integration | **Indeed** | Job Board | π― | | | | **Inzojob** | Job Board | π― | | | | **Jobijoba** | Job Board | π― | | | +| [**Jobology**](./src/hrflow_connectors/connectors/jobology/README.md) | Job Board | :white_check_mark: | *21/12/2022* | *08/01/2024* | :x: | :x: | :x: | :x: | | **Jobrapido** | Job Board | π― | | | | **JobTeaser** | Job Board | π― | | | | **Jobtransport** | Job Board | π― | | | diff --git a/manifest.json b/manifest.json index 7bb5eb904..bad921f3e 100644 --- a/manifest.json +++ b/manifest.json @@ -25049,6 +25049,210 @@ ], "type": "ATS", "logo": "https://raw.githubusercontent.com/Riminder/hrflow-connectors/master/src/hrflow_connectors/connectors/digitalrecruiters/logo.png" + }, + { + "name": "Jobology", + "actions": [ + { + "name": "catch_profile", + "action_type": "inbound", + "action_parameters": { + "title": "TriggerViewActionParameters", + "type": "object", + "properties": { + "read_mode": { + "description": "If 'incremental' then `read_from` of the last run is given to Origin Warehouse during read. **The actual behavior depends on implementation of read**. In 'sync' mode `read_from` is neither fetched nor given to Origin Warehouse during read.", + "default": "sync", + "allOf": [ + { + "$ref": "#/definitions/ReadMode" + } + ] + }, + "logics": { + "title": "logics", + "description": "List of logic functions. Each function should have the following signature typing.Callable[[typing.Dict], typing.Optional[typing.Dict]]. The final list should be exposed in a variable named 'logics'.", + "template": "\nimport typing as t\n\ndef logic_1(item: t.Dict) -> t.Union[t.Dict, None]:\n return None\n\ndef logic_2(item: t.Dict) -> t.Uniont[t.Dict, None]:\n return None\n\nlogics = [logic_1, logic_2]\n", + "type": "code_editor" + }, + "format": { + "title": "format", + "description": "Formatting function. You should expose a function named 'format' with following signature typing.Callable[[typing.Dict], typing.Dict]", + "template": "\nimport typing as t\n\ndef format(item: t.Dict) -> t.Dict:\n return item\n", + "type": "code_editor" + }, + "event_parser": { + "title": "event_parser", + "description": "Event parsing function for **CATCH** integrations. You should expose a function named 'event_parser' with following signature typing.Callable[[typing.Dict], typing.Dict]", + "template": "\nimport typing as t\n\ndef event_parser(event: t.Dict) -> t.Dict:\n parsed = dict()\n parsed[\"user_id\"] = event[\"email\"]\n parsed[\"thread_id\"] = event[\"subscription_id\"]\n return parsed\n", + "type": "code_editor" + } + }, + "additionalProperties": false, + "definitions": { + "ReadMode": { + "title": "ReadMode", + "description": "An enumeration.", + "enum": [ + "sync", + "incremental" + ] + } + } + }, + "data_type": "profile", + "trigger_type": "hook", + "origin": "Jobology Candidate", + "origin_parameters": { + "title": "ReadProfilesParameters", + "type": "object", + "properties": { + "profile": { + "title": "Profile", + "description": "Event object recieved from the Webhook", + "field_type": "Other", + "type": "object" + } + }, + "additionalProperties": false + }, + "origin_data_schema": { + "title": "BaseModel", + "type": "object", + "properties": {} + }, + "supports_incremental": false, + "target": "HrFlow.ai Profile Parsing", + "target_parameters": { + "title": "WriteProfileParsingParameters", + "type": "object", + "properties": { + "api_secret": { + "title": "Api Secret", + "description": "X-API-KEY used to access HrFlow.ai API", + "field_type": "Auth", + "type": "string" + }, + "api_user": { + "title": "Api User", + "description": "X-USER-EMAIL used to access HrFlow.ai API", + "field_type": "Auth", + "type": "string" + }, + "source_key": { + "title": "Source Key", + "description": "HrFlow.ai source key", + "field_type": "Other", + "type": "string" + }, + "only_insert": { + "title": "Only Insert", + "description": "When enabled the profile is written only if it doesn't exist in the source", + "default": false, + "field_type": "Other", + "type": "boolean" + } + }, + "required": [ + "api_secret", + "api_user", + "source_key" + ], + "additionalProperties": false + }, + "target_data_schema": { + "title": "HrFlowProfileParsing", + "type": "object", + "properties": { + "reference": { + "title": "Reference", + "description": "Custom identifier of the Profile.", + "type": "string" + }, + "created_at": { + "title": "Created At", + "description": "type: datetime ISO8601, Creation date of the Profile.", + "type": "string" + }, + "resume": { + "$ref": "#/definitions/ResumeToParse" + }, + "tags": { + "title": "Tags", + "description": "List of tags of the Profile.", + "type": "array", + "items": { + "$ref": "#/definitions/GeneralEntitySchema" + } + }, + "metadatas": { + "title": "Metadatas", + "description": "List of metadatas of the Profile.", + "type": "array", + "items": { + "$ref": "#/definitions/GeneralEntitySchema" + } + } + }, + "required": [ + "reference", + "created_at", + "resume", + "tags", + "metadatas" + ], + "definitions": { + "ResumeToParse": { + "title": "ResumeToParse", + "type": "object", + "properties": { + "raw": { + "title": "Raw", + "type": "string", + "format": "binary" + }, + "content_type": { + "title": "Content Type", + "type": "string" + } + }, + "required": [ + "raw", + "content_type" + ] + }, + "GeneralEntitySchema": { + "title": "GeneralEntitySchema", + "type": "object", + "properties": { + "name": { + "title": "Name", + "description": "Identification name of the Object", + "type": "string" + }, + "value": { + "title": "Value", + "description": "Value associated to the Object's name", + "type": "string" + } + }, + "required": [ + "name" + ] + } + } + }, + "workflow_code": "import typing as t\n\nfrom hrflow_connectors import Jobology\nfrom hrflow_connectors.core.connector import ActionInitError, Reason\n\nORIGIN_SETTINGS_PREFIX = \"origin_\"\nTARGET_SETTINGS_PREFIX = \"target_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << event_parser_placeholder >>\n\n\ndef workflow(\n \n _request: t.Dict,\n \n settings: t.Dict\n ) -> None:\n actions_parameters = dict()\n try:\n format\n except NameError:\n pass\n else:\n actions_parameters[\"format\"] = format\n\n try:\n logics\n except NameError:\n pass\n else:\n actions_parameters[\"logics\"] = logics\n\n if \"__workflow_id\" not in settings:\n return Jobology.catch_profile(\n workflow_id=\"\",\n action_parameters=dict(),\n origin_parameters=dict(),\n target_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n try:\n event_parser\n _event_parser = event_parser\n except NameError as e:\n action = Jobology.model.action_by_name(\"catch_profile\")\n # Without this trick event_parser is always only fetched from the local scope\n # meaning that try block always raises NameError even if the function is\n # defined in the placeholder\n _event_parser = action.parameters.__fields__[\"event_parser\"].default\n\n if _event_parser is not None:\n try:\n _request = _event_parser(_request)\n except Exception as e:\n return Jobology.catch_profile(\n workflow_id=workflow_id,\n action_parameters=dict(),\n origin_parameters=dict(),\n target_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.event_parsing_failure,\n data=dict(error=e, event=_request),\n )\n )\n \n\n origin_parameters = dict()\n for parameter in ['profile']:\n if \"{}{}\".format(ORIGIN_SETTINGS_PREFIX, parameter) in settings:\n origin_parameters[parameter] = settings[\"{}{}\".format(ORIGIN_SETTINGS_PREFIX, parameter)]\n \n if parameter in _request:\n origin_parameters[parameter] = _request[parameter]\n \n\n target_parameters = dict()\n for parameter in ['api_secret', 'api_user', 'source_key', 'only_insert']:\n if \"{}{}\".format(TARGET_SETTINGS_PREFIX, parameter) in settings:\n target_parameters[parameter] = settings[\"{}{}\".format(TARGET_SETTINGS_PREFIX, parameter)]\n \n if parameter in _request:\n target_parameters[parameter] = _request[parameter]\n \n\n return Jobology.catch_profile(\n workflow_id=workflow_id,\n action_parameters=actions_parameters,\n origin_parameters=origin_parameters,\n target_parameters=target_parameters,\n )", + "workflow_code_format_placeholder": "# << format_placeholder >>", + "workflow_code_logics_placeholder": "# << logics_placeholder >>", + "workflow_code_event_parser_placeholder": "# << event_parser_placeholder >>", + "workflow_code_workflow_id_settings_key": "__workflow_id", + "workflow_code_origin_settings_prefix": "origin_", + "workflow_code_target_settings_prefix": "target_" + } + ], + "type": "Job Board", + "logo": "https://raw.githubusercontent.com/Riminder/hrflow-connectors/master/src/hrflow_connectors/connectors/jobology/logo.jpeg" } ] } \ No newline at end of file diff --git a/src/hrflow_connectors/__init__.py b/src/hrflow_connectors/__init__.py index 57adaf247..55ad43fc7 100644 --- a/src/hrflow_connectors/__init__.py +++ b/src/hrflow_connectors/__init__.py @@ -5,6 +5,7 @@ from hrflow_connectors.connectors.digitalrecruiters import DigitalRecruiters from hrflow_connectors.connectors.greenhouse.connector import Greenhouse from hrflow_connectors.connectors.hubspot import Hubspot +from hrflow_connectors.connectors.jobology import Jobology from hrflow_connectors.connectors.lever import Lever from hrflow_connectors.connectors.poleemploi import PoleEmploi from hrflow_connectors.connectors.recruitee import Recruitee @@ -40,6 +41,7 @@ Lever, Salesforce, DigitalRecruiters, + Jobology, ] # This makes sure that connector are in module namespace diff --git a/src/hrflow_connectors/connectors/jobology/README.md b/src/hrflow_connectors/connectors/jobology/README.md new file mode 100644 index 000000000..9aff45bc0 --- /dev/null +++ b/src/hrflow_connectors/connectors/jobology/README.md @@ -0,0 +1,72 @@ +# π Summary +- [π Summary](#-summary) +- [πΌ About Jobology](#-about-jobology) + - [π Why is it a big deal for Jobology customers & partners?](#-why-is-it-a-big-deal-for-jobology-customers--partners) +- [π§ How does it work?](#-how-does-it-work) + - [π Data integration capabilities:](#-data-integration-capabilities) +- [π Connector Actions](#-connector-actions) +- [π Quick Start Examples](#-quick-start-examples) +- [π Useful Links](#-useful-links) +- [π Special Thanks](#-special-thanks) + + +# πΌ About Jobology + +> La mission de jobology est de faciliter le processus de recrutement pour les entreprises + + +## π Why is it a big deal for Jobology customers & partners? + +This new connector will enable: +- β‘ A Fastlane Talent & Workforce data integration for Jobology customers & partners +- π€ Cutting-edge AI-powered Talent Experiences & Recruiter Experiences for Jobology customers + +# π§ How does it work? +## π Data integration capabilities: +- β¬ οΈ Send Profiles data from Jobology to a Destination of your choice: + + + + + +# π Connector Actions +
+ +| Action | Description | +| ------- | ----------- | +| [**Catch profile**](docs/catch_profile.md) | Imports candidates, in synchronization with jobology | + + +
+ +
+
+
{#;ROUp&YXS*b}lQ$AeJ zrth$eRLBZHu5^x4tLi9${WkuAH6tkLQcqAwP)i6bQ-Qh{EMlX%t*>7J zcv?Rl9i24<_v_;M8DrmO<&IzB6#!Q&-(X$jC?D>30NF4Wt8YAKcl5ZRR62_k;6!k? z)trPZkCnhCj?*})FA2;SJjLhbL*S4Equ_&Beg`n8*DSlut07-Gi};ptH4Rpz-t7nY zgfofUh6~MK2lmsy+5IHIs?|e><)gK6UR-cjF*^|nERQ6(`sqtn(tcO_ cd7=@?e$t@_4}URWsTbT zmFCY#rD9n706 uW2HDF zYcrZtwXqVL3**qlewSmLa$KiN?rew*17$9OU(*J^jz2xrV}TgYu3$nGTZq(o=sxS< zFpk*qu4j|$j($j;VNr6o6r!XfRu+(oQs_3}k+j{hpkL_ 3yW-s`@lZAPh^h5ePAowY9?lBD7EBoV2$o&|8P#RcUG7xpn)(ymSaD vS%O`{yKT0$1t8WF=;ekY4 zs2mmEhOd)7g3~jx<^A;$QO_M4cq(#J&?oqq{7k5IP{*5Iwd6Mke4j))!#WaF6^uQ& zoIiBo!zR4B5N|mM8ArFqNRSqU7lMz7SSWwk$y#~?(HY-ve)6_(qqOHY&bPQ@&}&NL zUfadJXnCP|?!nBdn*ueipf%?@OB}oc*j3)U_bb&pX63zU8+UFGF4rQ1tZO6K@gf%Q zJGkmr`xUY;cysG^nT3<@SADmwy4;~Aw^X$+d8(N`2z{IU;(-Bys84`bfFmhTQv;>> zm&^f|f;xTidQ>d=+9Fwl4GW9>Gs=N1moFdn4pY%EVRsSkZ?aYLkF1=|CF@H%CopOY zkAS<%12cBtrQR>5%*vTp_;&vG2tKQVh@az^w&$3+GiPl&g1!1TYR%D0`1uCtWpAEa zv%f&X9G@Ir-Mr7a6&r@Eg9JtC$%bP^S;d`T6!s$tPJx(B)BR2HP(0Sb9U=c%V_6t< zM(ucJ@FL97vB*yQ))!uD|D-3kH=ZCJyROHUjn*JFZK0D>xR}?>Z1`TQY7%?jX3T^4 z-?8doNpsn`$}W?YdCho@0xWf|Zwx*Cig_s)V!qJu3cw&MNq`rPOR^s14Lvt55K0j) z%`XqTcQ|~9!XwP=W 2igf*Y#A&jJ-+@7ey)%C-=xK8NsOjZ$ncK#lzrMiXS( &_i4-;NwW47VXN*ym -co=0Kl)jU}4Ai zSjqK{LrePdmtVyaM`CyIE}pb3UC=*|I^T%l7ni1dGAS8R!!Os(%VOiYkMXGNL@#(y zu3bRg{lZTUXM!*DMkkz{UF%~aH3&`|ES=)PBfrV?VMK}JY)UQT3?Hmik;S?SD`Xiz z!Ob)m0Cp=M@5`jmBY%9xpjkhoQEzB2jgr5U9?sNrD_$HKLL-KYUN@AiJq+e~Y9Cl_ zzPH;9MALYjK