class TrunkSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) context = fields.String(allow_none=True) twilio_incoming = StrictBoolean(allow_none=True) links = ListLink(Link('trunks')) endpoint_sip = Nested( 'EndpointSIPSchema', only=[ 'uuid', 'label', 'name', 'auth_section_options.username', 'registration_section_options.client_uri', 'links', ], dump_only=True, ) endpoint_custom = Nested( 'CustomSchema', only=['id', 'interface', 'links'], dump_only=True ) endpoint_iax = Nested('IAXSchema', only=['id', 'name', 'links'], dump_only=True) outcalls = Nested( 'OutcallSchema', only=['id', 'name', 'links'], many=True, dump_only=True ) register_iax = Nested('RegisterIAXSchema', only=['id', 'links'], dump_only=True)
class WizardDiscoverSchema(BaseSchema): hostname = fields.String() nameservers = fields.List(fields.String()) domain = fields.String() timezone = fields.String() interfaces = fields.List(Nested(WizardDiscoverInterfaceSchema)) gateways = fields.List(Nested(WizardDiscoverGatewaySchema))
class AgentSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) number = fields.String(validate=Regexp(NUMBER_REGEX), required=True) firstname = fields.String(validate=Length(max=128), allow_none=True) lastname = fields.String(validate=Length(max=128), allow_none=True) password = fields.String(validate=Length(max=128), allow_none=True, attribute='passwd') language = fields.String(validate=Length(max=20), allow_none=True) preprocess_subroutine = fields.String(validate=Length(max=39), allow_none=True) description = fields.String(allow_none=True) links = ListLink(Link('agents')) queues = Nested( 'AgentQueuesMemberSchema', attribute='queue_queue_members', many=True, dump_only=True, ) skills = Nested('AgentSkillsSchema', attribute='agent_queue_skills', many=True, dump_only=True) users = Nested( 'UserSchema', only=['uuid', 'firstname', 'lastname', 'links'], many=True, dump_only=True, )
class SwitchboardSchema(BaseSchema): uuid = fields.UUID(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(validate=Length(max=128), required=True) timeout = fields.Integer(validate=Range(min=1), allow_none=True) queue_music_on_hold = fields.String(validate=Length(max=128), allow_none=True) waiting_room_music_on_hold = fields.String( validate=Length(max=128), allow_none=True ) links = ListLink(Link('switchboards', field='uuid')) extensions = Nested( 'ExtensionSchema', only=['id', 'exten', 'context', 'links'], many=True, dump_only=True, ) incalls = Nested( 'IncallSchema', only=['id', 'extensions', 'links'], many=True, dump_only=True ) user_members = Nested( 'UserSchema', only=['uuid', 'firstname', 'lastname', 'links'], many=True, dump_only=True, ) fallbacks = Nested('SwitchboardFallbackSchema', dump_only=True) @post_dump def wrap_users(self, data, **kwargs): user_members = data.pop('user_members', []) if not self.only or 'members' in self.only: data['members'] = {'users': user_members} return data
class ConferenceSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(allow_none=True, validate=Length(max=128)) preprocess_subroutine = fields.String(allow_none=True, validate=Length(max=39)) max_users = fields.Integer(validate=Range(min=0)) record = fields.Boolean() pin = fields.String(allow_none=True, validate=(Length(max=80), Predicate('isdigit'))) admin_pin = fields.String(allow_none=True, validate=(Length(max=80), Predicate('isdigit'))) quiet_join_leave = fields.Boolean() announce_join_leave = fields.Boolean() announce_user_count = fields.Boolean() announce_only_user = fields.Boolean() music_on_hold = fields.String(allow_none=True, validate=Length(max=128)) links = ListLink(Link('conferences')) extensions = Nested( 'ExtensionSchema', only=['id', 'exten', 'context', 'links'], many=True, dump_only=True, ) incalls = Nested('IncallSchema', only=['id', 'extensions', 'links'], many=True, dump_only=True)
class CallPermissionSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(validate=Length(min=1, max=128), required=True) password = fields.String(validate=Regexp(PASSWORD_REGEX), allow_none=True) mode = fields.String(validate=OneOf(['allow', 'deny'])) extensions = fields.List(fields.String(validate=Regexp(EXTENSION_REGEX))) enabled = StrictBoolean() description = fields.String(allow_none=True) links = ListLink(Link('callpermissions')) outcalls = Nested('OutcallSchema', only=['id', 'name', 'links'], many=True, dump_only=True) groups = Nested('GroupSchema', only=['uuid', 'id', 'name', 'links'], many=True, dump_only=True) users = Nested( 'UserSchema', only=['uuid', 'firstname', 'lastname', 'links'], many=True, dump_only=True, )
class OutcallSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(validate=Length(max=128), required=True) internal_caller_id = StrictBoolean() preprocess_subroutine = fields.String(validate=Length(max=39), allow_none=True) ring_time = fields.Integer(validate=Range(min=0), allow_none=True) description = fields.String(allow_none=True) enabled = StrictBoolean() links = ListLink(Link('outcalls')) trunks = Nested( 'TrunkSchema', only=['tenant_uuid', 'id', 'endpoint_sip', 'endpoint_custom', 'links'], many=True, dump_only=True, ) extensions = Nested('DialPatternSchema', attribute='dialpatterns', many=True, dump_only=True) schedules = Nested( 'ScheduleSchema', only=['tenant_uuid', 'id', 'name', 'links'], many=True, dump_only=True, ) call_permissions = Nested( 'CallPermissionSchema', only=['tenant_uuid', 'id', 'name', 'links'], many=True, dump_only=True, )
class CustomSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) interface = fields.String(validate=Regexp(INTERFACE_REGEX), required=True) interface_suffix = fields.String(validate=Length(max=32), allow_none=True) enabled = StrictBoolean() links = ListLink(Link('endpoint_custom')) trunk = Nested('TrunkSchema', only=['id', 'links'], dump_only=True) line = Nested('LineSchema', only=['id', 'links'], dump_only=True)
class WizardSchema(BaseSchema): xivo_uuid = fields.UUID(dump_only=True) admin_username = fields.Constant(constant='root', dump_only=True) admin_password = fields.String(validate=Regexp(ADMIN_PASSWORD_REGEX), required=True) license = StrictBoolean(validate=Equal(True), required=True) language = fields.String(validate=OneOf(['en_US', 'fr_FR']), missing='en_US') timezone = fields.String(validate=Length(max=128), required=True) network = Nested(WizardNetworkSchema, required=True) steps = Nested(WizardStepsSchema, missing=WizardStepsSchema().load({}))
class ApplicationSchema(BaseSchema): uuid = fields.String(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(validate=Length(max=128), allow_none=True) destination = fields.String( validate=OneOf(ApplicationDestinationOptionsField._options.keys()), allow_none=True, default=None, ) destination_options = ApplicationDestinationOptionsField(default={}) links = ListLink( Link('applications', field='uuid', target='application_uuid')) lines = Nested('LineSchema', only=['id', 'name', 'links'], many=True, dump_only=True) @pre_dump def map_destination(self, obj, **kwargs): if obj.dest_node: obj.destination = 'node' obj.destination_options = obj.dest_node return obj @post_load def create_objects(self, data, **kwargs): dest = data.pop('destination', None) dest_options = data.pop('destination_options', {}) data['dest_node'] = None if dest == 'node': data['dest_node'] = ApplicationDestNode(**dest_options) return data
class ParkingLotSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(allow_none=True, validate=Length(max=128)) slots_start = fields.String(validate=(Length(max=40), Predicate('isdigit')), required=True) slots_end = fields.String(validate=(Length(max=40), Predicate('isdigit')), required=True) timeout = fields.Integer(validate=Range(min=0), allow_none=True, missing=45) music_on_hold = fields.String(validate=Length(max=128), allow_none=True, missing='default') links = ListLink(Link('parkinglots')) extensions = Nested( 'ExtensionSchema', only=['id', 'exten', 'context', 'links'], many=True, dump_only=True, ) @validates_schema def validate_slots_range(self, data, **kwargs): # validates_schema is executed before fields validator, so the required # fields is not yet checked if not data.get('slots_start') or not data.get('slots_end'): return if int(data['slots_start']) > int(data['slots_end']): raise ValidationError('It is not a valid range')
class MohSchema(BaseSchema): uuid = fields.UUID(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(dump_only=True) label = fields.String(validate=Length(max=128), required=True) mode = fields.String(validate=OneOf(['custom', 'files', 'mp3']), required=True) application = fields.String(validate=Length(max=256), allow_none=True) sort = fields.String(validate=OneOf( ['alphabetical', 'random', 'random_start']), allow_none=True) files = Nested(MohFileSchema, many=True, dump_only=True) links = ListLink(Link('moh', field='uuid')) # DEPRECATED 21.15 @pre_load def copy_name_to_label(self, data, **kwargs): if 'label' in data: return data if 'name' in data: logger.warning( 'the "name" field of moh is deprecated. use "label" instead') data['label'] = data['name'] return data
class VoicemailDestinationSchema(BaseDestinationSchema): voicemail_id = fields.Integer(attribute='actionarg1', required=True) skip_instructions = StrictBoolean() greeting = fields.String(validate=OneOf(['busy', 'unavailable']), allow_none=True) voicemail = Nested('VoicemailSchema', only=['name'], dump_only=True) @pre_dump def separate_action(self, data, **kwargs): options = data.actionarg2 if data.actionarg2 else '' data.skip_instructions = True if 's' in options else False data.greeting = ('busy' if 'b' in options else 'unavailable' if 'u' in options else None) return data @post_load def merge_action(self, data, **kwargs): greeting = data.pop('greeting', None) data['actionarg2'] = '{}{}'.format( 'b' if greeting == 'busy' else 'u' if greeting == 'unavailable' else '', 's' if data.pop('skip_instructions', False) else '', ) return data @post_dump def make_voicemail_fields_flat(self, data, **kwargs): if data.get('voicemail'): data['voicemail_name'] = data['voicemail']['name'] data.pop('voicemail', None) return data
class FeaturesConfigurationSchema(BaseSchema): options = Nested(AsteriskOptionSchema, many=True, required=True) @pre_load def convert_options_to_collection(self, data, **kwargs): options = data.get('options') if isinstance(options, dict): data['options'] = [{ 'key': key, 'value': value } for key, value in options.items()] return data @post_dump def convert_options_to_dict(self, data, **kwargs): data['options'] = { option['key']: option['value'] for option in data['options'] } return data @pre_dump def add_envelope(self, data, **kwargs): return {'options': data} @post_load def remove_envelope(self, data, **kwargs): return data['options']
class VoicemailSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(validate=Length(max=80), required=True) number = fields.String(validate=Regexp(NUMBER_REGEX), required=True) context = fields.String(required=True) password = fields.String(validate=Regexp(PASSWORD_REGEX), allow_none=True) email = fields.String(validate=Length(max=80), allow_none=True) language = fields.String(validate=Regexp(LANGUAGE_REGEX), allow_none=True) timezone = fields.String(allow_none=True) pager = fields.String(validate=Length(max=80), allow_none=True) max_messages = fields.Integer(validate=Range(min=0), allow_none=True) attach_audio = StrictBoolean(allow_none=True) delete_messages = StrictBoolean() ask_password = StrictBoolean() enabled = StrictBoolean() options = fields.List( fields.List(fields.String(), validate=Length(equal=2))) links = ListLink(Link('voicemails')) users = Nested( 'UserSchema', only=['uuid', 'firstname', 'lastname', 'links'], many=True, dump_only=True, )
class EmailConfigSchema(BaseSchema): domain_name = fields.String(attribute='mydomain', validate=Length(max=255), missing='') from_ = fields.String(attribute='origin', data_key='from', validate=Length(max=255), missing='') address_rewriting_rules = fields.List( Nested(_RewriteRule, missing=None), attribute='canonical_lines', missing=[], ) smtp_host = fields.String(attribute='relayhost', validate=Length(max=255), missing='') fallback_smtp_host = fields.String(attribute='fallback_relayhost', validate=Length(max=255), missing='') @pre_dump def split_canonical(self, data, **kwargs): data.canonical_lines = [ line for line in data.canonical.split('\\n') if line ] return data @post_load def join_canonical(self, data, **kwargs): data['canonical'] = '\\n'.join(data.get('canonical_lines', [])) return data
class FuncKeyUnifiedTemplateSchema(BaseSchema): id = fields.Integer(dump_only=True) name = fields.String(validate=Length(max=128)) keys = FuncKeyPositionField( fields.Integer(validate=Range(min=1)), Nested(FuncKeySchema, required=True), )
class SccpSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) options = fields.List(fields.List(fields.String(), validate=Length(equal=2))) links = ListLink(Link('endpoint_sccp')) line = Nested('LineSchema', only=['id', 'links'], dump_only=True)
class UserDestinationSchema(BaseDestinationSchema): user_id = fields.Integer(required=True) user = Nested( 'UserSchema', attribute='userfeatures', only=['firstname', 'lastname'], dump_only=True, ) endpoint_list = 'users_list' @post_dump def generate_href(self, output, **kwargs): user_id = output['user_id'] output['href'] = url_for('users', id=user_id, _external=True) return output @post_dump def make_user_fields_flat(self, data, **kwargs): if data.get('user'): data['user_firstname'] = data['user']['firstname'] data['user_lastname'] = data['user']['lastname'] data.pop('user', None) return data
class CallFilterSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(validate=Length(max=128), required=True) strategy = fields.String( validate=OneOf([ 'all-recipients-then-linear-surrogates', 'all-recipients-then-all-surrogates', 'all-surrogates-then-all-recipients', 'linear-surrogates-then-all-recipients', 'all', ]), required=True, ) source = fields.String( validate=OneOf(['internal', 'external', 'all']), attribute='callfrom', required=True, ) caller_id_mode = fields.String(validate=OneOf( ['prepend', 'overwrite', 'append']), allow_none=True) caller_id_name = fields.String(validate=Length(max=80), allow_none=True) surrogates_timeout = fields.Integer(validate=Range(min=0), allow_none=True) description = fields.String(allow_none=True) enabled = StrictBoolean() links = ListLink(Link('callfilters')) recipients = Nested('CallFilterRecipientsSchema', many=True, dump_only=True) surrogates = Nested('CallFilterSurrogatesSchema', many=True, dump_only=True) fallbacks = Nested('CallFilterFallbackSchema', dump_only=True) @post_dump def wrap_users(self, data, **kwargs): recipient_users = data.pop('recipients', []) surrogate_users = data.pop('surrogates', []) if not self.only or 'recipients' in self.only: data['recipients'] = {'users': recipient_users} if not self.only or 'surrogates' in self.only: data['surrogates'] = {'users': surrogate_users} return data
class GroupExtensionsSchema(BaseSchema): extensions = Nested(GroupExtensionSchema, many=True, required=True) @post_load def set_default_priority(self, data, **kwargs): for priority, extension in enumerate(data['extensions']): extension['priority'] = extension.get('priority', priority) return data
class ServicesSchema(BaseSchema): dnd = Nested(ServiceDNDSchema) incallfilter = Nested(ServiceIncallFilterSchema) types = ['dnd', 'incallfilter'] @pre_dump() def add_envelope(self, data, **kwargs): return {type_: data for type_ in self.types} @post_load def remove_envelope(self, data, **kwargs): result = {} for service in data.values(): for key, value in service.items(): result[key] = value return result
def _serialize(self, nested_obj, attr, obj): base = super()._serialize(nested_obj, attr, obj) if not base: return base schema = self.destination_schemas[base['type']] if base['type'] == 'application': base = Nested(schema, **self.kwargs)._serialize(nested_obj, attr, obj) schema = self.application_schemas[base['application']] if base['type'] == 'hangup': base = Nested(schema, **self.kwargs)._serialize(nested_obj, attr, obj) schema = self.hangup_schemas[base['cause']] return Nested(schema, **self.kwargs)._serialize(nested_obj, attr, obj)
class GroupUsersSchema(BaseSchema): users = Nested(GroupUserSchema, many=True, required=True) @post_load def set_default_priority(self, data, **kwargs): for priority, user in enumerate(data['users']): user['priority'] = user.get('priority', priority) return data
class IAXGeneralSchema(BaseSchema): options = Nested(IAXGeneralOption, many=True, required=True) ordered_options = fields.List(Nested(IAXGeneralOrderedOption), required=True) @pre_load def convert_options_to_collection(self, data, **kwargs): options = data.get('options') if isinstance(options, dict): data['options'] = [{ 'key': key, 'value': value } for key, value in options.items()] return data @post_load def merge_options_and_ordered_options(self, data, **kwargs): self._add_metric(data) result = [] result.extend(data['options']) result.extend(data['ordered_options']) return result def _add_metric(self, data): for metric, ordered_option in enumerate(data['ordered_options']): ordered_option['metric'] = metric for option in data['options']: option['metric'] = None @pre_dump def separate_options_and_ordered_options(self, data, **kwargs): return { 'options': [option for option in data if option.metric is None], 'ordered_options': [option for option in data if option.metric is not None], } @post_dump def convert_options_to_dict(self, data, **kwargs): data['options'] = { option['key']: option['value'] for option in data['options'] } return data
class ExtensionSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) exten = fields.String(validate=Length(max=40), required=True) context = fields.String(required=True) commented = fields.Boolean(attribute='legacy_commented') enabled = fields.Boolean() links = ListLink(Link('extensions')) conference = Nested('ConferenceSchema', only=['id', 'name', 'links'], dump_only=True) parking_lot = Nested('ParkingLotSchema', only=['id', 'name', 'links'], dump_only=True) group = Nested('GroupSchema', only=['uuid', 'id', 'name', 'links'], dump_only=True) incall = Nested('IncallSchema', only=['id', 'links'], dump_only=True) lines = Nested('LineSchema', only=['id', 'name', 'links'], many=True, dump_only=True) outcall = Nested('OutcallSchema', only=['id', 'name', 'links'], dump_only=True) queue = Nested('QueueSchema', only=['id', 'name', 'label', 'links'], dump_only=True)
class ForwardsSchema(BaseSchema): busy = Nested(ForwardBusySchema) noanswer = Nested(ForwardNoAnswerSchema) unconditional = Nested(ForwardUnconditionalSchema) types = ['busy', 'noanswer', 'unconditional'] @pre_dump def add_envelope(self, data, **kwargs): return {type_: data for type_ in self.types} @post_load def remove_envelope(self, data, **kwargs): result = {} for forward in data.values(): for key, value in forward.items(): result[key] = value return result
class FuncKeyTemplateSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(validate=Length(max=128)) keys = FuncKeyPositionField( fields.Integer(validate=Range(min=1)), Nested(FuncKeySchema, required=True), ) links = ListLink(Link('func_keys_templates'))
class VoicemailZoneMessagesSchema(BaseSchema): items = Nested(VoicemailZoneMessagesOption, many=True, required=True) @post_load def remove_envelope(self, data, **kwargs): return data['items'] @pre_dump def add_envelope(self, data, **kwargs): return {'items': [option for option in data]}
class IAXCallNumberLimitsCollectionSchema(BaseSchema): items = Nested(IAXCallNumberLimitsSchema, many=True, required=True) @post_load def remove_envelope(self, data, **kwargs): return data['items'] @pre_dump def add_envelope(self, data, **kwargs): return {'items': [option for option in data]}