Intro to the Polympics API wrapper¶
Creating a client¶
The first thing you need to do to use the API is create an API client. There are 3 types of client:
Unauthenticated
App-authenticated
User-authenticated
Creating an unauthenticated client is very simple:
client = UnauthenticatedClient()
However, if you want to do anything other than read-only operations, you’ll need to authenticate. To use app credentials, see the following example:
credentials = Credentials('A3', 'YOUR-TOKEN-HERE')
client = AppClient(credentials)
Creating a user-authenticated client is very similar:
credentials = Credentials('S3', 'YOUR-TOKEN-HERE')
client = UserClient(credentials)
Note
All three clients take an additional parameter, base_url. This is
the location at which the API is hosted, for example
http://127.0.0.1:8000 or https://api.polytopia.fun.
Getting an account¶
You can get an account by Discord ID using get_account. For example:
account = await client.get_account(12345678901234)
print(account.name)
print(account.permissions)
print(account.team.name)
Getting a team¶
You can get a team by ID using get_team. For example:
team = await client.get_team(31)
print(team.name)
print(team.member_count)
Getting an award¶
You can get an award by ID using the get_award method. For example:
award = await client.get_award(42)
print(award.title, award.image_url)
for awardee in award.awardees:
# awardee is an Account object.
print(awardee.name)
Listing all accounts¶
You can list all accounts using list_accounts. For example:
async for account in client.list_accounts():
print(account.name)
You can also get results a page at a time:
accounts = client.list_accounts()
for account in await accounts.get_page(0):
print(account.name)
You can use the search and team parameters to narrow down results.
print(f'Members from team {team.name} with "bob" in their name:')
async for account in client.list_accounts('bob', team=team):
print(account.name)
Listing all teams¶
You can list all teams using list_teams. For example:
async for team in client.list_teams():
print(team.name)
This supports the same pagination system as list_accounts, as well
as the search parameter:
teams = client.list_teams(search='foo')
print([team.name for team in await teams.get_page(0)])
Checking if signups are open¶
Call check_signups on any client to check if signups are open:
if await client.check_signups():
print('Signups are open.')
else:
print('Signups are closed.)
New users will not be allowed to register when signups are closed.
Creating an account¶
Registering a user is a simple call to create_account:
team = await client.get_team(5)
account = await client.create_account(
id=1234567,
name='Artemis',
discriminator='8472',
avatar_url='https://picsum.photos/200',
team=team
)
assert account.name == 'Artemis'
assert account.team.id == 5
Note
This requires an AppClient or UserClient with the
manage_account_details permission.
You can also chose the permissions to grant the user:
account = await client.create_account(
id=1234567,
name='Artemis',
discriminator='8472',
team=team,
permissions=Permissions(
manage_teams=True, manage_account_details=True
)
)
Note
In order to grant permissions to a user:
You must be authenticated.
You cannot grant permissions you do not have.
You cannot grant
authenticate_users, since that’s not a permission users can have.You cannot grant permissions unless you have the
manage_permissionspermission, except as stated below:You can grant the
manage_own_teampermission to other members of your own team (as long as you also havemanage_own_team).
Editing an account¶
Editing a user’s account can be done with update_account:
account = await client.get_account(41129492792313)
account = await client.update_account(
account, name='Artemis', discriminator='1231'
)
assert account.name == 'Artemis'
Note
This requires an AppClient or UserClient with the
manage_account_details permission.
You can similarly update a user’s team:
account = await client.update_account(account, team=team)
Note
This requires an AppClient or UserClient with the
manage_account_teams permission, or a UserClient authenticated
with the given account.
Or you can remove a user from a team, using the NO_TEAM constant:
account = await client.update_account(account, team=polympics.NO_TEAM)
Note
This requires permissions as explained above for adding a user to a team,
with the addition that you can remove a user from a team if you are a member
of that team and have the manage_own_team permission.
You can also update user permissions with the grant_permissions
and revoke_permissions args, subject to the rules outlined in
“Creating an account”.
Example:
account = await client.update_account(
account, grant_permissions=Permissions(manage_own_team=True),
revoke_permissions=Permissions(manage_teams=True)
)
Using the discord_token parameter, you can update a user’s name,
discriminator and avatar URL to match Discord. This requires no permissions,
since user tokens can be authenticated with Discord.
Example:
account = await client.update_account(account, discord_token=token)
Deleting an account¶
You can delete a user’s account with the delete_account method:
account = await client.get_account(124214913289)
await client.delete_account(account)
Note
This requires an AppClient or UserClient with the
manage_account_details permission, or just a UserClient associated
with the given account.
Creating a team¶
You can create a team using the create_team method. It accepts one
parameter, name, for the team’s name:
team = await client.create_team('Gods of Olympus')
assert team.name == 'Gods of Olympus'
Note
This requires an AppClient or UserClient with the
manage_teams permission.
Editing a team¶
You can edit a team using the update_team method. It accepts the same
name parameter as create_team:
team = await client.get_team(13)
team = await client.update_team(team, name='Cool Kidz')
assert team.name == 'Cool Kidz'
Note
This requires an AppClient or UserClient with the
manage_teams permission, or just a UserClient
with the manage_own_team permission who is a member of the
given team.
Deleting a team¶
You can delete a team with the delete_team method. It accepts a single
argument, the team to delete:
team = await client.get_team(28)
await client.delete_team(team)
Note
This requires an AppClient or UserClient with the
manage_teams permission, or just a UserClient
with the manage_own_team permission who is a member of the
given team.
Creating an award¶
You can create an award with the create_award method:
account_1 = await client.get_account(508140149014901)
team = await client.get_team(123)
award = await client.create_award(
title='Perfect 10 Gold',
image_url='https://link.to/icon.png',
team=team,
accounts=[account_1]
)
print(award.id, award.title)
Note
This requires an AppClient or UserClient with the
manage_awards permission.
Editing an award¶
You can edit an award with the update_award method:
award = await client.get_award(12)
award = await client.update_award(award, title='Gold - Perfect 10')
Note
This requires an AppClient or UserClient with the
manage_awards permission.
Deleting an award¶
You can delete an award with the delete_award method:
award = await client.get_award(52)
await client.delete_award(award)
Note
This requires an AppClient or UserClient with the
manage_awards permission.
Giving an award to a user¶
You can give a user an existing award with the give_award method:
account = await client.get_account(130914109419411)
award = await client.get_award(19)
await client.give_award(award, account)
Note
This requires an AppClient or UserClient with the
manage_awards permission.
Taking an award from a user¶
You can take an award away from a user that has it with the take_award method:
account = await client.get_account(8713710931790741)
award = await client.get_award(13)
await client.take_award(award, account)
Note
This requires an AppClient or UserClient with the
manage_awards permission.
Registering a callback¶
You can register an HTTP callback for a specific event type (currently only account_team_update) using the create_callback method.
await client.create_callback(
event=EventType.account_team_update,
url='https://example.com/fake_callback',
secret='obviously-dont-use-this'
)
Note
This requires an AppClient. It will overwrite any existing callback for this event type.
Listing all callbacks¶
You can list all callbacks registered for your app using the get_callbacks method:
callbacks = await client.get_callbacks()
for event, cb_url in callbacks.items():
print(f'{cb_url} registered for {event.value}')
Note
This requires an AppClient.
Getting a specific callback¶
You can get information on a specific callback using the get_callback method:
callback = await client.get_callback(EventType.account_team_update)
print(callback.id)
print(callback.event.value)
print(callback.url)
Note
This requires an AppClient.
Deleting a callback¶
You can delete the callback for a specific event type using the delete_callback method:
await client.delete_callback(EventType.account_team_update)
Note
This requires an AppClient.
Handling a callback event¶
This library does not implement an HTTP server to listen for events, so you will have to implement that yourself. Once you recieve an event, you should make sure that the Authorization header is equal to Bearer <secret>, where <secret> is the secret you passed to create_callback.
Once you have recieved and validated an event, you can use a handler function to parse the data. The following handler functions are available:
account_team_update
Creating a user auth session¶
An AppClient can create user sessions, which can in turn be used by a
UserClient as authentication. More usefully, user session can be passed
to the frontend, so that the user they are for can manipulate the API
client-side.
Example:
account = await client.get_account(1318219824080)
session = await client.create_session(account)
print(session.expires_at)
user_client = UserClient(session)
Note
This requires an AppClient with the authenticate_users
permission.
Authenticating via Discord OAuth2¶
Alternatively, you can use a Discord user authentication token to create a user session (these can be obtained using Discord OAuth2, which is beyond the scope of this library). This has the advantage that you do not need to be otherwise authenticated, so it can be used on the frontend (eg. with the OAuth2 implicit grant flow).
Example:
session = await client.discord_authenticate(token)
user_client = UserClient(session)
Note that the token used must be authorised for the identify scope.
Resetting the client’s token¶
The token of an AppClient or UserClient can be reset using
reset_token. Note that the client will automatically update to use the
new token. This function returns an AppCredentials object for an
AppClient, or a Session object for a UserClient, either of which
can be used in place of credentials, and also provide some metadata.
await client.reset_token()
Note
This requires an AppClient or UserClient.
Getting the authenticated app¶
When authenticated with an AppClient, you can use get_self to get
metadata on the authenticated app. Note that unlike reset_token, this
does not return the app’s new token.
app = await client.get_self()
print(app.name)
Getting the authenticated user¶
A UserClient can get the account of the user it has authenticated as
using the same method:
account = await client.get_self()
print(account.name)
Closing the connection¶
Before exiting, your app should call the close method of any clients you
have opened:
await client.close()
Errors¶
If the API returns an error, the wrapper will raise a PolympicsError.
This has the code attribute (the HTTP status code that was used, eg.
404 or 500).
There are also the following subclasses:
ServerErrorindicates a server-side issue that it may be beyond the client’s capability to resolve.DataErrorindicates an issue in the parameters passed to the API. This could indicate an issue in the library, but it will also be raised when a resource is not found. Theissuesattribute gives more detail, which can also be seen in the string representation of the error.ClientErrorindicates a client-side issue not covered byDataError. Thedetailattribute gives more information, in a human-readable format.