| from typing import Union, List | |
| from uuid import uuid4 | |
| class SolutionType: | |
| """ | |
| * HANGOUT - for Hangouts for consumers (hangouts.google.com) | |
| * NAMED_HANGOUT - for classic Hangouts for Google Workspace users (hangouts.google.com) | |
| * HANGOUTS_MEET - for Google Meet (meet.google.com) | |
| * ADD_ON - for 3P conference providers | |
| """ | |
| HANGOUT = 'eventHangout' | |
| NAMED_HANGOUT = 'eventNamedHangout' | |
| HANGOUTS_MEET = 'hangoutsMeet' | |
| ADD_ON = 'addOn' | |
| class _BaseConferenceSolution: | |
| """General conference-related information.""" | |
| def __init__( | |
| self, | |
| conference_id: str = None, | |
| signature: str = None, | |
| notes: str = None, | |
| _status: str = 'success' | |
| ): | |
| """ | |
| :param conference_id: | |
| The ID of the conference. Optional. | |
| Can be used by developers to keep track of conferences, should not be displayed to users. | |
| Values for solution types (see :py:class:`~gcsa.conference.SolutionType`): | |
| * HANGOUT: unset | |
| * NAMED_HANGOUT: the name of the Hangout | |
| * HANGOUTS_MEET: the 10-letter meeting code, for example "aaa-bbbb-ccc" | |
| * ADD_ON: defined by 3P conference provider | |
| :param signature: | |
| The signature of the conference data. | |
| Generated on server side. Must be preserved while copying the conference data between events, | |
| otherwise the conference data will not be copied. | |
| None for a conference with a failed create request. | |
| Optional for a conference with a pending create request. | |
| :param notes: | |
| String of additional notes (such as instructions from the domain administrator, legal notices) | |
| to display to the user. Can contain HTML. The maximum length is 2048 characters | |
| :param _status: | |
| The current status of the conference create request. Should not be set by developer. | |
| The possible values are: | |
| * "pending": the conference create request is still being processed. | |
| * "failure": the conference create request failed, there are no entry points. | |
| * "success": the conference create request succeeded, the entry points are populated. | |
| In this case `ConferenceSolution` with created entry points | |
| is stored in the event's `conference_data`. And `ConferenceSolutionCreateRequest` is omitted. | |
| Create requests are asynchronous. Check ``status`` field of event's ``conference_solution`` to find it's | |
| status. If the status is ``"success"``, ``conference_solution`` will contain a | |
| :py:class:`~gcsa.conference.ConferenceSolution` object and you'll be able to access it's field (like | |
| ``entry_points``). Otherwise (if ``status`` is ``""pending"`` or ``"failure"``), ``conference_solution`` | |
| will contain a :py:class:`~gcsa.conference.ConferenceSolutionCreateRequest` object. | |
| """ | |
| if notes and len(notes) > 2048: | |
| raise ValueError('Maximum notes length is 2048 characters.') | |
| self.conference_id = conference_id | |
| self.signature = signature | |
| self.notes = notes | |
| self.status = _status | |
| def __eq__(self, other): | |
| if not isinstance(other, _BaseConferenceSolution): | |
| return NotImplemented | |
| elif self is other: | |
| return True | |
| else: | |
| return ( | |
| self.conference_id == other.conference_id | |
| and self.signature == other.signature | |
| and self.notes == other.notes | |
| ) | |
| class EntryPoint: | |
| """Information about individual conference entry points, such as URLs or phone numbers.""" | |
| VIDEO = 'video' | |
| PHONE = 'phone' | |
| SIP = 'sip' | |
| MORE = 'more' | |
| ENTRY_POINT_TYPES = (VIDEO, PHONE, SIP, MORE) | |
| def __init__( | |
| self, | |
| entry_point_type: str, | |
| uri: str = None, | |
| label: str = None, | |
| pin: str = None, | |
| access_code: str = None, | |
| meeting_code: str = None, | |
| passcode: str = None, | |
| password: str = None | |
| ): | |
| """ | |
| When creating new conference data, populate only the subset of `meeting_code`, `access_code`, `passcode`, | |
| `password`, and `pin` fields that match the terminology that the conference provider uses. | |
| Only the populated fields should be displayed. | |
| :param entry_point_type: | |
| The type of the conference entry point. | |
| Possible values are: | |
| * VIDEO - joining a conference over HTTP. | |
| A conference can have zero or one `VIDEO` entry point. | |
| * PHONE - joining a conference by dialing a phone number. | |
| A conference can have zero or more `PHONE` entry points. | |
| * SIP - joining a conference over SIP. | |
| A conference can have zero or one `SIP` entry point. | |
| * MORE - further conference joining instructions, for example additional phone numbers. | |
| A conference can have zero or one `MORE` entry point. | |
| A conference with only a `MORE` entry point is not a valid conference. | |
| :param uri: | |
| The URI of the entry point. The maximum length is 1300 characters. | |
| Format: | |
| * for `VIDEO`, http: or https: schema is required. | |
| * for `PHONE`, tel: schema is required. | |
| The URI should include the entire dial sequence (e.g., tel:+12345678900,,,123456789;1234). | |
| * for `SIP`, sip: schema is required, e.g., sip:12345678@myprovider.com. | |
| * for `MORE`, http: or https: schema is required. | |
| :param label: | |
| The label for the URI. | |
| Visible to end users. Not localized. The maximum length is 512 characters. | |
| Examples: | |
| * for `VIDEO`: meet.google.com/aaa-bbbb-ccc | |
| * for `PHONE`: +1 123 268 2601 | |
| * for `SIP`: 12345678@altostrat.com | |
| * for `MORE`: should not be filled | |
| :param pin: | |
| The PIN to access the conference. The maximum length is 128 characters. | |
| :param access_code: | |
| The access code to access the conference. The maximum length is 128 characters. Optional. | |
| :param meeting_code: | |
| The meeting code to access the conference. The maximum length is 128 characters. | |
| :param passcode: | |
| The passcode to access the conference. The maximum length is 128 characters. | |
| :param password: | |
| The password to access the conference. The maximum length is 128 characters. | |
| """ | |
| if entry_point_type and entry_point_type not in self.ENTRY_POINT_TYPES: | |
| raise ValueError('"entry_point" must be one of {}. {} was provided.'.format( | |
| ', '.join(self.ENTRY_POINT_TYPES), | |
| entry_point_type | |
| )) | |
| if label and len(label) > 512: | |
| raise ValueError('Maximum label length is 512 characters.') | |
| if pin and len(pin) > 128: | |
| raise ValueError('Maximum pin length is 128 characters.') | |
| if access_code and len(access_code) > 128: | |
| raise ValueError('Maximum access_code length is 128 characters.') | |
| if meeting_code and len(meeting_code) > 128: | |
| raise ValueError('Maximum meeting_code length is 128 characters.') | |
| if passcode and len(passcode) > 128: | |
| raise ValueError('Maximum passcode length is 128 characters.') | |
| if password and len(password) > 128: | |
| raise ValueError('Maximum password length is 128 characters.') | |
| self.entry_point_type = entry_point_type | |
| self.uri = uri | |
| self.label = label | |
| self.pin = pin | |
| self.access_code = access_code | |
| self.meeting_code = meeting_code | |
| self.passcode = passcode | |
| self.password = password | |
| def __eq__(self, other): | |
| if not isinstance(other, EntryPoint): | |
| return NotImplemented | |
| elif self is other: | |
| return True | |
| else: | |
| return ( | |
| self.entry_point_type == other.entry_point_type | |
| and self.uri == other.uri | |
| and self.label == other.label | |
| and self.pin == other.pin | |
| and self.access_code == other.access_code | |
| and self.meeting_code == other.meeting_code | |
| and self.passcode == other.passcode | |
| and self.password == other.password | |
| ) | |
| def __str__(self): | |
| return "{} - '{}'".format(self.entry_point_type, self.uri) | |
| def __repr__(self): | |
| return '<EntryPoint {}>'.format(self.__str__()) | |
| class ConferenceSolution(_BaseConferenceSolution): | |
| """Information about the conference solution, such as Hangouts or Google Meet.""" | |
| def __init__( | |
| self, | |
| entry_points: Union[EntryPoint, List[EntryPoint]], | |
| solution_type: str = None, | |
| name: str = None, | |
| icon_uri: str = None, | |
| conference_id: str = None, | |
| signature: str = None, | |
| notes: str = None | |
| ): | |
| """ | |
| :param entry_points: | |
| :py:class:`~gcsa.conference.EntryPoint` or list of :py:class:`~gcsa.conference.EntryPoint` s. | |
| Information about individual conference entry points, such as URLs or phone numbers. | |
| All of them must belong to the same conference. | |
| :param solution_type: | |
| Solution type. See :py:class:`~gcsa.conference.SolutionType` | |
| The possible values are: | |
| * HANGOUT - for Hangouts for consumers (hangouts.google.com) | |
| * NAMED_HANGOUT - for classic Hangouts for Google Workspace users (hangouts.google.com) | |
| * HANGOUTS_MEET - for Google Meet (meet.google.com) | |
| * ADD_ON - for 3P conference providers | |
| :param name: | |
| The user-visible name of this solution. Not localized. | |
| :param icon_uri: | |
| The user-visible icon for this solution. | |
| :param conference_id: | |
| The ID of the conference. Optional. | |
| Can be used by developers to keep track of conferences, should not be displayed to users. | |
| Values for solution types (see :py:class:`~gcsa.conference.SolutionType`): | |
| * HANGOUT: unset | |
| * NAMED_HANGOUT: the name of the Hangout | |
| * HANGOUTS_MEET: the 10-letter meeting code, for example "aaa-bbbb-ccc" | |
| * ADD_ON: defined by 3P conference provider | |
| :param signature: | |
| The signature of the conference data. | |
| Generated on server side. Must be preserved while copying the conference data between events, | |
| otherwise the conference data will not be copied. | |
| None for a conference with a failed create request. | |
| Optional for a conference with a pending create request. | |
| :param notes: | |
| String of additional notes (such as instructions from the domain administrator, legal notices) | |
| to display to the user. Can contain HTML. The maximum length is 2048 characters | |
| """ | |
| super().__init__(conference_id=conference_id, signature=signature, notes=notes) | |
| self.entry_points = [entry_points] if isinstance(entry_points, EntryPoint) else entry_points | |
| self._check_entry_points() | |
| self.solution_type = solution_type | |
| self.name = name | |
| self.icon_uri = icon_uri | |
| def _check_entry_points(self): | |
| """ | |
| Checks counts of entry points types. | |
| * A conference can have zero or one `VIDEO` entry point. | |
| * A conference can have zero or more `PHONE` entry points. | |
| * A conference can have zero or one `SIP` entry point. | |
| * A conference can have zero or one `MORE` entry point. | |
| A conference with only a `MORE` entry point is not a valid conference. | |
| """ | |
| if len(self.entry_points) == 0: | |
| raise ValueError('At least one entry point has to be provided.') | |
| video_count = 0 | |
| sip_count = 0 | |
| more_count = 0 | |
| for ep in self.entry_points: | |
| if ep.entry_point_type == EntryPoint.VIDEO: | |
| video_count += 1 | |
| elif ep.entry_point_type == EntryPoint.SIP: | |
| sip_count += 1 | |
| elif ep.entry_point_type == EntryPoint.MORE: | |
| more_count += 1 | |
| if video_count > 1: | |
| raise ValueError('A conference can have zero or one `VIDEO` entry point.') | |
| if sip_count > 1: | |
| raise ValueError('A conference can have zero or one `SIP` entry point.') | |
| if more_count > 1: | |
| raise ValueError('A conference can have zero or one `MORE` entry point.') | |
| if more_count == len(self.entry_points): | |
| raise ValueError('A conference with only a `MORE` entry point is not a valid conference.') | |
| def __eq__(self, other): | |
| if not isinstance(other, ConferenceSolution): | |
| return NotImplemented | |
| elif self is other: | |
| return True | |
| else: | |
| return ( | |
| super().__eq__(other) | |
| and self.entry_points == other.entry_points | |
| and self.solution_type == other.solution_type | |
| and self.name == other.name | |
| and self.icon_uri == other.icon_uri | |
| ) | |
| def __str__(self): | |
| return '{} - {}'.format(self.solution_type, self.entry_points) | |
| def __repr__(self): | |
| return '<ConferenceSolution {}>'.format(self.__str__()) | |
| class ConferenceSolutionCreateRequest(_BaseConferenceSolution): | |
| """ | |
| A request to generate a new conference and attach it to the event. | |
| The data is generated asynchronously. To see whether the data is present check the status field. | |
| """ | |
| def __init__( | |
| self, | |
| solution_type: str = None, | |
| request_id: str = None, | |
| _status: str = None, | |
| conference_id: str = None, | |
| signature: str = None, | |
| notes: str = None | |
| ): | |
| """ | |
| :param solution_type: | |
| Solution type. See :py:class:`~gcsa.conference.SolutionType` | |
| The possible values are: | |
| * HANGOUT - for Hangouts for consumers (hangouts.google.com) | |
| * NAMED_HANGOUT - for classic Hangouts for Google Workspace users (hangouts.google.com) | |
| * HANGOUTS_MEET - for Google Meet (meet.google.com) | |
| * ADD_ON - for 3P conference providers | |
| :param request_id: | |
| The client-generated unique ID for this request. | |
| By default it is generated as UUID. | |
| If you specify request_id manually, they should be unique for every new CreateRequest, | |
| otherwise request will be ignored. | |
| :param _status: | |
| The current status of the conference create request. Should not be set by developer. | |
| The possible values are: | |
| * "pending": the conference create request is still being processed. | |
| * "failure": the conference create request failed, there are no entry points. | |
| * "success": the conference create request succeeded, the entry points are populated. | |
| In this case `ConferenceSolution` with created entry points | |
| is stored in the event's `conference_data`. And `ConferenceSolutionCreateRequest` is omitted. | |
| :param conference_id: | |
| The ID of the conference. Optional. | |
| Can be used by developers to keep track of conferences, should not be displayed to users. | |
| Values for solution types (see :py:class:`~gcsa.conference.SolutionType`): | |
| * HANGOUT: unset | |
| * NAMED_HANGOUT: the name of the Hangout | |
| * HANGOUTS_MEET: the 10-letter meeting code, for example "aaa-bbbb-ccc" | |
| * ADD_ON: defined by 3P conference provider | |
| :param signature: | |
| The signature of the conference data. | |
| Generated on server side. Must be preserved while copying the conference data between events, | |
| otherwise the conference data will not be copied. | |
| None for a conference with a failed create request. | |
| Optional for a conference with a pending create request. | |
| :param notes: | |
| String of additional notes (such as instructions from the domain administrator, legal notices) | |
| to display to the user. Can contain HTML. The maximum length is 2048 characters | |
| """ | |
| super().__init__(conference_id=conference_id, signature=signature, notes=notes, _status=_status) | |
| self.request_id = request_id or uuid4().hex | |
| self.solution_type = solution_type | |
| def __eq__(self, other): | |
| if not isinstance(other, ConferenceSolutionCreateRequest): | |
| return NotImplemented | |
| elif self is other: | |
| return True | |
| else: | |
| return ( | |
| super().__eq__(other) | |
| and self.request_id == other.request_id | |
| and self.solution_type == other.solution_type | |
| and self.status == other.status | |
| ) | |
| def __str__(self): | |
| return "{} - status:'{}'".format(self.solution_type, self.status) | |
| def __repr__(self): | |
| return '<ConferenceSolutionCreateRequest {}>'.format(self.__str__()) | |