Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [AXM-1227, AXM-1235, AXM-1242] accredible models, client and sy… #187

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions credentials/apps/badges/accredible/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from credentials.apps.badges.base_api_client import BaseBadgeProviderClient
from credentials.apps.badges.accredible.data import AccredibleBadgeData, AccredibleExpireBadgeData
from credentials.apps.badges.accredible.utils import get_accredible_api_base_url
from credentials.apps.badges.accredible.exceptions import AccredibleError


logger = logging.getLogger(__name__)
Expand All @@ -18,24 +19,38 @@ class AccredibleAPIClient(BaseBadgeProviderClient):

This class provides methods for performing various operations on the Accredible API.
"""

PROVIDER_NAME = "Accredible"

def __init__(self, api_config: AccredibleAPIConfig):
def __init__(self, api_config_id: int):
"""
Initializes a AccredibleAPIClient object.

Args:
api_config (AccredibleAPIConfig): Configuration object for the Accredible API.
"""
self.api_config = api_config

self.api_config_id = api_config_id
self.api_config = self.get_api_config()

def get_api_config(self) -> AccredibleAPIConfig:
"""
Returns the API configuration object for the Accredible API.
"""
try:
api_config = AccredibleAPIConfig.objects.get(id=self.api_config_id)
kyrylo-kh marked this conversation as resolved.
Show resolved Hide resolved
return api_config
except AccredibleAPIConfig.DoesNotExist:
raise AccredibleError(f"AccredibleAPIConfig with the id {self.api_config_id} does not exist!")

def _get_base_api_url(self) -> str:
return get_accredible_api_base_url(settings)

def _get_headers(self) -> dict:
"""
Returns the headers for making API requests to Credly.
Returns the headers for making API requests to Accredible.
"""

return {
"Accept": "application/json",
"Content-Type": "application/json",
Expand All @@ -46,12 +61,14 @@ def fetch_all_groups(self) -> dict:
"""
Fetch all groups.
"""

return self.perform_request("get", "issuer/all_groups")

def fetch_design_image(self, design_id: int) -> str:
"""
Fetches the design and return the URL of image.
"""

design_raw = self.perform_request("get", f"designs/{design_id}")
return design_raw.get("design", {}).get("rasterized_content_url")

Expand All @@ -62,6 +79,7 @@ def issue_badge(self, issue_badge_data: AccredibleBadgeData) -> dict:
Args:
issue_badge_data (IssueBadgeData): Data required to issue the badge.
"""

return self.perform_request("post", "credentials", asdict(issue_badge_data))

def revoke_badge(self, badge_id, data: AccredibleExpireBadgeData) -> dict:
Expand All @@ -72,6 +90,7 @@ def revoke_badge(self, badge_id, data: AccredibleExpireBadgeData) -> dict:
badge_id (str): ID of the badge to revoke.
data (dict): Additional data for the revocation.
"""

return self.perform_request("patch", f"credentials/{badge_id}", asdict(data))

def sync_groups(self, site_id: int) -> int:
Expand All @@ -84,6 +103,7 @@ def sync_groups(self, site_id: int) -> int:
Returns:
int | None: processed items.
"""

try:
site = Site.objects.get(id=site_id)
except Site.DoesNotExist:
Expand All @@ -93,6 +113,9 @@ def sync_groups(self, site_id: int) -> int:
groups_data = self.fetch_all_groups()
raw_groups = groups_data.get("groups", [])

all_group_ids = [group.get("id") for group in raw_groups]
AccredibleGroup.objects.exclude(id__in=all_group_ids).delete()

