Участники
`members.list`, `list_all`, `iterate`, `get`, `add`, `update`, `remove`, `grant_address`, `revoke_address` и методы приглашений рядом с ними.
Все методы
from openemail import openemail roles = openemail.roles.list_all()support = next(role for role in roles if role['name'] == 'Support')viewer = next(role for role in roles if role['builtin'] == 'viewer') invitation = openemail.members.add({ 'email': '[email protected]', 'roleId': support['id'], 'addressIds': ['2b81de07-…'], 'access': 'member',}) people = openemail.members.list_all()sam = next(person for person in people if person['email'] == '[email protected]')member = openemail.members.get(sam['userId']) openemail.members.update(sam['userId'], {'roleId': viewer['id']}) openemail.members.grant_address(sam['userId'], { 'addressId': 'c40a95f2-…', 'access': 'viewer',})openemail.members.revoke_address(sam['userId'], 'c40a95f2-…') openemail.members.remove(sam['userId'])На человека приходится два разрешения, и сливать их нельзя. role означает, что ему можно делать, а addresses означает, с чем именно. Оба должны совпадать: роль с emails:send и 'access': 'viewer' на invoices@ описывает человека, который может отправлять почту и не может отправлять её с этого адреса. Исключение составляет роль с addresses:all: она охватывает все адреса, что бы ни было перечислено в addresses, ведь этот массив содержит только прямые выдачи, поэтому проверьте permissions, прежде чем читать его как весь доступ человека.
Все методы принимают userId, а не адрес. Единственное исключение составляет add, потому что он приглашает адрес: userId у человека появляется только после того, как он примет приглашение, а до тех пор приглашение отслеживает list_invitations.
'implied': True означает, что роль никто не выбирал. У человека есть адреса и нет строки роли, поэтому роль выведена из самого широкого имеющегося разрешения. Считайте это «ещё не решено»; превращает вывод в решение update. До тех пор расширение его доступа к адресам молча расширяет и то, что ему можно делать.
Владелец рабочего пространства занимает первую строку, помеченную 'isOwner': True, при этом add, update и remove всё равно отказывают по нему с member_is_owner. Рабочее пространство, которым ни с кем не поделились, сообщает об одном участнике, а не о нуле, поэтому при подсчёте мест исключайте isOwner.
remove забирает обе оси (и роль, И все выдачи адресов в этом рабочем пространстве) и сообщает addressesRevoked. revoke_address является узким вариантом, для того, кто сменил команду, а не ушёл.
Параметры
emailstrобязательно- Кого пригласить (с обрезкой пробелов и приведением к нижнему регистру). Аккаунт пока не нужен: приглашение уходит кому угодно, а роль и выдачи применяются, когда человек его примет. Тот, кто уже в рабочем пространстве, даёт `member_is_owner` (422).
roleIdstrобязательно- Роль, которую он получит, от 1 до 128 символов, и это должна быть роль этого рабочего пространства: неизвестный идентификатор даёт `role_not_found` (404). Роль владельца выдать нельзя, она возвращает `role_immutable` (409), потому что сделать кого-то владельцем означает передать рабочее пространство, а такого вызова здесь нет.
addressIdslist[str]- Адреса, которые несёт приглашение: не более 64 идентификаторов длиной от 1 до 128 символов каждый; они выдаются, когда приглашение принято. Каждый идентификатор проверяется до какой-либо записи, поэтому один идентификатор, не являющийся адресом этого рабочего пространства, приводит к отказу всего вызова с 422 `member_not_found`, и ничего не отправляется. Повторное приглашение того же адреса в течение десяти минут даёт 409 `invitation_too_soon`.
accessLiteral['member', 'viewer']- Что ему можно делать с каждым идентификатором из `addressIds`: `member` читает адрес и отправляет от его имени, `viewer` только читает. По умолчанию `member` (уровень, который всегда использовали консоль и прежний механизм общего доступа), поэтому один и тот же вызов означает одно и то же из скрипта и с экрана; чтобы выдать разные уровни, вызовите затем `grant_address` для тех, что отличаются.
Ответ
objectLiteral['member']- Всегда `member`. Удаление отвечает тем же значением, его `userId`, `'deleted': True` и `addressesRevoked`, но ни одним из остальных полей ниже.
userIdstr- Идентификатор его аккаунта и тот ключ, который все прочие вызовы участников принимают в пути: get, update, remove и оба вызова по адресам. Добавление является единственным вызовом, работающим вместо этого по адресу, потому что тот, кто добавляет коллегу, знает его адрес, а не идентификатор.
emailstr- Адрес на его аккаунте, возвращаемый в том виде, в каком его хранит та строка. Этот ресурс его никогда не записывает, а приведение к нижнему регистру в `add` касается адреса, который вы отправляете для поиска, а не того, что приходит обратно. После владельца список участников отсортирован по нему, а не по дате присоединения, потому что список читают, чтобы найти конкретного человека, а не чтобы увидеть, что изменилось.
namestr | None- Его отображаемое имя, взятое из аккаунта, где колонка объявлена NOT NULL. `None` в типе является подстраховкой, а не состоянием, которое этот API когда-либо выдавал. Имя принадлежит человеку, а не рабочему пространству, поэтому ничто в этом ресурсе не может его задать.
imagestr | None- Его аватар, взятый из аккаунта; null, если он его не задал.
role.idstr | None- Идентификатор роли, которой он обладает, или null, если её никто не выбирал. См. `implied`. Null здесь является единственным случаем, когда `role` сообщает вывод, а не чьё-то решение.
role.namestr- Имя роли. У подразумеваемого участника это имя встроенного шаблона, к которому свёлся его доступ, а не строки в этом рабочем пространстве.
role.builtinLiteral['owner', 'admin', 'member', 'viewer', 'developer', 'billing'] | None- Какой встроенной роли соответствует эта роль, или null для пользовательской. `owner` встречается только в строке самого владельца, рядом с `'isOwner': True`; назначение этой роли кому-либо отклоняется с `role_immutable` (409).
isOwnerbool- True ровно в одной строке: у аккаунта, на который завязано рабочее пространство. Он обладает всеми правами, что бы ни говорила его строка роли, сортируется первым, а `add`, `update` и `remove` отказывают по нему с `member_is_owner`. При подсчёте мест его исключайте.
impliedbool- True, когда у человека есть выдачи адресов и нет строки участника, то есть роль была выведена, а не выбрана: любая выдача `member` сводится к встроенной роли Member, иначе к Viewer. Для владельца никогда не true. Показывайте это как «подразумевается доступом». Пока PATCH не превратит вывод в решение, расширение его доступа к адресам молча расширяет и то, что ему можно делать.
permissionslist[Permission]- Права роли, развёрнутые прямо на участнике, чтобы одно чтение отвечало на вопрос «можно ли ему?» без запроса роли. У подразумеваемого участника они берутся из встроенного ШАБЛОНА, а не из строки роли этого рабочего пространства, поэтому правка встроенной роли Member не меняет того, чем обладает подразумеваемый участник.
addresseslist[MemberAddressResource]- Выданные ему адреса, отсортированные по адресу, каждый со своим уровнем доступа. Пусто у того, у кого есть роль и нет выдач. Именно так выглядит новый участник, пока ему не выдан адрес, и это правильный вид отказа, пока вы ещё решаете, что ему следует видеть.
addresses[].addressIdstr- Идентификатор адреса; именно его принимают `grant_address` и `revoke_address`. Идентификатор, не являющийся адресом этого рабочего пространства, отклоняется в обоих вызовах, вместо того чтобы сообщить об отзыве, которого не было.
addresses[].addressstr- Полный адрес в нижнем регистре, собранный заново из локальной части и домена.
addresses[].accessLiteral['member', 'viewer']- Что ему можно делать с этим конкретным адресом: `member` читает его и отправляет от его имени, `viewer` только читает. Отправка происходит, лишь когда её разрешают и это поле, и роль, поэтому роль с `emails:send` поверх выдачи `viewer` не отправляет ни с одного адреса; в хранилище колонка называется `role`, и здесь она переименована, чтобы один объект не нёс два `role` из двух разных словарей.
createdAtstr | None- Когда была создана его строка участника, ISO-8601; null, когда строки участника нет вовсе. Этот null описывает ту же группу, что и `'implied': True`: людей, у которых адреса остались с времён до появления ролей и которым с тех пор никто роль не назначил.
Приглашения
from openemail import openemail waiting = openemail.members.list_all_invitations() for invitation in waiting: if invitation['expired']: openemail.members.resend_invitation(invitation['id']) openemail.members.revoke_invitation('winv_6bb640f5b99e47deb758f1f5')add отвечает приглашением, и вот вызовы, которые идут за ним: list_invitations, list_all_invitations и iterate_invitations читают те, что ещё никто не принял, resend_invitation отправляет приглашение повторно с новой ссылкой и ещё четырнадцатью днями, а revoke_invitation отзывает его. Ожидающее приглашение ничего не даёт, пока его не примут.
resend_invitation отклоняет тот же адрес во второй раз за десять минут с 409 invitation_too_soon, а revoke_invitation отклоняет уже принятое приглашение с 409 invitation_accepted.
Коды подтверждения
add, update, remove, grant_address и revoke_address спрашивают у токена доступа OAuth код подтверждения, прежде чем что-либо менять, а resend_invitation и revoke_invitation не спрашивают. Вызов выбрасывает OpenEmailApiError, у которого is_step_up_required равен True: запросите код через security.begin_step_up(), проверьте тот, что даст вам человек, через security.verify_step_up({'code': ...}), затем сделайте вызов снова. Одно подтверждение действует 60 минут, а у API-ключа код никогда не спрашивают.
Справочник
members.list()Полный справочникmembers.list_all()Полный справочникmembers.iterate()Полный справочникmembers.get()Полный справочникmembers.add()Полный справочникmembers.update()Полный справочникmembers.remove()Полный справочникmembers.grant_address()Полный справочникmembers.revoke_address()Полный справочникmembers.list_invitations()Полный справочникmembers.list_all_invitations()Полный справочникmembers.iterate_invitations()Полный справочникmembers.resend_invitation()Полный справочникmembers.revoke_invitation()Полный справочник