notify-api-412 use black to enforce python coding style

This commit is contained in:
Kenneth Kehl
2023-08-25 09:12:23 -07:00
parent c6eb007386
commit 8c9721d8e2
201 changed files with 31660 additions and 28105 deletions

View File

@@ -8,7 +8,6 @@ from notifications_utils.serialised_model import (
class JSONModel(SerialisedModel):
def __init__(self, _dict):
# in the case of a bad request _dict may be `None`
self._dict = _dict or {}
@@ -27,13 +26,12 @@ class JSONModel(SerialisedModel):
def _get_by_id(self, things, id):
try:
return next(thing for thing in things if thing['id'] == str(id))
return next(thing for thing in things if thing["id"] == str(id))
except StopIteration:
abort(404)
class ModelList(SerialisedModelCollection):
@property
@abstractmethod
def client_method(self):
@@ -44,8 +42,7 @@ class ModelList(SerialisedModelCollection):
class PaginatedModelList(ModelList):
response_key = 'data'
response_key = "data"
def __init__(self, *args, page=None, **kwargs):
try:
@@ -58,11 +55,10 @@ class PaginatedModelList(ModelList):
page=self.current_page,
)
self.items = response[self.response_key]
self.prev_page = response.get('links', {}).get('prev', None)
self.next_page = response.get('links', {}).get('next', None)
self.prev_page = response.get("links", {}).get("prev", None)
self.next_page = response.get("links", {}).get("next", None)
class SortByNameMixin():
class SortByNameMixin:
def __lt__(self, other):
return self.name.lower() < other.name.lower()

View File

