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_permissions
permission, except as stated below:You can grant the
manage_own_team
permission 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:
ServerError
indicates a server-side issue that it may be beyond the client’s capability to resolve.DataError
indicates 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. Theissues
attribute gives more detail, which can also be seen in the string representation of the error.ClientError
indicates a client-side issue not covered byDataError
. Thedetail
attribute gives more information, in a human-readable format.