Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
59 changes: 59 additions & 0 deletions libzapi/application/commands/ticketing/user_cmds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import Iterable, TypeAlias


@dataclass(frozen=True, slots=True)
class CreateUserCmd:
name: str
email: str | None = None
role: str | None = None
phone: str | None = None
alias: str | None = None
external_id: str | None = None
organization_id: int | None = None
custom_role_id: int | None = None
default_group_id: int | None = None
details: str | None = None
notes: str | None = None
locale_id: int | None = None
time_zone: str | None = None
verified: bool | None = None
active: bool | None = None
moderator: bool | None = None
only_private_comments: bool | None = None
restricted_agent: bool | None = None
suspended: bool | None = None
ticket_restriction: str | None = None
tags: Iterable[str] | None = None
user_fields: dict | None = None


@dataclass(frozen=True, slots=True)
class UpdateUserCmd:
name: str | None = None
email: str | None = None
role: str | None = None
phone: str | None = None
alias: str | None = None
external_id: str | None = None
organization_id: int | None = None
custom_role_id: int | None = None
default_group_id: int | None = None
details: str | None = None
notes: str | None = None
locale_id: int | None = None
time_zone: str | None = None
verified: bool | None = None
active: bool | None = None
moderator: bool | None = None
only_private_comments: bool | None = None
restricted_agent: bool | None = None
suspended: bool | None = None
ticket_restriction: str | None = None
tags: Iterable[str] | None = None
user_fields: dict | None = None


UserCmd: TypeAlias = CreateUserCmd | UpdateUserCmd

Check warning on line 59 in libzapi/application/commands/ticketing/user_cmds.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use a "type" statement instead of this "TypeAlias".

See more on https://sonarcloud.io/project/issues?id=BCR-CX_libzapi&issues=AZ2xrobrz-zbOMCyxXsz&open=AZ2xrobrz-zbOMCyxXsz&pullRequest=78
98 changes: 97 additions & 1 deletion libzapi/application/services/ticketing/users_service.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from __future__ import annotations

from typing import Iterable

from libzapi.domain.models.ticketing.user import User
from libzapi.application.commands.ticketing.user_cmds import CreateUserCmd, UpdateUserCmd
from libzapi.domain.models.ticketing.user import ComplianceDeletionStatus, User, UserRelated
from libzapi.domain.shared_objects.count_snapshot import CountSnapshot
from libzapi.domain.shared_objects.job_status import JobStatus
from libzapi.infrastructure.api_clients.ticketing.user_api_client import UserApiClient


Expand Down Expand Up @@ -31,3 +35,95 @@ def count_by_organization(self, organization_id: int) -> CountSnapshot:

def get_by_id(self, user_id: int) -> User:
return self._client.get(user_id)

def me(self) -> User:
return self._client.me()

def show_many(self, user_ids: Iterable[int]) -> Iterable[User]:
return self._client.show_many(user_ids=user_ids)

def search(self, query: str | None = None, external_id: str | None = None) -> Iterable[User]:
return self._client.search(query=query, external_id=external_id)

def autocomplete(self, name: str) -> Iterable[User]:
return self._client.autocomplete(name=name)

def list_related(self, user_id: int) -> UserRelated:
return self._client.list_related(user_id=user_id)

def list_compliance_deletion_statuses(
self, user_id: int
) -> Iterable[ComplianceDeletionStatus]:
return self._client.list_compliance_deletion_statuses(user_id=user_id)

def list_deleted(self) -> Iterable[User]:
return self._client.list_deleted()

def count_deleted(self) -> CountSnapshot:
return self._client.count_deleted()

def show_deleted(self, deleted_user_id: int) -> User:
return self._client.show_deleted(deleted_user_id=deleted_user_id)

def me_settings(self) -> dict:
return self._client.me_settings()

def update_me_settings(self, settings: dict) -> dict:
return self._client.update_me_settings(settings=settings)

def list_entitlements(self, user_id: int) -> list[dict]:
return self._client.list_entitlements(user_id=user_id)

def create(self, **fields) -> User:
return self._client.create(entity=CreateUserCmd(**fields))