for raw_group in raw_groups:
kyrylo-kh marked this conversation as resolved.
Show resolved Hide resolved
AccredibleGroup.objects.update_or_create(
id=raw_group.get("id"),
Expand Down
4 changes: 4 additions & 0 deletions credentials/apps/badges/accredible/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class AccredibleRecipient:
name (str): The recipient's name.
email (str): The recipient's email address.
"""

name: str
email: str

Expand Down Expand Up @@ -40,18 +41,21 @@ class AccredibleExpiredCredential:
"""
Represents the data required to expire a credential.
"""

expired_on: datetime

@attr.s(auto_attribs=True, frozen=True)
class AccredibleBadgeData:
"""
Represents the data required to issue a badge.
"""

credential: AccredibleCredential

@attr.s(auto_attribs=True, frozen=True)
class AccredibleExpireBadgeData:
"""
Represents the data required to expire a badge.
"""

credential: AccredibleExpiredCredential
11 changes: 11 additions & 0 deletions credentials/apps/badges/accredible/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
Specific for Accredible exceptions.
"""

from credentials.apps.badges.exceptions import BadgesError


class AccredibleError(BadgesError):
"""
Accredible backend generic error.
"""
4 changes: 4 additions & 0 deletions credentials/apps/badges/accredible/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
Accredible utility functions.
"""

def get_accredible_api_base_url(settings) -> str:
NiedielnitsevIvan marked this conversation as resolved.
Show resolved Hide resolved
"""
Determines the base URL for the Accredible service based on application settings.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
import logging

from django.core.management.base import BaseCommand

from credentials.apps.badges.accredible.api_client import AccredibleAPIClient
from credentials.apps.badges.models import AccredibleAPIConfig


logger = logging.getLogger(__name__)
class Command(BaseCommand):
"""
Sync groups for a specific accredible api config or all configs.

Usage:
site_id=1
api_config_id=1

class Command(BaseCommand):
help = "Sync badge templates for a specific organization or all organizations"
./manage.py sync_accredible_groups --site_id $site_id
./manage.py sync_accredible_groups --site_id $site_id --api_config_id $api_config_id
"""
help = "Sync accredible groups for a specific api config or all api configs"

def add_arguments(self, parser):
parser.add_argument("--site_id", type=int, help="Site ID.")
parser.add_argument("--api_config_id", type=str, help="ID of the API config.")

def handle(self, *args, **options):
"""
Sync groups for a specific accredible api config or all configs.

Usage:
site_id=1
api_config_id=1

./manage.py sync_organization_badge_templates --site_id $site_id
./manage.py sync_organization_badge_templates --site_id $site_id --api_config_id $api_config_id
Handle the command.
"""
DEFAULT_SITE_ID = 1
api_configs_to_sync = []
Expand All @@ -34,24 +32,23 @@ def handle(self, *args, **options):
api_config_id = options.get("api_config_id")

if site_id is None:
logger.warning(f"Side ID wasn't provided: assuming site_id = {DEFAULT_SITE_ID}")
self.stdout.write(f"Side ID wasn't provided: assuming site_id = {DEFAULT_SITE_ID}")
site_id = DEFAULT_SITE_ID

if api_config_id:
api_configs_to_sync.append(api_config_id)
logger.info(f"Syncing groups for the single config: {api_config_id}")
self.stdout.write(f"Syncing groups for the single config: {api_config_id}")
else:
api_configs_to_sync = AccredibleAPIConfig.get_all_api_config_ids()
logger.info(
self.stdout.write(
"API Config ID wasn't provided: syncing groups for all configs - "
f"{api_configs_to_sync}",
)

for api_config_id in api_configs_to_sync:
api_config = AccredibleAPIConfig.objects.get(id=api_config_id)
accredible_api_client = AccredibleAPIClient(api_config)
for api_config in AccredibleAPIConfig.objects.filter(id__in=api_configs_to_sync):
accredible_api_client = AccredibleAPIClient(api_config.id)
processed_items = accredible_api_client.sync_groups(site_id)

logger.info(f"API Config {api_config_id}: got {processed_items} groups.")
self.stdout.write(f"API Config {api_config_id}: got {processed_items} groups.")

logger.info("...completed!")
self.stdout.write("...completed!")

This file was deleted.

Loading
Loading