-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into dev-new-delivery-service
- Loading branch information
Showing
18 changed files
with
476 additions
and
379 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
__title__ = "cg" | ||
__version__ = "62.2.4" | ||
__version__ = "62.2.5" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,61 @@ | ||
from datetime import datetime | ||
from typing import Tuple, Union | ||
|
||
from pydantic import BaseModel | ||
from pydantic import BaseModel, EmailStr, Field | ||
|
||
from cg.clients.freshdesk.constants import Priority, Source, Status | ||
|
||
|
||
class TicketCreate(BaseModel): | ||
"""Freshdesk ticket.""" | ||
|
||
attachments: list[dict[str, str]] = [] | ||
email: str | ||
attachments: list[str | bytes] = Field(default_factory=list) | ||
email: EmailStr | ||
email_config_id: int | None = None | ||
description: str | ||
name: str | ||
priority: int = Priority.LOW | ||
source: int = Source.EMAIL | ||
status: int = Status.OPEN | ||
subject: str | ||
tags: list[str] = [] | ||
type: str | None = None | ||
custom_fields: dict[str, str | int | float | None] = Field(default_factory=dict) | ||
|
||
def to_multipart_data(self) -> list[Tuple[str, str | int | bytes]]: | ||
"""Custom converter to multipart form data.""" | ||
multipart_data = [] | ||
|
||
for field, value in self.model_dump(exclude_none=True).items(): | ||
if isinstance(value, list): | ||
multipart_data.extend([(f"{field}[]", v) for v in value]) | ||
elif isinstance(value, dict): | ||
multipart_data.extend([(f"{field}[{k}]", v) for k, v in value.items()]) | ||
else: | ||
multipart_data.append((field, value)) | ||
|
||
return multipart_data | ||
|
||
|
||
class TicketResponse(BaseModel): | ||
"""Freshdesk ticket response.""" | ||
"""Response from Freshdesk""" | ||
|
||
attachments: list[dict[str, str]] = [] | ||
created_at: datetime | None = None | ||
email: str | ||
id: int | ||
name: str | None = None | ||
priority: int | ||
source: int | ||
status: int | ||
description: str | ||
subject: str | ||
tags: list[str] = [] | ||
type: str | None = None | ||
to_emails: list[str] | None = None | ||
status: int | ||
priority: int | ||
|
||
|
||
class ReplyCreate(BaseModel): | ||
"""Reply to a ticket.""" | ||
|
||
ticket_number: str | ||
body: str | ||
|
||
def to_multipart_data(self) -> list[Tuple[str, Union[str, int, bytes]]]: | ||
"""Custom converter to multipart form data.""" | ||
multipart_data = [ | ||
("body", self.body), | ||
] | ||
return multipart_data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import logging | ||
from functools import wraps | ||
from pathlib import Path | ||
from tempfile import TemporaryDirectory | ||
|
||
from pydantic import ValidationError | ||
from requests import ConnectionError, HTTPError | ||
from requests.exceptions import MissingSchema | ||
|
||
from cg.clients.freshdesk.exceptions import ( | ||
FreshdeskAPIException, | ||
FreshdeskModelException, | ||
) | ||
from cg.constants.constants import FileFormat | ||
from cg.io.controller import WriteFile | ||
|
||
LOG = logging.getLogger(__name__) | ||
|
||
|
||
def extract_error_detail(error): | ||
"""Extract detailed error information from HTTPError.""" | ||
if error.response is not None: | ||
try: | ||
return error.response.json() | ||
except ValueError: | ||
return error.response.text | ||
return None | ||
|
||
|
||
def log_and_raise(exception_class, message, error): | ||
"""Log the error and raise the appropriate exception.""" | ||
LOG.error(message) | ||
raise exception_class(error) from error | ||
|
||
|
||
def handle_client_errors(func): | ||
"""Decorator to handle and log errors in Freshdesk client methods.""" | ||
|
||
@wraps(func) | ||
def wrapper(*args, **kwargs): | ||
try: | ||
return func(*args, **kwargs) | ||
except HTTPError as error: | ||
error_detail = extract_error_detail(error) | ||
log_and_raise( | ||
FreshdeskAPIException, | ||
f"Failed request to Freshdesk: {error} - Status code: " | ||
f"{error.response.status_code if error.response else 'N/A'}, Details: {error_detail}", | ||
error, | ||
) | ||
except (MissingSchema, ConnectionError) as error: | ||
log_and_raise(FreshdeskAPIException, f"Request to Freshdesk failed: {error}", error) | ||
except ValidationError as error: | ||
log_and_raise( | ||
FreshdeskModelException, f"Invalid response from Freshdesk: {error}", error | ||
) | ||
except ValueError as error: | ||
log_and_raise(FreshdeskAPIException, f"Operation failed: {error}", error) | ||
except Exception as error: | ||
log_and_raise( | ||
FreshdeskAPIException, f"Unexpected error in Freshdesk client: {error}", error | ||
) | ||
|
||
return wrapper | ||
|
||
|
||
def prepare_attachments(attachments: list[Path]) -> list[tuple[str, tuple[str, bytes]]]: | ||
"""Prepare the attachments for a request.""" | ||
return [ | ||
("attachments[]", (attachment.name, open(attachment, "rb"))) for attachment in attachments | ||
] | ||
|
||
|
||
def create_temp_attachment_file(content: dict, file_name: Path) -> TemporaryDirectory: | ||
"""Create a file-based attachment.""" | ||
if content and file_name: | ||
directory = TemporaryDirectory() | ||
WriteFile.write_file_from_content( | ||
content=content, | ||
file_format=FileFormat.JSON, | ||
file_path=Path(directory.name, "order.json"), | ||
) | ||
return directory | ||
else: | ||
LOG.error("Content or file path is None. Cannot create file attachment.") | ||
raise ValueError("Both content and file path must be provided and cannot be None") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.