def update(self, user_id: int, **fields) -> User:
return self._client.update(user_id=user_id, entity=UpdateUserCmd(**fields))

def delete(self, user_id: int) -> User:
return self._client.delete(user_id=user_id)

def create_many(self, users: Iterable[dict]) -> JobStatus:
return self._client.create_many(entities=[CreateUserCmd(**u) for u in users])

def create_or_update(self, **fields) -> User:
return self._client.create_or_update(entity=CreateUserCmd(**fields))

def create_or_update_many(self, users: Iterable[dict]) -> JobStatus:
return self._client.create_or_update_many(entities=[CreateUserCmd(**u) for u in users])

def update_many(self, user_ids: Iterable[int], **fields) -> JobStatus:
return self._client.update_many(user_ids=user_ids, entity=UpdateUserCmd(**fields))

def update_many_individually(
self, updates: Iterable[tuple[int, dict]]
) -> JobStatus:
pairs = [(user_id, UpdateUserCmd(**fields)) for user_id, fields in updates]
return self._client.update_many_individually(updates=pairs)

def destroy_many(self, user_ids: Iterable[int]) -> JobStatus:
return self._client.destroy_many(user_ids=user_ids)

def merge(self, source_user_id: int, target_user_id: int) -> User:
return self._client.merge(source_user_id=source_user_id, target_user_id=target_user_id)

def permanently_delete(self, deleted_user_id: int) -> User:
return self._client.permanently_delete(deleted_user_id=deleted_user_id)

def request_create(self, **fields) -> dict:
return self._client.request_create(entity=CreateUserCmd(**fields))

def logout_many(self, user_ids: Iterable[int]) -> None:
self._client.logout_many(user_ids=user_ids)

def list_tags(self, user_id: int) -> list[str]:
return self._client.list_tags(user_id=user_id)

def set_tags(self, user_id: int, tags: Iterable[str]) -> list[str]:
return self._client.set_tags(user_id=user_id, tags=tags)

def add_tags(self, user_id: int, tags: Iterable[str]) -> list[str]:
return self._client.add_tags(user_id=user_id, tags=tags)

def remove_tags(self, user_id: int, tags: Iterable[str]) -> list[str]:
return self._client.remove_tags(user_id=user_id, tags=tags)
44 changes: 33 additions & 11 deletions libzapi/domain/models/ticketing/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,43 +13,65 @@ class User:
id: int
url: str
name: str
email: str
email: Optional[str]
created_at: datetime
updated_at: datetime
time_zone: str
iana_time_zone: str
phone: str
shared_phone_number: bool
phone: Optional[str]
shared_phone_number: Optional[bool]
photo: Optional[Thumbnail]
locale_id: int
locale: str
organization_id: Optional[OrganizationIdType]
role: str
verified: bool
external_id: str
external_id: Optional[str]
tags: List[str]
alias: str
alias: Optional[str]
active: bool
shared: bool
shared_agent: bool
last_login_at: datetime
last_login_at: Optional[datetime]
two_factor_auth_enabled: bool
signature: str
details: str
notes: str
signature: Optional[str]
details: Optional[str]
notes: Optional[str]
role_type: Optional[int]
custom_role_id: Optional[int]
is_billing_admin: bool
moderator: bool
ticket_restriction: str
ticket_restriction: Optional[str]
only_private_comments: bool
restricted_agent: bool
suspended: bool
default_group_id: Optional[int]
report_csv: bool
user_fields: dict
user_fields: Optional[dict] = None

@property
def logical_key(self) -> LogicalKey:
base = f"id_{self.id}"
return LogicalKey("user", base)


@dataclass(frozen=True, slots=True)
class UserRelated:
assigned_tickets: int = 0
requested_tickets: int = 0
ccd_tickets: int = 0
organization_subscriptions: int = 0
topic_comments: int = 0
topics: int = 0
votes: int = 0
subscriptions: int = 0


@dataclass(frozen=True, slots=True)
class ComplianceDeletionStatus:
account_subdomain: Optional[str] = None
action: Optional[str] = None
application: Optional[str] = None
created_at: Optional[datetime] = None
executer_id: Optional[int] = None
user_id: Optional[int] = None
Loading
Loading