@@ -8,7 +8,6 @@ from app.notify_client.service_api_client import service_api_client
class Event(ABC):
def __init__(
self,
item,
@@ -17,8 +16,8 @@ class Event(ABC):
value_to=None,
):
self.item = item
self.time = item['updated_at'] or item['created_at']
self.user_id = item['created_by_id']
self.time = item["updated_at"] or item["created_at"]
self.user_id = item["created_by_id"]
self.key = key
self.value_from = value_from
self.value_to = value_to
@@ -34,17 +33,13 @@ class Event(ABC):
class ServiceCreationEvent(Event):
relevant = True
def __str__(self):
return 'Created this service and called it {}'.format(
self.item['name']
)
return "Created this service and called it {}".format(self.item["name"])
class ServiceEvent(Event):
@property
def relevant(self):
return self.value_from != self.value_to and bool(self._formatter)
@@ -54,44 +49,38 @@ class ServiceEvent(Event):
@property
def _formatter(self):
return getattr(self, 'format_{}'.format(self.key), None)
return getattr(self, "format_{}".format(self.key), None)
def format_restricted(self):
if self.value_to is False:
return 'Made this service live'
return "Made this service live"
if self.value_to is True:
return 'Put this service back into trial mode'
return "Put this service back into trial mode"
def format_active(self):
if self.value_to is False:
return 'Deleted this service'
return "Deleted this service"
if self.value_to is True:
return 'Unsuspended this service'
return "Unsuspended this service"
def format_contact_link(self):
return 'Set the contact details for this service to {}'.format(
self.value_to
)
return "Set the contact details for this service to {}".format(self.value_to)
def format_email_branding(self):
return 'Updated this services email branding'
return "Updated this services email branding"
def format_inbound_api(self):
return 'Updated the callback for received text messages'
return "Updated the callback for received text messages"
def format_message_limit(self):
return (
'{} this services daily message limit from {} to {}'
).format(
'Reduced' if self.value_from > self.value_to else 'Increased',
return ("{} this services daily message limit from {} to {}").format(
"Reduced" if self.value_from > self.value_to else "Increased",
format_thousands(self.value_from),
format_thousands(self.value_to),
)
def format_name(self):
return (
'Renamed this service from {} to {}'
).format(
return ("Renamed this service from {} to {}").format(
self.value_from, self.value_to
)
@@ -99,61 +88,54 @@ class ServiceEvent(Event):
added = list(sorted(set(self.value_to) - set(self.value_from)))
removed = list(sorted(set(self.value_from) - set(self.value_to)))
if removed and added:
return 'Removed {} from this services permissions, added {}'.format(
return "Removed {} from this services permissions, added {}".format(
formatted_list(removed),
formatted_list(added),
)
if added:
return 'Added {} to this services permissions'.format(
return "Added {} to this services permissions".format(
formatted_list(added)
)
if removed:
return 'Removed {} from this services permissions'.format(
return "Removed {} from this services permissions".format(
formatted_list(removed)
)
def format_prefix_sms(self):
if self.value_to is True:
return 'Set text messages to start with the name of this service'
return "Set text messages to start with the name of this service"
else:
return 'Set text messages to not start with the name of this service'
return "Set text messages to not start with the name of this service"
def format_research_mode(self):
if self.value_to is True:
return 'Put this service into research mode'
return "Put this service into research mode"
else:
return 'Took this service out of research mode'
return "Took this service out of research mode"
def format_service_callback_api(self):
return 'Updated the callback for delivery receipts'
return "Updated the callback for delivery receipts"
def format_go_live_user(self):
return 'Requested for this service to go live'
return "Requested for this service to go live"
class APIKeyEvent(Event):
relevant = True
def __str__(self):
if self.item['updated_at']:
return (
'Revoked the {} API key'
).format(self.item['name'])
if self.item["updated_at"]:
return ("Revoked the {} API key").format(self.item["name"])
else:
return (
'Created an API key called {}'
).format(self.item['name'])
return ("Created an API key called {}").format(self.item["name"])
class APIKeyEvents(ModelList):
model = APIKeyEvent
client_method = service_api_client.get_service_api_key_history
class ServiceEvents(ModelList):
client_method = service_api_client.get_service_service_history
@property
@@ -162,10 +144,9 @@ class ServiceEvents(ModelList):
@staticmethod
def splat(events):
for index, item in enumerate(sorted(
events,
key=lambda event: event['updated_at'] or event['created_at']
)):
for index, item in enumerate(
sorted(events, key=lambda event: event["updated_at"] or event["created_at"])
):
if index == 0:
yield ServiceCreationEvent(item)
else:
@@ -179,5 +160,7 @@ class ServiceEvents(ModelList):
def __init__(self, service_id):
self.items = [
event for event in self.splat(self.client_method(service_id)) if event.relevant
event
for event in self.splat(self.client_method(service_id))
if event.relevant
]

View File

@@ -1,3 +1,3 @@
QUESTION_TICKET_TYPE = 'ask-question-give-feedback'
PROBLEM_TICKET_TYPE = 'report-problem'
GENERAL_TICKET_TYPE = 'general'
QUESTION_TICKET_TYPE = "ask-question-give-feedback"
PROBLEM_TICKET_TYPE = "report-problem"
GENERAL_TICKET_TYPE = "general"

View File

@@ -9,65 +9,68 @@ from app.utils.time import is_less_than_days_ago
class Job(JSONModel):
ALLOWED_PROPERTIES = {
'id',
'service',
'template_name',
'template_version',
'original_file_name',
'created_at',
'notification_count',
'created_by',
'template_type',
'recipient',
"id",
"service",
"template_name",
"template_version",
"original_file_name",
"created_at",
"notification_count",
"created_by",
"template_type",
"recipient",
}
@classmethod
def from_id(cls, job_id, service_id):
return cls(job_api_client.get_job(service_id, job_id)['data'])
return cls(job_api_client.get_job(service_id, job_id)["data"])
@property
def status(self):
return self._dict.get('job_status')
return self._dict.get("job_status")
@property
def cancelled(self):
return self.status == 'cancelled'
return self.status == "cancelled"
@property
def scheduled(self):
return self.status == 'scheduled'
return self.status == "scheduled"
@property
def scheduled_for(self):
return self._dict.get('scheduled_for')
return self._dict.get("scheduled_for")
@property
def upload_type(self):
return self._dict.get('upload_type')
return self._dict.get("upload_type")
@property
def processing_started(self):
if not self._dict.get('processing_started'):
if not self._dict.get("processing_started"):
return None
return self._dict['processing_started']
return self._dict["processing_started"]
def _aggregate_statistics(self, *statuses):
return sum(
outcome['count'] for outcome in self._dict['statistics']
if not statuses or outcome['status'] in statuses
outcome["count"]
for outcome in self._dict["statistics"]
if not statuses or outcome["status"] in statuses
)
@property
def notifications_delivered(self):
return self._aggregate_statistics('delivered', 'sent')
return self._aggregate_statistics("delivered", "sent")
@property
def notifications_failed(self):
return self._aggregate_statistics(
'failed', 'technical-failure', 'temporary-failure',
'permanent-failure', 'cancelled',
"failed",
"technical-failure",
"temporary-failure",
"permanent-failure",
"cancelled",
)
@property
@@ -92,9 +95,7 @@ class Job(JSONModel):
@property
def still_processing(self):
return (
self.status != 'finished' or self.percentage_complete < 100
)
return self.status != "finished" or self.percentage_complete < 100
@cached_property
def finished_processing(self):
@@ -111,7 +112,7 @@ class Job(JSONModel):
@property
def template_id(self):
return self._dict['template']
return self._dict["template"]
@cached_property
def template(self):
@@ -119,7 +120,7 @@ class Job(JSONModel):
service_id=self.service,
template_id=self.template_id,
version=self.template_version,
)['data']
)["data"]
@property
def percentage_complete(self):
@@ -127,23 +128,21 @@ class Job(JSONModel):
@cached_property
def all_notifications(self):
return self.get_notifications(set_status_filters({}))['notifications']
return self.get_notifications(set_status_filters({}))["notifications"]
@property
def uncancellable_notifications(self):
# TODO: this is redundant now
return (
n for n in self.all_notifications
)
return (n for n in self.all_notifications)
@property
def failure_rate(self):
if not self.notifications_delivered:
return 100 if self.notifications_failed else 0
return (
self.notifications_failed / (
self.notifications_failed + self.notifications_delivered
) * 100
self.notifications_failed
/ (self.notifications_failed + self.notifications_delivered)
* 100
)
@property
@@ -152,7 +151,9 @@ class Job(JSONModel):
def get_notifications(self, status):
return notification_api_client.get_notifications_for_service(
self.service, self.id, status=status,
self.service,
self.id,
status=status,
)
def cancel(self):

View File

@@ -8,31 +8,32 @@ from app.notify_client.organizations_api_client import organizations_client
class Organization(JSONModel, SortByNameMixin):
TYPE_FEDERAL = "federal"
TYPE_STATE = "state"
TYPE_OTHER = "other"
TYPE_FEDERAL = 'federal'
TYPE_STATE = 'state'
TYPE_OTHER = 'other'
TYPE_LABELS = OrderedDict([
(TYPE_FEDERAL, 'Federal government'),
(TYPE_STATE, 'State government'),
(TYPE_OTHER, 'Other'),
])
TYPE_LABELS = OrderedDict(
[
(TYPE_FEDERAL, "Federal government"),
(TYPE_STATE, "State government"),
(TYPE_OTHER, "Other"),
]
)
ALLOWED_PROPERTIES = {
'id',
'name',
'active',
'organization_type',
'email_branding_id',
'domains',
'request_to_go_live_notes',
'count_of_live_services',
'billing_contact_email_addresses',
'billing_contact_names',
'billing_reference',
'purchase_order_number',
'notes',
"id",
"name",
"active",
"organization_type",
"email_branding_id",
"domains",
"request_to_go_live_notes",
"count_of_live_services",
"billing_contact_email_addresses",
"billing_contact_names",
"billing_reference",
"purchase_order_number",
"notes",
}
@classmethod
@@ -58,13 +59,14 @@ class Organization(JSONModel, SortByNameMixin):
@classmethod
def create(cls, name, organization_type):
return cls(organizations_client.create_organization(
name=name,
organization_type=organization_type,
))
return cls(
organizations_client.create_organization(
name=name,
organization_type=organization_type,
)
)
def __init__(self, _dict):
super().__init__(_dict)
if self._dict == {}:
@@ -84,7 +86,7 @@ class Organization(JSONModel, SortByNameMixin):
self.billing_contact_email_addresses,
self.billing_contact_names,
self.billing_reference,
self.purchase_order_number
self.purchase_order_number,
]
if any(billing_details):
return billing_details
@@ -97,24 +99,26 @@ class Organization(JSONModel, SortByNameMixin):
@cached_property
def service_ids(self):
return [s['id'] for s in self.services]
return [s["id"] for s in self.services]
@property
def live_services(self):
return [s for s in self.services if s['active'] and not s['restricted']]
return [s for s in self.services if s["active"] and not s["restricted"]]
@property
def trial_services(self):
return [s for s in self.services if not s['active'] or s['restricted']]
return [s for s in self.services if not s["active"] or s["restricted"]]
@cached_property
def invited_users(self):
from app.models.user import OrganizationInvitedUsers
return OrganizationInvitedUsers(self.id)
@cached_property
def active_users(self):
from app.models.user import OrganizationUsers
return OrganizationUsers(self.id)
@cached_property
@@ -127,15 +131,15 @@ class Organization(JSONModel, SortByNameMixin):
@cached_property
def email_branding(self):
if self.email_branding_id:
return email_branding_client.get_email_branding(
self.email_branding_id
)['email_branding']
return email_branding_client.get_email_branding(self.email_branding_id)[
"email_branding"
]
@property
def email_branding_name(self):
if self.email_branding_id:
return self.email_branding['name']
return 'GOV.UK'
return self.email_branding["name"]
return "GOV.UK"
def update(self, delete_services_cache=False, **kwargs):
response = organizations_client.update_organization(
@@ -146,10 +150,7 @@ class Organization(JSONModel, SortByNameMixin):
self.__init__(response)
def associate_service(self, service_id):
organizations_client.update_service_organization(
service_id,
self.id
)
organizations_client.update_service_organization(service_id, self.id)
def services_and_usage(self, financial_year):
return organizations_client.get_services_and_usage(self.id, financial_year)

View File

@@ -19,52 +19,51 @@ from app.utils import get_default_sms_sender
class Service(JSONModel, SortByNameMixin):
ALLOWED_PROPERTIES = {
'active',
'billing_contact_email_addresses',
'billing_contact_names',
'billing_reference',
'consent_to_research',
'contact_link',
'count_as_live',
'email_from',
'go_live_at',
'go_live_user',
'id',
'inbound_api',
'message_limit',
'rate_limit',
'name',
'notes',
'prefix_sms',
'purchase_order_number',
'research_mode',
'service_callback_api',
'volume_email',
'volume_sms',
"active",
"billing_contact_email_addresses",
"billing_contact_names",
"billing_reference",
"consent_to_research",
"contact_link",
"count_as_live",
"email_from",
"go_live_at",
"go_live_user",
"id",
"inbound_api",
"message_limit",
"rate_limit",
"name",
"notes",
"prefix_sms",
"purchase_order_number",
"research_mode",
"service_callback_api",
"volume_email",
"volume_sms",
}
TEMPLATE_TYPES = (
'email',
'sms',
"email",
"sms",
)
ALL_PERMISSIONS = TEMPLATE_TYPES + (
'edit_folder_permissions',
'email_auth',
'inbound_sms',
'international_sms',
'upload_document',
"edit_folder_permissions",
"email_auth",
"inbound_sms",
"international_sms",
"upload_document",
)
@classmethod
def from_id(cls, service_id):
return cls(service_api_client.get_service(service_id)['data'])
return cls(service_api_client.get_service(service_id)["data"])
@property
def permissions(self):
return self._dict.get('permissions', self.TEMPLATE_TYPES)
return self._dict.get("permissions", self.TEMPLATE_TYPES)
@property
def billing_details(self):
@@ -72,7 +71,7 @@ class Service(JSONModel, SortByNameMixin):
self.billing_contact_email_addresses,
self.billing_contact_names,
self.billing_reference,
self.purchase_order_number
self.purchase_order_number,
]
if any(billing_details):
return billing_details
@@ -83,7 +82,9 @@ class Service(JSONModel, SortByNameMixin):
return service_api_client.update_service(self.id, **kwargs)
def update_count_as_live(self, count_as_live):
return service_api_client.update_count_as_live(self.id, count_as_live=count_as_live)
return service_api_client.update_count_as_live(
self.id, count_as_live=count_as_live
)
def update_status(self, live):
return service_api_client.update_status(self.id, live=live)
@@ -95,7 +96,6 @@ class Service(JSONModel, SortByNameMixin):
)
def force_permission(self, permission, on=False):
permissions, permission = set(self.permissions), {permission}
return self.update_permissions(
@@ -110,7 +110,7 @@ class Service(JSONModel, SortByNameMixin):
@property
def trial_mode(self):
return self._dict['restricted']
return self._dict["restricted"]
@property
def live(self):
@@ -118,7 +118,7 @@ class Service(JSONModel, SortByNameMixin):
def has_permission(self, permission):
if permission not in self.ALL_PERMISSIONS:
raise KeyError(f'{permission} is not a service permission')
raise KeyError(f"{permission} is not a service permission")
return permission in self.permissions
def get_page_of_jobs(self, page):
@@ -146,7 +146,7 @@ class Service(JSONModel, SortByNameMixin):
@cached_property
def scheduled_job_stats(self):
if not self.has_jobs:
return {'count': 0}
return {"count": 0}
return job_api_client.get_scheduled_job_stats(self.id)
@cached_property
@@ -155,8 +155,7 @@ class Service(JSONModel, SortByNameMixin):
def invite_pending_for(self, email_address):
return email_address.lower() in (
invited_user.email_address.lower()
for invited_user in self.invited_users
invited_user.email_address.lower() for invited_user in self.invited_users
)
@cached_property
@@ -172,10 +171,16 @@ class Service(JSONModel, SortByNameMixin):
@cached_property
def has_team_members(self):
return len([
user for user in self.team_members
if user.has_permission_for_service(self.id, 'manage_service')
]) > 1
return (
len(
[
user
for user in self.team_members
if user.has_permission_for_service(self.id, "manage_service")
]
)
> 1
)
def cancel_invite(self, invited_user_id):
if str(invited_user_id) not in {user.id for user in self.invited_users}:
@@ -187,7 +192,6 @@ class Service(JSONModel, SortByNameMixin):
)
def get_team_member(self, user_id):
if str(user_id) not in {user.id for user in self.active_users}:
abort(404)
@@ -195,20 +199,22 @@ class Service(JSONModel, SortByNameMixin):
@cached_property
def all_templates(self):
templates = service_api_client.get_service_templates(self.id)['data']
templates = service_api_client.get_service_templates(self.id)["data"]
return [
template for template in templates
if template['template_type'] in self.available_template_types
template
for template in templates
if template["template_type"] in self.available_template_types
]
@cached_property
def all_template_ids(self):
return {template['id'] for template in self.all_templates}
return {template["id"] for template in self.all_templates}
def get_template(self, template_id, version=None):
return service_api_client.get_service_template(self.id, template_id, version)['data']
return service_api_client.get_service_template(self.id, template_id, version)[
"data"
]
def get_template_folder_with_user_permission_or_403(self, folder_id, user):
template_folder = self.get_template_folder(folder_id)
@@ -221,7 +227,7 @@ class Service(JSONModel, SortByNameMixin):
def get_template_with_user_permission_or_403(self, template_id, user):
template = self.get_template(template_id)
self.get_template_folder_with_user_permission_or_403(template['folder'], user)
self.get_template_folder_with_user_permission_or_403(template["folder"], user)
return template
@@ -238,32 +244,31 @@ class Service(JSONModel, SortByNameMixin):
@property
def has_multiple_template_types(self):
return len({
template['template_type'] for template in self.all_templates
}) > 1
return len({template["template_type"] for template in self.all_templates}) > 1
@property
def has_estimated_usage(self):
return (
self.consent_to_research is not None and any((
return self.consent_to_research is not None and any(
(
self.volume_email,
self.volume_sms,
))
)
)
def has_templates_of_type(self, template_type):
return any(
template for template in self.all_templates
if template['template_type'] == template_type
template
for template in self.all_templates
if template["template_type"] == template_type
)
@property
def has_email_templates(self):
return self.has_templates_of_type('email')
return self.has_templates_of_type("email")
@property
def has_sms_templates(self):
return self.has_templates_of_type('sms')
return self.has_templates_of_type("sms")
@property
def intending_to_send_email(self):
@@ -293,9 +298,11 @@ class Service(JSONModel, SortByNameMixin):
def default_email_reply_to_address(self):
return next(
(
x['email_address']
for x in self.email_reply_to_addresses if x['is_default']
), None
x["email_address"]
for x in self.email_reply_to_addresses
if x["is_default"]
),
None,
)
def get_email_reply_to_address(self, id):
@@ -315,15 +322,14 @@ class Service(JSONModel, SortByNameMixin):
@property
def sms_senders_with_hints(self):
def attach_hint(sender):
hints = []
if sender['is_default']:
if sender["is_default"]:
hints += ["default"]
if sender['inbound_number_id']:
if sender["inbound_number_id"]:
hints += ["receives replies"]
if hints:
sender['hint'] = "(" + " and ".join(hints) + ")"
sender["hint"] = "(" + " and ".join(hints) + ")"
return sender
return [attach_hint(sender) for sender in self.sms_senders]
@@ -338,39 +344,48 @@ class Service(JSONModel, SortByNameMixin):
@property
def sms_sender_is_govuk(self):
return self.default_sms_sender in {'GOVUK', 'None'}
return self.default_sms_sender in {"GOVUK", "None"}
def get_sms_sender(self, id):
return service_api_client.get_sms_sender(self.id, id)
@property
def needs_to_change_sms_sender(self):
return all((
self.intending_to_send_sms,
self.shouldnt_use_govuk_as_sms_sender,
self.sms_sender_is_govuk,
))
return all(
(
self.intending_to_send_sms,
self.shouldnt_use_govuk_as_sms_sender,
self.sms_sender_is_govuk,
)
)
@property
def volumes(self):
return sum(filter(None, (
self.volume_email,
self.volume_sms,
)))
return sum(
filter(
None,
(
self.volume_email,
self.volume_sms,
),
)
)
@property
def go_live_checklist_completed(self):
return all((
bool(self.volumes),
self.has_team_members,
self.has_templates,
not self.needs_to_add_email_reply_to_address,
not self.needs_to_change_sms_sender,
))
return all(
(
bool(self.volumes),
self.has_team_members,
self.has_templates,
not self.needs_to_add_email_reply_to_address,
not self.needs_to_change_sms_sender,
)
)
@property
def go_live_checklist_completed_as_yes_no(self):
return 'Yes' if self.go_live_checklist_completed else 'No'
return "Yes" if self.go_live_checklist_completed else "No"
@cached_property
def free_sms_fragment_limit(self):
@@ -381,36 +396,42 @@ class Service(JSONModel, SortByNameMixin):
return service_api_client.get_service_data_retention(self.id)
def get_data_retention_item(self, id):
return next(
(dr for dr in self.data_retention if dr['id'] == id),
None
)
return next((dr for dr in self.data_retention if dr["id"] == id), None)
def get_days_of_retention(self, notification_type):
return next(
(dr for dr in self.data_retention if dr['notification_type'] == notification_type),
{}
).get('days_of_retention', current_app.config['ACTIVITY_STATS_LIMIT_DAYS'])
(
dr
for dr in self.data_retention
if dr["notification_type"] == notification_type
),
{},
).get("days_of_retention", current_app.config["ACTIVITY_STATS_LIMIT_DAYS"])
@property
def email_branding_id(self):
return self._dict['email_branding']
return self._dict["email_branding"]
@cached_property
def email_branding(self):
if self.email_branding_id:
return email_branding_client.get_email_branding(self.email_branding_id)['email_branding']
return email_branding_client.get_email_branding(self.email_branding_id)[
"email_branding"
]
return None
@cached_property
def email_branding_name(self):
if self.email_branding is None:
return 'GOV.UK'
return self.email_branding['name']
return "GOV.UK"
return self.email_branding["name"]
@property
def needs_to_change_email_branding(self):
return self.email_branding_id is None and self.organization_type != Organization.TYPE_CENTRAL
return (
self.email_branding_id is None
and self.organization_type != Organization.TYPE_CENTRAL
)
@cached_property
def organization(self):
@@ -418,11 +439,11 @@ class Service(JSONModel, SortByNameMixin):
@property
def organization_id(self):
return self._dict['organization']
return self._dict["organization"]
@property
def organization_type(self):
return self.organization.organization_type or self._dict['organization_type']
return self.organization.organization_type or self._dict["organization_type"]
@property
def organization_name(self):
@@ -436,7 +457,9 @@ class Service(JSONModel, SortByNameMixin):
@cached_property
def inbound_number(self):
return inbound_number_client.get_inbound_sms_number_for_service(self.id)['data'].get('number', '')
return inbound_number_client.get_inbound_sms_number_for_service(self.id)[
"data"
].get("number", "")
@property
def has_inbound_number(self):
@@ -444,7 +467,7 @@ class Service(JSONModel, SortByNameMixin):
@cached_property
def inbound_sms_summary(self):
if not self.has_permission('inbound_sms'):
if not self.has_permission("inbound_sms"):
return None
return service_api_client.get_inbound_sms_summary(self.id)
@@ -452,35 +475,34 @@ class Service(JSONModel, SortByNameMixin):
def all_template_folders(self):
return sorted(
template_folder_api_client.get_template_folders(self.id),
key=lambda folder: folder['name'].lower(),
key=lambda folder: folder["name"].lower(),
)
@cached_property
def all_template_folder_ids(self):
return {folder['id'] for folder in self.all_template_folders}
return {folder["id"] for folder in self.all_template_folders}
def get_template_folder(self, folder_id):
if folder_id is None:
return {
'id': None,
'name': 'Templates',
'parent_id': None,
"id": None,
"name": "Templates",
"parent_id": None,
}
return self._get_by_id(self.all_template_folders, folder_id)
def get_template_folder_path(self, template_folder_id):
folder = self.get_template_folder(template_folder_id)
if folder['id'] is None:
if folder["id"] is None:
return [folder]
return self.get_template_folder_path(folder['parent_id']) + [
self.get_template_folder(folder['id'])
return self.get_template_folder_path(folder["parent_id"]) + [
self.get_template_folder(folder["id"])
]
def get_template_path(self, template):
return self.get_template_folder_path(template['folder']) + [
return self.get_template_folder_path(template["folder"]) + [
template,
]
@@ -489,7 +511,6 @@ class Service(JSONModel, SortByNameMixin):
return len(self.all_templates + self.all_template_folders)
def move_to_folder(self, ids_to_move, move_to):
ids_to_move = set(ids_to_move)
template_folder_api_client.move_to_folder(
@@ -502,8 +523,8 @@ class Service(JSONModel, SortByNameMixin):
@cached_property
def api_keys(self):
return sorted(
api_key_api_client.get_api_keys(self.id)['apiKeys'],
key=lambda key: key['name'].lower(),
api_key_api_client.get_api_keys(self.id)["apiKeys"],
key=lambda key: key["name"].lower(),
)
def get_api_key(self, id):

View File

@@ -6,26 +6,21 @@ import pyexcel
import pyexcel_xlsx
class Spreadsheet():
ALLOWED_FILE_EXTENSIONS = ('csv', 'xlsx', 'xls', 'ods', 'xlsm', 'tsv')
def __init__(self, csv_data=None, rows=None, filename=''):
class Spreadsheet:
ALLOWED_FILE_EXTENSIONS = ("csv", "xlsx", "xls", "ods", "xlsm", "tsv")
def __init__(self, csv_data=None, rows=None, filename=""):
self.filename = filename
if csv_data and rows:
raise TypeError('Spreadsheet must be created from either rows or CSV data')
raise TypeError("Spreadsheet must be created from either rows or CSV data")
self._csv_data = csv_data or ''
self._csv_data = csv_data or ""
self._rows = rows or []
@property
def as_dict(self):
return {
'file_name': self.filename,
'data': self.as_csv_data
}
return {"file_name": self.filename, "data": self.as_csv_data}
@property
def as_csv_data(self):
@@ -43,37 +38,36 @@ class Spreadsheet():
@staticmethod
def get_extension(filename):
return path.splitext(filename)[1].lower().lstrip('.')
return path.splitext(filename)[1].lower().lstrip(".")
@staticmethod
def normalise_newlines(file_content):
return '\r\n'.join(file_content.read().decode('utf-8').splitlines())
return "\r\n".join(file_content.read().decode("utf-8").splitlines())
@classmethod
def from_rows(cls, rows, filename=''):
def from_rows(cls, rows, filename=""):
return cls(rows=rows, filename=filename)
@classmethod
def from_dict(cls, dictionary, filename=''):
def from_dict(cls, dictionary, filename=""):
return cls.from_rows(
zip(
*sorted(dictionary.items(), key=lambda pair: pair[0])
),
zip(*sorted(dictionary.items(), key=lambda pair: pair[0])),
filename=filename,
)
@classmethod
def from_file(cls, file_content, filename=''):
def from_file(cls, file_content, filename=""):
extension = cls.get_extension(filename)
if extension == 'csv':
return cls(csv_data=Spreadsheet.normalise_newlines(file_content), filename=filename)
if extension == "csv":
return cls(
csv_data=Spreadsheet.normalise_newlines(file_content), filename=filename
)
if extension == 'tsv':
file_content = StringIO(
Spreadsheet.normalise_newlines(file_content))
if extension == "tsv":
file_content = StringIO(Spreadsheet.normalise_newlines(file_content))
if extension == 'xlsm':
if extension == "xlsm":
file_data = pyexcel_xlsx.get_data(file_content)
instance = cls.from_rows(
# Get the first sheet from the workbook
@@ -83,10 +77,8 @@ class Spreadsheet():
return instance
instance = cls.from_rows(
pyexcel.iget_array(
file_type=extension,
file_stream=file_content),
filename)
pyexcel.iget_array(file_type=extension, file_stream=file_content), filename
)
pyexcel.free_resources()
return instance

View File

@@ -3,12 +3,11 @@ from werkzeug.utils import cached_property
from app import format_notification_type
class TemplateList():
class TemplateList:
def __init__(
self,
service,
template_type='all',
template_type="all",
template_folder_id=None,
user=None,
):
@@ -22,33 +21,35 @@ class TemplateList():
@cached_property
def items(self):
return list(self.get_templates_and_folders(
self.template_type, self.template_folder_id, ancestors=[]
))
return list(
self.get_templates_and_folders(
self.template_type, self.template_folder_id, ancestors=[]
)
)
def get_templates_and_folders(self, template_type, template_folder_id, ancestors):
for item in self.get_template_folders(
template_type, template_folder_id,
template_type,
template_folder_id,
):
yield TemplateListFolder(
item,
folders=self.get_template_folders(
template_type, item['id'],
),
templates=self.get_templates(
template_type, item['id']
template_type,
item["id"],
),
templates=self.get_templates(template_type, item["id"]),
ancestors=ancestors,
service_id=self.service.id,
)
for sub_item in self.get_templates_and_folders(
template_type, item['id'], ancestors + [item]
template_type, item["id"], ancestors + [item]
):
yield sub_item
for item in self.get_templates(
template_type, template_folder_id,
template_type,
template_folder_id,
):
yield TemplateListTemplate(
item,
@@ -56,7 +57,7 @@ class TemplateList():
service_id=self.service.id,
)
def get_templates(self, template_type='all', template_folder_id=None):
def get_templates(self, template_type="all", template_folder_id=None):
if self.user and template_folder_id:
folder = self.service.get_template_folder(template_folder_id)
if not self.user.has_template_folder_permission(folder):
@@ -67,9 +68,10 @@ class TemplateList():
if template_folder_id:
template_folder_id = str(template_folder_id)
return [
template for template in self.service.all_templates
if (set(template_type) & {'all', template['template_type']})
and template.get('folder') == template_folder_id
template
for template in self.service.all_templates
if (set(template_type) & {"all", template["template_type"]})
and template.get("folder") == template_folder_id
]
@cached_property
@@ -89,15 +91,19 @@ class TemplateList():
"""
user_folders = []
for folder in self.service.all_template_folders:
if not self.user.has_template_folder_permission(folder, service=self.service):
if not self.user.has_template_folder_permission(
folder, service=self.service
):
continue
parent = self.service.get_template_folder(folder["parent_id"])
if self.user.has_template_folder_permission(parent, service=self.service):
user_folders.append(folder)
else:
folder_attrs = {
"id": folder["id"], "name": folder["name"], "parent_id": folder["parent_id"],
"users_with_permission": folder["users_with_permission"]
"id": folder["id"],
"name": folder["name"],
"parent_id": folder["parent_id"],
"users_with_permission": folder["users_with_permission"],
}
while folder_attrs["parent_id"] is not None:
folder_attrs["name"] = [
@@ -109,12 +115,14 @@ class TemplateList():
else:
parent = self.service.get_template_folder(parent["parent_id"])
folder_attrs["parent_id"] = parent.get("id", None)
if self.user.has_template_folder_permission(parent, service=self.service):
if self.user.has_template_folder_permission(
parent, service=self.service
):
break
user_folders.append(folder_attrs)
return user_folders
def get_template_folders(self, template_type='all', parent_folder_id=None):
def get_template_folders(self, template_type="all", parent_folder_id=None):
if self.user:
folders = self.user_template_folders
else:
@@ -123,24 +131,26 @@ class TemplateList():
parent_folder_id = str(parent_folder_id)
return [
folder for folder in folders
folder
for folder in folders
if (
folder['parent_id'] == parent_folder_id
and self.is_folder_visible(folder['id'], template_type)
folder["parent_id"] == parent_folder_id
and self.is_folder_visible(folder["id"], template_type)
)
]
def is_folder_visible(self, template_folder_id, template_type='all'):
if template_type == 'all':
def is_folder_visible(self, template_folder_id, template_type="all"):
if template_type == "all":
return True
if self.get_templates(template_type, template_folder_id):
return True
if any(
self.is_folder_visible(child_folder['id'], template_type)
for child_folder in self.get_template_folders(template_type, template_folder_id)
self.is_folder_visible(child_folder["id"], template_type)
for child_folder in self.get_template_folders(
template_type, template_folder_id
)
):
return True
@@ -156,9 +166,9 @@ class TemplateList():
@property
def folder_is_empty(self):
return not any(self.get_templates_and_folders(
'all', self.template_folder_id, []
))
return not any(
self.get_templates_and_folders("all", self.template_folder_id, [])
)
class ServiceTemplateList(TemplateList):
@@ -178,12 +188,11 @@ class ServiceTemplateList(TemplateList):
yield from self.get_templates_and_folders(
self.template_type,
self.template_folder_id,
ancestors=[template_list_service]
ancestors=[template_list_service],
)
class TemplateLists():
class TemplateLists:
def __init__(self, user):
self.services = sorted(
user.services,
@@ -210,8 +219,7 @@ class TemplateLists():
return bool(self.services)
class TemplateListItem():
class TemplateListItem:
is_service = False
def __init__(
@@ -219,13 +227,12 @@ class TemplateListItem():
template_or_folder,
ancestors,
):
self.id = template_or_folder['id']
self.name = template_or_folder['name']
self.id = template_or_folder["id"]
self.name = template_or_folder["name"]
self.ancestors = ancestors
class TemplateListTemplate(TemplateListItem):
is_folder = False
def __init__(
@@ -236,16 +243,15 @@ class TemplateListTemplate(TemplateListItem):
):
super().__init__(template, ancestors)
self.service_id = service_id
self.template_type = template['template_type']
self.content = template.get('content')
self.template_type = template["template_type"]
self.content = template.get("content")
@property
def hint(self):
return format_notification_type(self.template_type) + ' template'
return format_notification_type(self.template_type) + " template"
class TemplateListFolder(TemplateListItem):
is_folder = True
def __init__(
@@ -264,23 +270,22 @@ class TemplateListFolder(TemplateListItem):
@property
def _hint_parts(self):
if self.number_of_folders == self.number_of_templates == 0:
yield 'Empty'
yield "Empty"
if self.number_of_templates == 1:
yield '1 template'
yield "1 template"
elif self.number_of_templates > 1:
yield '{} templates'.format(self.number_of_templates)
yield "{} templates".format(self.number_of_templates)
if self.number_of_folders == 1:
yield '1 folder'
yield "1 folder"
elif self.number_of_folders > 1:
yield '{} folders'.format(self.number_of_folders)
yield "{} folders".format(self.number_of_folders)
@property
def hint(self):
return ', '.join(self._hint_parts)
return ", ".join(self._hint_parts)
class TemplateListService(TemplateListFolder):

View File

@@ -24,36 +24,35 @@ from app.utils.user_permissions import (
def _get_service_id_from_view_args():
return str(request.view_args.get('service_id', '')) or None
return str(request.view_args.get("service_id", "")) or None
def _get_org_id_from_view_args():
return str(request.view_args.get('org_id', '')) or None
return str(request.view_args.get("org_id", "")) or None
class User(JSONModel, UserMixin):
MAX_FAILED_LOGIN_COUNT = 10
ALLOWED_PROPERTIES = {
'id',
'name',
'email_address',
'auth_type',
'current_session_id',
'failed_login_count',
'email_access_validated_at',
'logged_in_at',
'mobile_number',
'password_changed_at',
'permissions',
'state',
"id",
"name",
"email_address",
"auth_type",
"current_session_id",
"failed_login_count",
"email_access_validated_at",
"logged_in_at",
"mobile_number",
"password_changed_at",
"permissions",
"state",
}
def __init__(self, _dict):
super().__init__(_dict)
self.permissions = _dict.get('permissions', {})
self._platform_admin = _dict['platform_admin']
self.permissions = _dict.get("permissions", {})
self._platform_admin = _dict["platform_admin"]
@classmethod
def from_id(cls, user_id):
@@ -104,8 +103,7 @@ class User(JSONModel, UserMixin):
"""
self._permissions = {
service: translate_permissions_from_db_to_ui(permissions)
for service, permissions
in permissions_by_service.items()
for service, permissions in permissions_by_service.items()
}
def update(self, **kwargs):
@@ -117,9 +115,7 @@ class User(JSONModel, UserMixin):
self.__init__(response)
def update_email_access_validated_at(self):
self.update(
email_access_validated_at=datetime.utcnow().isoformat()
)
self.update(email_access_validated_at=datetime.utcnow().isoformat())
def password_changed_more_recently_than(self, datetime_string):
if not self.password_changed_at:
@@ -144,24 +140,26 @@ class User(JSONModel, UserMixin):
)
def logged_in_elsewhere(self):
return session.get('current_session_id') != self.current_session_id
return session.get("current_session_id") != self.current_session_id
def activate(self):
if self.is_pending:
user_data = user_api_client.activate_user(self.id)
return self.__class__(user_data['data'])
return self.__class__(user_data["data"])
else:
return self
def login(self):
login_user(self)
session['user_id'] = self.id
session["user_id"] = self.id
def send_login_code(self):
if self.email_auth:
user_api_client.send_verify_code(self.id, 'email', None, request.args.get('next'))
user_api_client.send_verify_code(
self.id, "email", None, request.args.get("next")
)
if self.sms_auth:
user_api_client.send_verify_code(self.id, 'sms', self.mobile_number)
user_api_client.send_verify_code(self.id, "sms", self.mobile_number)
def sign_out(self):
session.clear()
@@ -172,22 +170,22 @@ class User(JSONModel, UserMixin):
@property
def sms_auth(self):
return self.auth_type == 'sms_auth'
return self.auth_type == "sms_auth"
@property
def email_auth(self):
return self.auth_type == 'email_auth'
return self.auth_type == "email_auth"
def reset_failed_login_count(self):
user_api_client.reset_failed_login_count(self.id)
@property
def is_active(self):
return self.state == 'active'
return self.state == "active"
@property
def is_pending(self):
return self.state == 'pending'
return self.state == "pending"
@property
def is_gov_user(self):
@@ -197,20 +195,25 @@ class User(JSONModel, UserMixin):
@property
def is_authenticated(self):
return (
not self.logged_in_elsewhere() and
super(User, self).is_authenticated
)
return not self.logged_in_elsewhere() and super(User, self).is_authenticated
@property
def platform_admin(self):
current_app.logger.warn(f"Checking User {self.id} for platform admin: {self._platform_admin}")
return self._platform_admin and not session.get('disable_platform_admin_view', False)
current_app.logger.warn(
f"Checking User {self.id} for platform admin: {self._platform_admin}"
)
return self._platform_admin and not session.get(
"disable_platform_admin_view", False
)
def has_permissions(self, *permissions, restrict_admin_usage=False, allow_org_user=False):
def has_permissions(
self, *permissions, restrict_admin_usage=False, allow_org_user=False
):
unknown_permissions = set(permissions) - all_ui_permissions
if unknown_permissions:
raise TypeError('{} are not valid permissions'.format(list(unknown_permissions)))
raise TypeError(
"{} are not valid permissions".format(list(unknown_permissions))
)
# Service id is always set on the request for service specific views.
service_id = _get_service_id_from_view_args()
@@ -236,9 +239,7 @@ class User(JSONModel, UserMixin):
current_app.logger.warn(f"{log_msg} True because belongs_to_service")
return True
if any(
self.permissions_for_service(service_id) & set(permissions)
):
if any(self.permissions_for_service(service_id) & set(permissions)):
current_app.logger.warn(f"{log_msg} permissions valid")
return True
@@ -266,7 +267,7 @@ class User(JSONModel, UserMixin):
return True
# Top-level templates are always visible
if template_folder is None or template_folder['id'] is None:
if template_folder is None or template_folder["id"] is None:
return True
return self.id in template_folder.get("users_with_permission", [])
@@ -297,7 +298,7 @@ class User(JSONModel, UserMixin):
@property
def email_domain(self):
return self.email_address.split('@')[-1]
return self.email_address.split("@")[-1]
@cached_property
def orgs_and_services(self):
@@ -306,38 +307,36 @@ class User(JSONModel, UserMixin):
@property
def services(self):
from app.models.service import Services
return Services(self.orgs_and_services['services'])
return Services(self.orgs_and_services["services"])
@property
def services_with_organization(self):
return [
service for service in self.services
service
for service in self.services
if self.belongs_to_organization(service.organization_id)
]
@property
def service_ids(self):
return self._dict['services']
return self._dict["services"]
@property
def trial_mode_services(self):
return [
service for service in self.services if service.trial_mode
]
return [service for service in self.services if service.trial_mode]
@property
def live_services(self):
return [
service for service in self.services if service.live
]
return [service for service in self.services if service.live]
@property
def organizations(self):
return Organizations(self.orgs_and_services['organizations'])
return Organizations(self.orgs_and_services["organizations"])
@property
def organization_ids(self):
return self._dict['organizations']
return self._dict["organizations"]
@cached_property
def default_organization(self):
@@ -351,11 +350,7 @@ class User(JSONModel, UserMixin):
@property
def has_access_to_live_and_trial_mode_services(self):
return (
self.organizations or self.live_services
) and (
self.trial_mode_services
)
return (self.organizations or self.live_services) and (self.trial_mode_services)
def serialize(self):
dct = {
@@ -368,10 +363,10 @@ class User(JSONModel, UserMixin):
"failed_login_count": self.failed_login_count,
"permissions": [x for x in self._permissions],
"organizations": self.organization_ids,
"current_session_id": self.current_session_id
"current_session_id": self.current_session_id,
}
if hasattr(self, '_password'):
dct['password'] = self._password
if hasattr(self, "_password"):
dct["password"] = self._password
return dct
@classmethod
@@ -383,13 +378,15 @@ class User(JSONModel, UserMixin):
password,
auth_type,
):
return cls(user_api_client.register_user(
name,
email_address,
mobile_number or None,
password,
auth_type,
))
return cls(
user_api_client.register_user(
name,
email_address,
mobile_number or None,
password,
auth_type,
)
)
def set_password(self, pwd):
self._password = pwd
@@ -398,16 +395,20 @@ class User(JSONModel, UserMixin):
user_api_client.send_verify_email(self.id, self.email_address)
def send_verify_code(self, to=None):
user_api_client.send_verify_code(self.id, 'sms', to or self.mobile_number)
user_api_client.send_verify_code(self.id, "sms", to or self.mobile_number)
def send_already_registered_email(self):
user_api_client.send_already_registered_email(self.id, self.email_address)
def refresh_session_id(self):
self.current_session_id = user_api_client.get_user(self.id).get('current_session_id')
session['current_session_id'] = self.current_session_id
self.current_session_id = user_api_client.get_user(self.id).get(
"current_session_id"
)
session["current_session_id"] = self.current_session_id
def add_to_service(self, service_id, permissions, folder_permissions, invited_by_id):
def add_to_service(
self, service_id, permissions, folder_permissions, invited_by_id
):
try:
user_api_client.add_user_to_service(
service_id,
@@ -422,7 +423,10 @@ class User(JSONModel, UserMixin):
ui_permissions=permissions,
)
except HTTPError as exception:
if exception.status_code == 400 and 'already part of service' in exception.message:
if (
exception.status_code == 400
and "already part of service" in exception.message
):
pass
else:
raise exception
@@ -442,22 +446,21 @@ class User(JSONModel, UserMixin):
class InvitedUser(JSONModel):
ALLOWED_PROPERTIES = {
'id',
'service',
'email_address',
'permissions',
'status',
'created_at',
'auth_type',
'folder_permissions',
"id",
"service",
"email_address",
"permissions",
"status",
"created_at",
"auth_type",
"folder_permissions",
}
def __init__(self, _dict):
super().__init__(_dict)
self.permissions = _dict.get('permissions') or []
self._from_user = _dict['from_user']
self.permissions = _dict.get("permissions") or []
self._from_user = _dict["from_user"]
@classmethod
def create(
@@ -469,14 +472,16 @@ class InvitedUser(JSONModel):
auth_type,
folder_permissions,
):
return cls(invite_api_client.create_invite(
invite_from_id,
service_id,
email_address,
permissions,
auth_type,
folder_permissions,
))
return cls(
invite_api_client.create_invite(
invite_from_id,
service_id,
email_address,
permissions,
auth_type,
folder_permissions,
)
)
@classmethod
def by_id_and_service_id(cls, service_id, invited_user_id):
@@ -486,9 +491,7 @@ class InvitedUser(JSONModel):
@classmethod
def by_id(cls, invited_user_id):
return cls(
invite_api_client.get_invited_user(invited_user_id)
)
return cls(invite_api_client.get_invited_user(invited_user_id))
def accept_invite(self):
invite_api_client.accept_invite(self.service, self.id)
@@ -502,7 +505,7 @@ class InvitedUser(JSONModel):
if isinstance(permissions, list):
self._permissions = permissions
else:
self._permissions = permissions.split(',')
self._permissions = permissions.split(",")
self._permissions = translate_permissions_from_db_to_ui(self.permissions)
@property
@@ -511,110 +514,122 @@ class InvitedUser(JSONModel):
@property
def sms_auth(self):
return self.auth_type == 'sms_auth'
return self.auth_type == "sms_auth"
@property
def email_auth(self):
return self.auth_type == 'email_auth'
return self.auth_type == "email_auth"
@classmethod
def from_token(cls, token):
try:
return cls(invite_api_client.check_token(token))
except HTTPError as exception:
if exception.status_code == 400 and 'invitation' in exception.message:
raise InviteTokenError(exception.message['invitation'])
if exception.status_code == 400 and "invitation" in exception.message:
raise InviteTokenError(exception.message["invitation"])
else:
raise exception
@classmethod
def from_session(cls):
invited_user_id = session.get('invited_user_id')
invited_user_id = session.get("invited_user_id")
return cls.by_id(invited_user_id) if invited_user_id else None
def has_permissions(self, *permissions):
current_app.logger.warn(f"Checking invited user {self.id} for permissions: {permissions}")
if self.status == 'cancelled':
current_app.logger.warn(
f"Checking invited user {self.id} for permissions: {permissions}"
)
if self.status == "cancelled":
return False
return set(self.permissions) > set(permissions)
def has_permission_for_service(self, service_id, permission):
current_app.logger.warn(f"Checking invited user {self.id} for permission: {permission} on service {service_id}")
if self.status == 'cancelled':
current_app.logger.warn(
f"Checking invited user {self.id} for permission: {permission} on service {service_id}"
)
if self.status == "cancelled":
return False
return self.service == service_id and permission in self.permissions
def __eq__(self, other):
return ((self.id,
self.service,
self._from_user,
self.email_address,
self.auth_type,
self.status) == (other.id,
other.service,
other._from_user,
other.email_address,
other.auth_type,
other.status))
return (
self.id,
self.service,
self._from_user,
self.email_address,
self.auth_type,
self.status,
) == (
other.id,
other.service,
other._from_user,
other.email_address,
other.auth_type,
other.status,
)
def serialize(self, permissions_as_string=False):
data = {'id': self.id,
'service': self.service,
'from_user': self._from_user,
'email_address': self.email_address,
'status': self.status,
'created_at': str(self.created_at),
'auth_type': self.auth_type,
'folder_permissions': self.folder_permissions
}
data = {
"id": self.id,
"service": self.service,
"from_user": self._from_user,
"email_address": self.email_address,
"status": self.status,
"created_at": str(self.created_at),
"auth_type": self.auth_type,
"folder_permissions": self.folder_permissions,
}
if permissions_as_string:
data['permissions'] = ','.join(self.permissions)
data["permissions"] = ",".join(self.permissions)
else:
data['permissions'] = sorted(self.permissions)
data["permissions"] = sorted(self.permissions)
return data
def template_folders_for_service(self, service=None):
# only used on the manage users page to display the count, so okay to not be fully fledged for now
return [{'id': x} for x in self.folder_permissions]
return [{"id": x} for x in self.folder_permissions]
def is_editable_by(self, other):
return False
class InvitedOrgUser(JSONModel):
ALLOWED_PROPERTIES = {
'id',
'organization',
'email_address',
'status',
'created_at',
"id",
"organization",
"email_address",
"status",
"created_at",
}
def __init__(self, _dict):
super().__init__(_dict)
self._invited_by = _dict['invited_by']
self._invited_by = _dict["invited_by"]
def __eq__(self, other):
return ((self.id,
self.organization,
self._invited_by,
self.email_address,
self.status) == (other.id,
other.organization,
other._invited_by,
other.email_address,
other.status))
return (
self.id,
self.organization,
self._invited_by,
self.email_address,
self.status,
) == (
other.id,
other.organization,
other._invited_by,
other.email_address,
other.status,
)
@classmethod
def create(cls, invite_from_id, org_id, email_address):
return cls(org_invite_api_client.create_invite(
invite_from_id, org_id, email_address
))
return cls(
org_invite_api_client.create_invite(invite_from_id, org_id, email_address)
)
@classmethod
def from_session(cls):
invited_org_user_id = session.get('invited_org_user_id')
invited_org_user_id = session.get("invited_org_user_id")
return cls.by_id(invited_org_user_id) if invited_org_user_id else None
@classmethod
@@ -625,18 +640,17 @@ class InvitedOrgUser(JSONModel):
@classmethod
def by_id(cls, invited_user_id):
return cls(
org_invite_api_client.get_invited_user(invited_user_id)
)
return cls(org_invite_api_client.get_invited_user(invited_user_id))
def serialize(self, permissions_as_string=False):
data = {'id': self.id,
'organization': self.organization,
'invited_by': self._invited_by,
'email_address': self.email_address,
'status': self.status,
'created_at': str(self.created_at)
}
data = {
"id": self.id,
"organization": self.organization,
"invited_by": self._invited_by,
"email_address": self.email_address,
"status": self.status,
"created_at": str(self.created_at),
}
return data
@property
@@ -648,8 +662,8 @@ class InvitedOrgUser(JSONModel):
try:
return cls(org_invite_api_client.check_token(token))
except HTTPError as exception:
if exception.status_code == 400 and 'invitation' in exception.message:
raise InviteTokenError(exception.message['invitation'])
if exception.status_code == 400 and "invitation" in exception.message:
raise InviteTokenError(exception.message["invitation"])
else:
raise exception
@@ -669,7 +683,6 @@ class AnonymousUser(AnonymousUserMixin):
class Users(ModelList):
client_method = user_api_client.get_users_for_service
model = User
@@ -683,7 +696,7 @@ class Users(ModelList):
user = User.from_id(id)
if user and user.name:
return user.name
return 'Unknown'
return "Unknown"
class OrganizationUsers(Users):
@@ -691,14 +704,14 @@ class OrganizationUsers(Users):
class InvitedUsers(Users):
client_method = invite_api_client.get_invites_for_service
model = InvitedUser
def __init__(self, service_id):
self.items = [
user for user in self.client_method(service_id)
if user['status'] != 'accepted'
user
for user in self.client_method(service_id)
if user["status"] != "accepted"
]