mobilizon-python/mobilizon.py

305 wiersze
8.9 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# use `pip install gql tenacity`
from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport
from gql.transport.exceptions import TransportQueryError
from requests.exceptions import HTTPError
from tenacity import *
# this class has been integrated in Tenacity after 7.0.0 release
# see https://github.com/jd/tenacity/blame/c18dcfbf4b6a719f668f12fdb4999afaeef62648/tenacity/retry.py#L86
class retry_if_not_exception_type(retry_if_exception):
"""Retries except an exception has been raised of one or more types."""
def __init__(self, exception_types=Exception):
self.exception_types = exception_types
super(retry_if_not_exception_type, self).__init__(
lambda e: not isinstance(e, exception_types))
class BadRequest(Exception):
pass
# ==== GQL : Events ====
CREATE_GQL = gql("""
mutation createEvent($organizerActorId: ID!, $attributedToId: ID, $title: String!, $description: String!, $beginsOn: DateTime!, $endsOn: DateTime, $status: EventStatus, $visibility: EventVisibility, $joinOptions: EventJoinOptions, $draft: Boolean, $tags: [String], $picture: MediaInput, $onlineAddress: String, $phoneAddress: String, $category: String, $physicalAddress: AddressInput, $options: EventOptionsInput, $contacts: [Contact]) {
createEvent(organizerActorId: $organizerActorId, attributedToId: $attributedToId, title: $title, description: $description, beginsOn: $beginsOn, endsOn: $endsOn, status: $status, visibility: $visibility, joinOptions: $joinOptions, draft: $draft, tags: $tags, picture: $picture, onlineAddress: $onlineAddress, phoneAddress: $phoneAddress, category: $category, physicalAddress: $physicalAddress, options: $options, contacts: $contacts) {
id
uuid
}
}
""")
UPDATE_GQL = gql("""
mutation updateEvent($id: ID!, $title: String, $description: String, $beginsOn: DateTime, $endsOn: DateTime, $status: EventStatus, $visibility: EventVisibility, $joinOptions: EventJoinOptions, $draft: Boolean, $tags: [String], $picture: PictureInput, $onlineAddress: String, $phoneAddress: String, $organizerActorId: ID, $attributedToId: ID, $category: String, $physicalAddress: AddressInput, $options: EventOptionsInput, $contacts: [Contact]) {
updateEvent(eventId: $id, title: $title, description: $description, beginsOn: $beginsOn, endsOn: $endsOn, status: $status, visibility: $visibility, joinOptions: $joinOptions, draft: $draft, tags: $tags, picture: $picture, onlineAddress: $onlineAddress, phoneAddress: $phoneAddress, organizerActorId: $organizerActorId, attributedToId: $attributedToId, category: $category, physicalAddress: $physicalAddress, options: $options, contacts: $contacts) {
id
uuid
}
}
""")
CANCEL_GQL = gql("""
mutation updateEvent($eventId: ID!) {
updateEvent(eventId: $eventId, status: CANCELLED) {
id
uuid
}
}
""")
CONFIRM_GQL = gql("""
mutation updateEvent($eventId: ID!) {
updateEvent(eventId: $eventId, status: CONFIRMED) {
id
uuid
}
}
""")
DELETE_GQL = gql("""
mutation DeleteEvent($eventId: ID!) {
deleteEvent(eventId: $eventId) {
id
}
}
""")
# ==== /GQL : Events ====
# ==== GQL : Actors ====
CREATE_USER_GQL = gql("""
mutation createUser($email: String!, $locale: String="fr", $password: String!) {
createUser(email: $email, locale: $locale, password: $password) {
id
}
}""")
CREATE_GROUP_GQL = gql("""
mutation createGroup($name: String, $preferredUsername: String!, $summary: String = "") {
createGroup(name: $name, preferredUsername: $preferredUsername, summary: $summary) {
id
}
}""")
CREATE_PERSON_GQL = gql("""
mutation createPerson($name: String, $preferredUsername: String!, $summary: String = "") {
createPerson(name: $name, preferredUsername: $preferredUsername, summary: $summary) {
id url
}
}""")
CREATE_MEMBER_GQL = gql("""
mutation inviteMember($groupId: ID!, $targetActorUsername: String!) {
inviteMember(groupId: $groupId, targetActorUsername: $targetActorUsername) {
id role
}
}""")
UPDATE_MEMBER_GQL = gql("""
mutation updateMemberRole($memberId: ID!, $role:MemberRoleEnum!) {
updateMember(memberId: $memberId, role: $role) {
id role
}
}""")
# ==== /GQL : Users ====
# ==== GQL : credentials ====
LOGIN_GQL = gql("""
mutation login($email: String!, $password: String!) {
login(email: $email, password: $password) {
accessToken refreshToken
}
}""")
REFRESH_TOKEN_GQL = gql("""
mutation RefreshToken($rt:String!) {
refreshToken(refreshToken: $rt) {
accessToken refreshToken
}
}""")
LOGOUT_GQL = gql("""
mutation logout($rt: String!) {
logout(refreshToken: $rt)
}""")
# ==== /GQL : credentials ====
# ==== GQL : identities - actors - persons and groups ====
PROFILES_GQL = gql("""
query Identities { identities { ...ActorFragment } }
fragment ActorFragment on Actor { id type preferredUsername name url}
""")
GROUPS_GQL = gql("""
query LoggedUserMemberships($membershipName: String, $page: Int, $limit: Int) {
loggedUser {
memberships(name: $membershipName, page: $page, limit: $limit) {
elements {
role
actor { ...ActorFragment }
parent { ...ActorFragment }
}
}
}
}
fragment ActorFragment on Actor { id type preferredUsername name }
""")
class Mobilizon():
__slots__ = 'client'
def __init__(self, endpoint, bearer=None):
self.client = self._build_client(endpoint, bearer)
# events
def create_event(self, actor_id, variables):
variables["organizerActorId"] = actor_id
return self._publish(CREATE_GQL, variables)
def update_event(self, actor_id, variables):
variables["organizerActorId"] = actor_id
return self._publish(UPDATE_GQL, variables)
def confirm_event(self, event_id):
variables = dict()
variables["eventId"] = event_id
return self._publish(CONFIRM_GQL, variables)
def cancel_event(self, event_id):
variables = dict()
variables["eventId"] = event_id
return self._publish(CANCEL_GQL, variables)
def delete_event(self, actor_id, event_id):
variables = { "actorId": actor_id,
"eventId" : event_id }
return self._publish(DELETE_GQL, variables)
# actors
def create_user(self, email, password):
variables = dict()
variables["email"] = email
variables["password"] = password
return self._publish(CREATE_USER_GQL, variables)
def create_person(self, name, preferredUsername, summary = ""):
variables = dict()
variables["name"] = name
variables["preferredUsername"] = preferredUsername
variables["summary"] = summary
return self._publish(CREATE_PERSON_GQL, variables)['createPerson']
def create_group(self, name, preferredUsername, summary = ""):
variables = dict()
variables["name"] = name
variables["preferredUsername"] = preferredUsername
variables["summary"] = summary
return self._publish(CREATE_GROUP_GQL, variables)['createGroup']
def create_member(self, group_id, preferredUsername):
variables = dict()
variables["groupId"] = group_id
variables["targetActorUsername"] = preferredUsername
return self._publish(CREATE_MEMBER_GQL, variables)['inviteMember']
def update_member(self, memberId, role):
variables = dict()
variables["memberId"] = memberId
variables["role"] = role
return self._publish(UPDATE_MEMBER_GQL, variables)['updateMember']
# users / credentials
def login(self, email, password):
variables = dict()
variables["email"] = email
variables["password"] = password
data = self._publish(LOGIN_GQL, variables)
login = data['login']
return login['accessToken'], login['refreshToken']
def logout(self, rt):
variables = dict()
variables["rt"] = rt
return self._publish(LOGOUT_GQL, variables) # void
def refresh_token(self, refresh_token:str):
variables = dict()
variables = { 'rt':refresh_token }
return self._publish(REFRESH_TOKEN_GQL, variables)
def user_identities(self):
variables = dict()
data = self._publish(PROFILES_GQL, variables)
profiles = data['identities']
return profiles
def user_memberships(self):
variables = { "limit": 20 }
data = self._publish(GROUPS_GQL, variables)
memberships = data['loggedUser']['memberships']['elements']
return memberships
# interns
def _build_client(self, endpoint, bearer=None):
headers = dict()
if bearer is not None:
headers['Authorization']='Bearer '+bearer
transport = RequestsHTTPTransport(
url=endpoint,
headers=headers,
verify=True,
#retries=3,
)
return Client(transport=transport)
# attempts at 0s, 2s, 4s, 8s
@retry(reraise=True, retry=retry_if_not_exception_type(BadRequest), stop=stop_after_attempt(4), wait=wait_exponential(multiplier=2))
def _publish(self, mutation, variables):
try:
r = self.client.execute(mutation, variable_values=variables)
except HTTPError as e:
if e.response.status_code in [400,404]:
raise BadRequest(e)
else:
raise
except TransportQueryError as e:
raise BadRequest(e)
except:
raise
return r
if __name__ == "__main__":
import sys
endpoint = sys.argv[1]
bearer = sys.argv[2]
actor_id = sys.argv[3]
import json
event = json.load(sys.stdin)
r = Mobilizon(endpoint, bearer).create_event(actor_id, event)
print(json.dumps(r))