|
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:[email protected].
|
|
* 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`: [email protected]
|
|
* 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__())
|
|
|