diff --git a/sigeca_data_export_microservice/app/application/scheduler/sigeca_data_export_scheduler.py b/sigeca_data_export_microservice/app/application/scheduler/sigeca_data_export_scheduler.py index 38b4225..931fd75 100644 --- a/sigeca_data_export_microservice/app/application/scheduler/sigeca_data_export_scheduler.py +++ b/sigeca_data_export_microservice/app/application/scheduler/sigeca_data_export_scheduler.py @@ -1,7 +1,7 @@ from typing import List from apscheduler.schedulers.background import BlockingScheduler from app.application.services.sigeca_data_export_service import DataSyncService -from app.infrastructure.api import ResourceAPIClient +from app.infrastructure.api import SigecaApiClient from app.infrastructure.utils import ChangeLogOperationEnum from sqlalchemy.orm import sessionmaker from app.infrastructure.repository import SyncLogRepository diff --git a/sigeca_data_export_microservice/app/infrastructure/__init__.py b/sigeca_data_export_microservice/app/infrastructure/__init__.py index 9464adf..9b4e48d 100644 --- a/sigeca_data_export_microservice/app/infrastructure/__init__.py +++ b/sigeca_data_export_microservice/app/infrastructure/__init__.py @@ -1,3 +1,3 @@ from .jdbc_reader import JDBCReader from .utils import ChangeLogOperationEnum -from .api import ResourceAPIClient +from .api import SigecaApiClient diff --git a/sigeca_data_export_microservice/app/infrastructure/api.py b/sigeca_data_export_microservice/app/infrastructure/api.py index 13b11a9..079790f 100644 --- a/sigeca_data_export_microservice/app/infrastructure/api.py +++ b/sigeca_data_export_microservice/app/infrastructure/api.py @@ -1,20 +1,59 @@ import requests -from typing import Any, Dict -from .utils import ChangeLogOperationEnum +import logging -class ResourceAPIClient: - def __init__(self, api_url: str, token: str): +class SigecaApiClient: + LOGIN_URI = "token/" + SYNC_URI = "sync/" + + def __init__(self, api_config: dict): + api_url: str = api_config["api_url"] + headers: str = api_config["headers"] + self.credentials = api_config['credentials'] + self.skip_verification: bool = api_config.get('skip_verification') or False + + if api_url.endswith("/"): + api_url = api_url[:-1] + self.api_url = api_url - self.token = token self.headers = { - "Authorization": f"Bearer {self.token}", - "Content-Type": "application/json", + # Required for avoid openLMIS 401 Unauthorized during login + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0", + **headers, } - def send_data( - self, resource: str, operation: ChangeLogOperationEnum, data: Dict[str, Any] - ) -> Dict[str, Any]: - endpoint = f"{self.api_url}/{resource}/{operation.value}" - response = requests.post(endpoint, json=data, headers=self.headers) - return response.json() + def sync(self, json_data=None): + if not isinstance(json_data, list): + logging.error( + f"Attempt to sync invalid payload: {json_data}" + ) + raise Exception("Attempt to sync invalid payload") + + self._get_token() + url = f"{self.api_url}/{self.SYNC_URI}" + + response = requests.post(url, json=json_data, headers=self.headers, verify=not self.skip_verification) + + if response.status_code == 200: + return True + else: + logging.error( + f"Failed to sync data with sigeca central API: {response.status_code} {response}" + ) + raise Exception("Failed to sync data with sigeca central API") + + def _get_token(self): + """Login to get access token""" + url = f"{self.api_url}/{self.LOGIN_URI}" + data = self.credentials + + response = requests.post(url, headers=self.headers, data=data, verify=not self.skip_verification) + + if response.status_code == 200: + self.token = response.json().get("access_token") + self.headers['Authorization'] = F"Bearer {self.token}" + else: + logging.error( + f"Failed to log into OpenLMIS API: {response.status_code} {response}" + ) + raise Exception("Failed to log into sigeca central API") \ No newline at end of file diff --git a/sigeca_data_export_microservice/config_example.json b/sigeca_data_export_microservice/config_example.json index 211d57c..d98b303 100644 --- a/sigeca_data_export_microservice/config_example.json +++ b/sigeca_data_export_microservice/config_example.json @@ -1,23 +1,28 @@ { - "api": { - "url": "https://api.example.com", // URL of the external API to which data will be synchronized - "token": "your_api_token" // Authentication token for accessing the external API + "sigeca_api" : { + "api_url": "https://example.com/api", + "headers": {}, + "credentials": { + "username": "username", + "password": "password" + }, + "skip_verification": false }, "changelog_database": { - "username": "user1", // Username for the database used to store synchronization logs - "password": "password1", // Password for the database user - "host": "localhost", // Hostname or IP address of the database server - "port": 5432, // Port number on which the database server is listening - "database": "database" // Name of the database + "username": "user1", + "password": "password1", + "host": "localhost", + "port": 5432, + "database": "database" }, - "jdbc_reader": { - "jdbc_url": "jdbc:postgresql://localhost:5432/database", // JDBC URL for connecting to the database - "jdbc_user": "user1", // Username for the database used by JDBC Reader - "jdbc_password": "password1", // Password for the database user used by JDBC Reader - "jdbc_driver": "org.postgresql.Driver", // JDBC driver class for PostgreSQL - "log_level": "INFO" // Log level for JDBC operations (e.g., INFO, DEBUG) + "jdbc_reader": { + "jdbc_url": "jdbc:postgresql://localhost:5432/database", + "jdbc_user": "user1", + "jdbc_password": "password1", + "jdbc_driver": "org.postgresql.Driver", + "log_level": "INFO" }, "sync": { - "interval_minutes": 0.2 // Synchronization interval in minutes (0.2 minutes = 12 seconds for quick testing) + "interval_minutes": 0.2 } } diff --git a/sigeca_data_export_microservice/main.py b/sigeca_data_export_microservice/main.py index f8176bb..96e338f 100644 --- a/sigeca_data_export_microservice/main.py +++ b/sigeca_data_export_microservice/main.py @@ -12,7 +12,7 @@ from app.application.scheduler.sigeca_data_export_scheduler import ChangesSyncScheduler from app.application.synchronizations import FacilityResourceSynchronization from app.infrastructure import (ChangeLogOperationEnum, JDBCReader, - ResourceAPIClient) + SigecaApiClient) from app.infrastructure.database import Base, get_engine, get_session @@ -46,7 +46,7 @@ def main(): Base.metadata.create_all(engine) jdbc_reader = JDBCReader(config["jdbc_reader"]) - api_client = ResourceAPIClient(config["api"]["url"], config["api"]["token"]) + api_client = SigecaApiClient(config["sigeca_api"]) sigeca_data_export_service = DataSyncService(session_maker) sync_interval_minutes = config["sync"]["interval_minutes"]