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 = fields.Nested( 'AgentQueuesMemberSchema', attribute='queue_queue_members', many=True, dump_only=True, ) skills = fields.Nested('AgentSkillsSchema', attribute='agent_queue_skills', many=True, dump_only=True) users = fields.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 SipSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) username = fields.String(validate=Regexp(USERNAME_REGEX)) name = fields.String(validate=Regexp(USERNAME_REGEX)) secret = fields.String(validate=Regexp(SECRET_REGEX)) type = fields.String(validate=OneOf(['friend', 'peer', 'user'])) host = fields.String(validate=Length(max=255)) options = fields.List( fields.List(fields.String(), validate=Length(equal=2))) links = ListLink(Link('endpoint_sip')) trunk = fields.Nested('TrunkSchema', only=['id', 'links'], dump_only=True) line = fields.Nested('LineSchema', only=['id', 'links'], dump_only=True) # The set_name_to_username_if_missing method is a compatibility method that # was added in 19.15 to avoid breaking the API. In the old version, the name # could not be specified in the API the username was always copied. @post_load def set_name_to_username_if_missing(self, data, **kwargs): name = data.get('name') if not name and 'username' in data: logger.warning( 'DEPRECATION: creating a SIP endpoint with a "username" and no "name" is' ' deprecated. Populate the name field if it is required') data['name'] = data['username'] return data
class ExternalAppSchema(BaseSchema): tenant_uuid = fields.String(dump_only=True) name = fields.String(dump_only=True) label = fields.String(validate=Length(max=256), allow_none=True) configuration = fields.Dict(allow_none=True) links = ListLink(Link('external_apps', field='name'))
class UserCallPermissionSchema(BaseSchema): user_id = fields.Integer() call_permission_id = fields.Integer() links = ListLink( Link('users', field='user_id', target='id'), Link('callpermissions', field='call_permission_id', target='id'), )
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 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 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 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 ExtensionFeatureSchema(BaseSchema): id = fields.Integer(dump_only=True) exten = fields.String(validate=Regexp(EXTEN_REGEX), required=True) context = fields.String(dump_only=True) feature = fields.String(attribute='typeval', dump_only=True) enabled = fields.Boolean() links = ListLink(Link('extensions_features'))
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 LineExtensionLegacySchema(BaseSchema): line_id = fields.Integer(dump_only=True) extension_id = fields.Integer(required=True) links = ListLink( Link('lines', field='line_id', target='id'), Link('extensions', field='extension_id', target='id'), )
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 = fields.Nested('SipSchema', only=['id', 'username', 'links'], dump_only=True) endpoint_custom = fields.Nested('CustomSchema', only=['id', 'interface', 'links'], dump_only=True) endpoint_iax = fields.Nested('IAXSchema', only=['id', 'name', 'links'], dump_only=True) outcalls = fields.Nested('OutcallSchema', only=['id', 'name', 'links'], many=True, dump_only=True) register_iax = fields.Nested('RegisterIAXSchema', only=['id', 'links'], dump_only=True) register_sip = fields.Nested('RegisterSIPSchema', only=['id', 'links'], dump_only=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 FuncKeyTemplateUserSchema(BaseSchema): user_id = fields.Integer(attribute='id') template_id = fields.Integer(attribute='func_key_template_id') links = ListLink( Link('func_keys_templates', field='func_key_template_id', target='id'), Link('users', field='id'), )
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 LineDeviceSchema(BaseSchema): line_id = fields.Integer() device_id = fields.String() links = ListLink( Link('lines', field='line_id', target='id'), Link('devices', field='device_id', target='id'), )
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 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 UserVoicemailSchema(BaseSchema): user_id = fields.Integer(dump_only=True) voicemail_id = fields.Integer(required=True) links = ListLink( Link('voicemails', field='voicemail_id', target='id'), Link('users', field='user_id', target='id'), )
class FuncKeyTemplateSchema(BaseSchema): id = fields.Integer(dump_only=True) name = fields.String(validate=Length(max=128)) keys = FuncKeyPositionField( fields.Integer(validate=Range(min=1)), fields.Nested(FuncKeySchema, required=True, unknown=EXCLUDE), ) links = ListLink(Link('func_keys_templates'))
class MeetingSchema(BaseSchema): uuid = fields.UUID(dump_only=True) owner_uuids = fields.List(fields.UUID()) name = fields.String(validate=Length(max=512), required=True) ingress_http_uri = fields.Method('_uri', dump_only=True) guest_sip_authorization = fields.Method('_guest_sip_authorization', dump_only=True) persistent = fields.Boolean(missing=False) links = ListLink(Link('meetings', field='uuid')) tenant_uuid = fields.String(dump_only=True) creation_time = fields.DateTime(attribute='created_at', dump_only=True) exten = fields.Method('_exten', dump_only=True) require_authorization = fields.Boolean(missing=False) def _uri(self, meeting): if meeting.ingress_http: return meeting.ingress_http.uri default_ingress_http = self.context['default_ingress_http'] if default_ingress_http: return default_ingress_http.uri raise NoIngressHTTPException() def _exten(self, meeting): prefix = self.context['exten_prefix'] if not prefix: logger.debug( 'cannot add the meeting exten, no "meetingjoin" extension_features configured' ) return return '{}{}'.format(prefix, meeting.number) def _guest_sip_authorization(self, model): if not model.guest_endpoint_sip: return None if model.require_authorization: return None return self.format_sip_authorization(model.guest_endpoint_sip) @staticmethod def format_sip_authorization(endpoint_sip): username = None password = None for option, value in endpoint_sip.auth_section_options: if option == 'username': username = value elif option == 'password': password = value if username is None or password is None: return None return b64encode('{}:{}'.format(username, password).encode()).decode()
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 LineSipSchema(BaseSchema): id = fields.Integer(dump_only=True) username = fields.String(validate=Regexp(USERNAME_REGEX)) secret = fields.String(validate=Regexp(SECRET_REGEX)) callerid = fields.String(validate=Regexp(CALLERID_REGEX), allow_none=True) device_slot = fields.Integer(validate=Range(min=0)) context = fields.String(required=True) provisioning_extension = fields.String( validate=(Length(equal=6), Predicate('isdigit')) ) links = ListLink(Link('lines'), Link('lines_sip'))
class SkillSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(validate=(Regexp(NAME_REGEX), Length(max=64)), required=True) category = fields.String(validate=Length(max=64), allow_none=True) description = fields.String(allow_none=True) links = ListLink(Link('skills')) agents = fields.Nested( 'SkillAgentsSchema', attribute='agent_queue_skills', many=True, dump_only=True )
class ContextSchema(BaseSchema): id = fields.Integer(dump_only=True) name = fields.String( validate=( Regexp(CONTEXT_REGEX), Length(min=1, max=39), NoneOf( [ 'authentication', 'general', 'global', 'globals', 'parkedcalls', 'xivo-features', 'zonemessages', ] ), ), required=True, ) label = fields.String(validate=Length(max=128), allow_none=True) type = fields.String( validate=OneOf(['internal', 'incall', 'outcall', 'services', 'others']) ) user_ranges = Nested(RangeSchema, many=True) group_ranges = Nested(RangeSchema, many=True) queue_ranges = Nested(RangeSchema, many=True) conference_room_ranges = Nested(RangeSchema, many=True) incall_ranges = Nested(IncallRangeSchema, many=True) description = fields.String(allow_none=True) tenant_uuid = fields.String(dump_only=True) enabled = StrictBoolean() links = ListLink(Link('contexts')) contexts = Nested( 'ContextSchema', only=['id', 'name', 'label', 'links'], many=True, dump_only=True, ) @post_load def create_objects(self, data, **kwargs): for key in [ 'user_ranges', 'group_ranges', 'queue_ranges', 'conference_room_ranges', 'incall_ranges', ]: if data.get(key): data[key] = [ContextNumbers(**d) for d in data[key]] return data
class IAXSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(validate=Regexp(NAME_REGEX)) type = fields.String(validate=OneOf(['friend', 'peer', 'user'])) host = fields.String(validate=Length(max=255)) options = fields.List(fields.List(fields.String(), validate=Length(equal=2))) links = ListLink(Link('endpoint_iax')) trunk = fields.Nested( 'TrunkSchema', only=['id', 'links'], dump_only=True, attribute='trunk_rel' )
class LineSchema(BaseSchema): id = fields.Integer(dump_only=True) tenant_uuid = fields.String(dump_only=True) name = fields.String(dump_only=True) protocol = fields.String(dump_only=True) device_id = fields.String(dump_only=True) device_slot = fields.Integer(dump_only=True) provisioning_extension = fields.String(dump_only=True) context = fields.String(required=True) provisioning_code = fields.String(validate=(Predicate('isdigit'), Length(equal=6))) position = fields.Integer(validate=Range(min=1)) caller_id_name = fields.String( allow_none=True) # Validate length callerid_name + num = max(160) caller_id_num = fields.String(validate=Predicate('isdigit'), allow_none=True) registrar = fields.String(validate=Length(max=128)) links = ListLink(Link('lines')) application = Nested('ApplicationSchema', only=['uuid', 'name', 'links'], dump_only=True) endpoint_sip = Nested( 'EndpointSIPSchema', # TODO(pc-m): Is it really useful to have the username/password on the relation? only=[ 'uuid', 'label', 'name', 'auth_section_options.username', 'links', ], dump_only=True, ) endpoint_sccp = Nested('SccpSchema', only=['id', 'links'], dump_only=True) endpoint_custom = Nested('CustomSchema', only=['id', 'interface', 'links'], dump_only=True) extensions = Nested( 'ExtensionSchema', only=['id', 'exten', 'context', 'links'], many=True, dump_only=True, ) users = Nested( 'UserSchema', only=['uuid', 'firstname', 'lastname', 'links'], many=True, dump_only=True, )
class SoundSchema(BaseSchema): tenant_uuid = fields.String() name = fields.String( validate=[ Length(max=149, min=1), NoneOf([ASTERISK_CATEGORY]), NoneOf(RESERVED_DIRECTORIES, error=RESERVED_DIRECTORIES_ERROR), Regexp(DIRECTORY_REGEX), ], required=True, ) files = Nested(SoundFileSchema, many=True, dump_only=True) links = ListLink(Link('sounds', field='name', target='category'))