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 | + + +

+ +

+ +

+ + +# πŸ’ Quick Start Examples + +To make sure you can successfully run the latest versions of the example scripts, you have to **install the package from PyPi**. + + +To browse the examples of actions corresponding to released versions of πŸ€— this connector, you just need to import the module like this : + +

+ +

+ + +Once the connector module is imported, you can leverage all the different actions that it offers. + +For more code details checkout connector code. + + +# πŸ”— Useful Links + +- πŸ“„Visit [Jobology](https://www.jobology.com/) to learn more. +- πŸ’» [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/connectors/jobology) on our Github. + + +# πŸ‘ Special Thanks +- πŸ’» HrFlow.ai : Abdellahi Mezid - Software Engineer +- 🀝 Jobology : Jobology Team \ No newline at end of file diff --git a/src/hrflow_connectors/connectors/jobology/__init__.py b/src/hrflow_connectors/connectors/jobology/__init__.py new file mode 100644 index 000000000..a077e33fd --- /dev/null +++ b/src/hrflow_connectors/connectors/jobology/__init__.py @@ -0,0 +1 @@ +from hrflow_connectors.connectors.jobology.connector import Jobology # noqa diff --git a/src/hrflow_connectors/connectors/jobology/connector.py b/src/hrflow_connectors/connectors/jobology/connector.py new file mode 100644 index 000000000..0f20c139a --- /dev/null +++ b/src/hrflow_connectors/connectors/jobology/connector.py @@ -0,0 +1,83 @@ +import typing as t + +from hrflow_connectors.connectors.hrflow.warehouse import HrFlowProfileParsingWarehouse +from hrflow_connectors.connectors.jobology.warehouse import JobologyProfilesWarehouse +from hrflow_connectors.core import ( + ActionName, + ActionType, + BaseActionParameters, + Connector, + ConnectorAction, + ConnectorType, + WorkflowType, +) + + +def rename_profile_fields(jobology_profile: t.Dict) -> t.Dict: + return { + "job-key": jobology_profile["jobkey"], + "first_name": jobology_profile.get("firstName"), + "last_name": jobology_profile.get("lastName"), + "phone": jobology_profile.get("phone"), + "email": jobology_profile.get("email"), + "coverText": jobology_profile.get("coverText"), + "profile-country": jobology_profile.get("profilecountry"), + "profile-regions": jobology_profile.get("profileregions"), + "profile-domains": jobology_profile.get("profiledomains"), + "job-lien_annonce_site_carriere": jobology_profile.get( + "joblien_annonce_site_carriere" + ), + "statistic-source": jobology_profile.get("statisticsource"), + "statistic-jbsource": jobology_profile.get("statisticjbsource"), + } + + +def add_tags(profile_tags: t.Dict) -> t.List[t.Dict]: + return [dict(name=key, value=value) for key, value in profile_tags.items() if value] + + +def format_jobology_profile(jobology_profile: t.List) -> t.Dict: + profile_tags = rename_profile_fields(jobology_profile) + tags = add_tags(profile_tags) + resume_dict = dict( + raw=jobology_profile["cv"], + content_type=jobology_profile["content_type"], + ) + return dict( + reference=jobology_profile["email"], + resume=resume_dict, + tags=tags, + metadatas=[], + created_at=None, + ) + + +def event_parser(event: t.Dict) -> t.Dict: + return dict(profile=event) + + +DESCRIPTION = ( + "La mission de jobology est de faciliter le processus de recrutement pour les" + " entreprises " +) +Jobology = Connector( + name="Jobology", + type=ConnectorType.JobBoard, + description=DESCRIPTION, + url="https://www.jobology.fr/", + actions=[ + ConnectorAction( + name=ActionName.catch_profile, + trigger_type=WorkflowType.catch, + description="Imports candidates, in synchronization with jobology", + parameters=BaseActionParameters.with_defaults( + "TriggerViewActionParameters", + format=format_jobology_profile, + event_parser=event_parser, + ), + origin=JobologyProfilesWarehouse, + target=HrFlowProfileParsingWarehouse, + action_type=ActionType.inbound, + ) + ], +) diff --git a/src/hrflow_connectors/connectors/jobology/docs/catch_profile.md b/src/hrflow_connectors/connectors/jobology/docs/catch_profile.md new file mode 100644 index 000000000..86a79e4ce --- /dev/null +++ b/src/hrflow_connectors/connectors/jobology/docs/catch_profile.md @@ -0,0 +1,61 @@ +# Catch profile +`Jobology Candidate` :arrow_right: `HrFlow.ai Profile Parsing` + +Imports candidates, in synchronization with jobology + + + +## Action Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `logics` | `typing.List[typing.Callable[[typing.Dict], typing.Optional[typing.Dict]]]` | [] | List of logic functions | +| `format` | `typing.Callable[[typing.Dict], typing.Dict]` | [`format_jobology_profile`](../connector.py#L39) | Formatting function | +| `read_mode` | `str` | ReadMode.sync | 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. | + +## Source Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `profile` | `typing.Dict` | None | Event object recieved from the Webhook | + +## Destination Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `api_secret` :red_circle: | `str` | None | X-API-KEY used to access HrFlow.ai API | +| `api_user` :red_circle: | `str` | None | X-USER-EMAIL used to access HrFlow.ai API | +| `source_key` :red_circle: | `str` | None | HrFlow.ai source key | +| `only_insert` | `bool` | False | When enabled the profile is written only if it doesn't exist in the source | + +:red_circle: : *required* + +## Example + +```python +import logging +from hrflow_connectors import Jobology +from hrflow_connectors.core import ReadMode + + +logging.basicConfig(level=logging.INFO) + + +Jobology.catch_profile( + workflow_id="some_string_identifier", + action_parameters=dict( + logics=[], + format=lambda *args, **kwargs: None # Put your code logic here, + read_mode=ReadMode.sync, + ), + origin_parameters=dict( + profile=***, + ), + target_parameters=dict( + api_secret="your_api_secret", + api_user="your_api_user", + source_key="your_source_key", + only_insert=False, + ) +) +``` \ No newline at end of file diff --git a/src/hrflow_connectors/connectors/jobology/logo.jpeg b/src/hrflow_connectors/connectors/jobology/logo.jpeg new file mode 100644 index 000000000..bdafbe3cf Binary files /dev/null and b/src/hrflow_connectors/connectors/jobology/logo.jpeg differ diff --git a/src/hrflow_connectors/connectors/jobology/schemas.py b/src/hrflow_connectors/connectors/jobology/schemas.py new file mode 100644 index 000000000..e5a0784ea --- /dev/null +++ b/src/hrflow_connectors/connectors/jobology/schemas.py @@ -0,0 +1,20 @@ +import typing as t + +from pydantic import BaseModel + + +class jobologyEventObject(BaseModel): + type: str + jobkey: t.Optional[str] + firstName: t.Optional[str] + lastName: t.Optional[str] + phone: t.Optional[str] + email: str + cvUrl: str + coverText: t.Optional[str] + profilecountry: t.Optional[str] + profileregions: t.Optional[str] + profiledomains: t.Optional[str] + joblien_annonce_site_carriere: t.Optional[str] + statisticsource: t.Optional[str] + statisticjbsource: t.Optional[str] diff --git a/src/hrflow_connectors/connectors/jobology/test-config.yaml b/src/hrflow_connectors/connectors/jobology/test-config.yaml new file mode 100644 index 000000000..33eeeed09 --- /dev/null +++ b/src/hrflow_connectors/connectors/jobology/test-config.yaml @@ -0,0 +1,96 @@ +warehouse: + JobologyProfilesWarehouse: + read: + - parameters: + profile: { + "type":"jobology_direct_apply", + "jobkey":" JO-0145781_1701343287", + "firstName":"Abdellahi", + "lastName":"Mezid", + "phone":"0611423374", + "email":"pierre.dupont@mailprovider.com", + "cvUrl":"https://riminder-documents-eu-2019-12.s3-eu-west-1.amazonaws.com/teams/fc9d40fd60e679119130ea74ae1d34a3e22174f2/sources/e6159e65395995ae9f69a90ce916f7b6f90823dd/profiles/ab1c521d49b73d321bd54f6f6d3a4d81a31835eb/parsing/original.pdf", + "coverText":"Ceci est le texte de motivation.\nCe champ peut contenir des retours Γ  la ligne.", + "profilecountry": "France", + "profileregions": "Ile-de-france", + "profiledomains": "Chauffeur SPL, Chauffeur routier, Chauffeur", + "joblien_annonce_site_carriere": "https://www.jobtransport.com/offre-emploi/approvisionneur-h-f-ecquevilly-2476964.aspx", + "statisticsource": "Groupe Fed", + "statisticjbsource": "jobology", + } +actions: + catch_profile: + - id: no_hrflow_source_key + origin_parameters: + profile: { + "type":"jobology_direct_apply", + "jobkey":" JO-0145781_1701343287", + "firstName":"Abdellahi", + "lastName":"Mezid", + "phone":"0611423374", + "email":"pierre.dupont@mailprovider.com", + "cvUrl":"https://riminder-documents-eu-2019-12.s3-eu-west-1.amazonaws.com/teams/fc9d40fd60e679119130ea74ae1d34a3e22174f2/sources/e6159e65395995ae9f69a90ce916f7b6f90823dd/profiles/ab1c521d49b73d321bd54f6f6d3a4d81a31835eb/parsing/original.pdf", + "coverText":"Ceci est le texte de motivation.\nCe champ peut contenir des retours Γ  la ligne.", + "profilecountry": "France", + "profileregions": "Ile-de-france", + "profiledomains": "Chauffeur SPL, Chauffeur routier, Chauffeur", + "joblien_annonce_site_carriere": "https://www.jobtransport.com/offre-emploi/approvisionneur-h-f-ecquevilly-2476964.aspx", + "statisticsource": "Groupe Fed", + "statisticjbsource": "jobology", + } + target_parameters: + api_secret: $__API_SECRET + api_user: $__API_USER + only_insert: false + status: fatal + reason: bad_target_parameters + - id: invalid_hrflow_api_secret + origin_parameters: + profile: { + "type":"jobology_direct_apply", + "jobkey":" JO-0145781_1701343287", + "firstName":"Abdellahi", + "lastName":"Mezid", + "phone":"0611423374", + "email":"pierre.dupont@mailprovider.com", + "cvUrl":"https://riminder-documents-eu-2019-12.s3-eu-west-1.amazonaws.com/teams/fc9d40fd60e679119130ea74ae1d34a3e22174f2/sources/e6159e65395995ae9f69a90ce916f7b6f90823dd/profiles/ab1c521d49b73d321bd54f6f6d3a4d81a31835eb/parsing/original.pdf", + "coverText":"Ceci est le texte de motivation.\nCe champ peut contenir des retours Γ  la ligne.", + "profilecountry": "France", + "profileregions": "Ile-de-france", + "profiledomains": "Chauffeur SPL, Chauffeur routier, Chauffeur", + "joblien_annonce_site_carriere": "https://www.jobtransport.com/offre-emploi/approvisionneur-h-f-ecquevilly-2476964.aspx", + "statisticsource": "Groupe Fed", + "statisticjbsource": "jobology", + } + target_parameters: + api_secret: bad_api_secret + api_user: $__API_USER + source_key: $__SOURCE_KEY + only_insert: false + status: fatal + reason: write_failure + - id: write_success + origin_parameters: + profile: { + "type":"jobology_direct_apply", + "jobkey":" JO-0145781_1701343287", + "firstName":"Abdellahi", + "lastName":"Mezid", + "phone":"0611423374", + "email":"pierre.dupont@mailprovider.com", + "cvUrl":"https://riminder-documents-eu-2019-12.s3-eu-west-1.amazonaws.com/teams/fc9d40fd60e679119130ea74ae1d34a3e22174f2/sources/e6159e65395995ae9f69a90ce916f7b6f90823dd/profiles/ab1c521d49b73d321bd54f6f6d3a4d81a31835eb/parsing/original.pdf", + "coverText":"Ceci est le texte de motivation.\nCe champ peut contenir des retours Γ  la ligne.", + "profilecountry": "France", + "profileregions": "Ile-de-france", + "profiledomains": "Chauffeur SPL, Chauffeur routier, Chauffeur", + "joblien_annonce_site_carriere": "https://www.jobtransport.com/offre-emploi/approvisionneur-h-f-ecquevilly-2476964.aspx", + "statisticsource": "Groupe Fed", + "statisticjbsource": "jobology", + } + target_parameters: + api_secret: $__API_SECRET + api_user: $__API_USER + source_key: $__SOURCE_KEY + only_insert: false + status: success + \ No newline at end of file diff --git a/src/hrflow_connectors/connectors/jobology/warehouse.py b/src/hrflow_connectors/connectors/jobology/warehouse.py new file mode 100644 index 000000000..d90716284 --- /dev/null +++ b/src/hrflow_connectors/connectors/jobology/warehouse.py @@ -0,0 +1,55 @@ +import typing as t +from logging import LoggerAdapter + +import requests +from pydantic import Field + +from hrflow_connectors.core import ( + DataType, + FieldType, + ParametersModel, + ReadMode, + Warehouse, + WarehouseReadAction, +) + + +class ReadProfilesParameters(ParametersModel): + profile: t.Dict = Field( + None, + description="Event object recieved from the Webhook", + field_type=FieldType.Other, + ) + + +def read( + adapter: LoggerAdapter, + parameters: ReadProfilesParameters, + read_mode: t.Optional[ReadMode] = None, + read_from: t.Optional[str] = None, +) -> t.Iterable[t.Dict]: + result = {**parameters.profile} + cv_url = result["cvUrl"] + response = requests.get(cv_url) + if response.status_code == 200: + result["cv"] = response.content + result["content_type"] = response.headers["Content-Type"] + elif response.status_code == 400: + raise Exception(f"Bad Request {response.text}") + else: + raise Exception( + f"request failed with status code {response.status_code} and message" + f" {response.text}" + ) + + return [result] + + +JobologyProfilesWarehouse = Warehouse( + name="Jobology Candidate", + data_type=DataType.profile, + read=WarehouseReadAction( + parameters=ReadProfilesParameters, + function=read, + ), +)