mirror of
https://github.com/yawaflua/Flask-Discord.git
synced 2025-12-09 20:09:30 +02:00
Merge pull request #2 from thec0sm0s/quart
Use Async-OAuthlib rather than requests_oautlib which is not asynchronous library.
This commit is contained in:
57
CONTRIBUTING.rst
Normal file
57
CONTRIBUTING.rst
Normal file
@@ -0,0 +1,57 @@
|
||||
Contributing to Flask-Discord
|
||||
=============================
|
||||
|
||||
First of all, really thanks for considering this project and making contributions to improve it.
|
||||
|
||||
Any kind of improvements, feature additions, bug fixes, issues report or whatever which helps the library grow are welcomed. Just make sure that your part helps the library and its users in any way.
|
||||
|
||||
Basic Questions
|
||||
---------------
|
||||
|
||||
If you're having any issue with the library itself, please do check if similar issue already exists in the `Flask Discord Issues`_ section. If you can't find any issue which helps you, then feel free to create a new one; check `Reporting New Issues`_ or just ask about it in ``#flask-discord`` channel of our `Discord community`_.
|
||||
|
||||
.. _Flask Discord Issues: https://github.com/thec0sm0s/Flask-Discord/issues
|
||||
.. _Discord community: https://discord.gg/7CrQEyP
|
||||
.. _PEP 8: https://www.python.org/dev/peps/pep-0008/
|
||||
|
||||
Reporting New Issues
|
||||
--------------------
|
||||
|
||||
Feel free to drop a new issue whenever you feel anything could be potentially be wrong with the library or if you're just stuck somewhere.
|
||||
|
||||
Make sure to include following information with your post.
|
||||
|
||||
- The expected workflow you were trying to achieve.
|
||||
- If possible, include few steps to reproduce the situation.
|
||||
- What actually happened or the full traceback.
|
||||
|
||||
Submitting Patches
|
||||
------------------
|
||||
|
||||
You may optionally join our `Discord community`_ if you want to discuss in depth about the implementations before actually making the pull request. Ignore this if its obvious bug fix PR.
|
||||
|
||||
Minimal Style Guide
|
||||
*******************
|
||||
|
||||
You may or may not find it much relevant but I prefer few conventions and code style, some of which are list below.
|
||||
|
||||
- Make use of present tense for your commit messages. For example, use "Fix state mismatch error" rather than "Fixed state mismatch error".
|
||||
- Please do follow the Python `PEP 8`_ style guide.
|
||||
- You may or may not include docstrings. Although it's required but can also be added later on after making the PR.
|
||||
- Prefer prefixing the commit messages with emojis. Check the `Emoji Usage Reference`_ for info on which emoji to use.
|
||||
- Explicitly mention and inherit ``object`` when writing classes. For example, prefer ``class Foo(object): ...`` over ``class Foo: ...``.
|
||||
- Prefer relative imports over absolute imports.
|
||||
|
||||
Emoji Usage Reference
|
||||
*********************
|
||||
|
||||
Commits message looks nice on Github when they're prefixed with emojis. Prefer using any of the following emojis in your commit messages related to the following context.
|
||||
|
||||
- 🎨 ``:art:`` when improving the format/structure of the code.
|
||||
- 🐎 ``:racehorse:`` when improving performance.
|
||||
- 📝 ``:memo:`` when writing docs.
|
||||
- 🐛 ``:bug:`` when fixing a bug.
|
||||
- 💛 ``:yellow_heart:`` when adding a new feature.
|
||||
- 🔒 ``:lock:`` when dealing with security.
|
||||
- 👕 ``:shirt:`` when removing linter warnings.
|
||||
- ✔ ``:heavy_check_mark:`` For anything else.
|
||||
@@ -30,7 +30,7 @@ discord = DiscordOAuth2Session(app)
|
||||
|
||||
@app.route("/login/")
|
||||
async def login():
|
||||
return discord.create_session()
|
||||
return await discord.create_session()
|
||||
|
||||
|
||||
@app.route("/callback/")
|
||||
@@ -47,7 +47,7 @@ async def redirect_unauthorized(e):
|
||||
@app.route("/me/")
|
||||
@requires_authorization
|
||||
async def me():
|
||||
user = discord.fetch_user()
|
||||
user = await discord.fetch_user()
|
||||
return f"""
|
||||
<html>
|
||||
<head>
|
||||
@@ -68,7 +68,7 @@ For an example to the working application, check [`test_app.py`](tests/test_app.
|
||||
|
||||
### Requirements
|
||||
* Quart
|
||||
* requests_oauthlib
|
||||
* Async-OAuthlib
|
||||
* cachetools
|
||||
* discord.py
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ intersphinx_mapping = {
|
||||
'discord': ('https://discordpy.readthedocs.io/en/latest/', None),
|
||||
'quart': ('https://pgjones.gitlab.io/quart/', None),
|
||||
'cachetools': ('https://cachetools.readthedocs.io/en/stable/', None),
|
||||
'requests_oauthlib': ('https://requests-oauthlib.readthedocs.io/en/latest/', None)
|
||||
'async_oauthlib': ('https://async-oauthlib.readthedocs.io/en/latest/', None)
|
||||
}
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
||||
@@ -13,6 +13,7 @@ Discord's OAuth2 API easier.
|
||||
|
||||
**Features**
|
||||
|
||||
- Asynchronous wrapper.
|
||||
- Clean object-oriented design.
|
||||
- Covers most of the scopes provided by the API.
|
||||
- Supports various discord models and objects.
|
||||
|
||||
@@ -17,8 +17,8 @@ Requirements
|
||||
- **Quart**
|
||||
This is a Quart extension.
|
||||
|
||||
- **requests_oauthlib**
|
||||
It also requires requests_oauthlib to make OAuth2 sessions with discord.
|
||||
- **Async-OAuthlib**
|
||||
It also requires async_oauthlib to make OAuth2 sessions with discord.
|
||||
|
||||
- **cachetools**
|
||||
Quart Discord supports caching discord objects to boost the performance when page loads.
|
||||
@@ -37,7 +37,7 @@ in shell or command prompt: ::
|
||||
You can also install the latest development version (**maybe unstable/broken**) by
|
||||
using following command: ::
|
||||
|
||||
python3 -m pip install -U git+https://github.com/jnawk/Quart-Discord.git@dev
|
||||
python3 -m pip install -U git+https://github.com/jnawk/Quart-Discord.git
|
||||
|
||||
|
||||
Basic Usage
|
||||
@@ -65,25 +65,25 @@ in exchange for fetching user's details and display them on web page.
|
||||
|
||||
|
||||
@app.route("/login/")
|
||||
def login():
|
||||
return discord.create_session()
|
||||
async def login():
|
||||
return await discord.create_session()
|
||||
|
||||
|
||||
@app.route("/callback/")
|
||||
def callback():
|
||||
discord.callback()
|
||||
async def callback():
|
||||
await discord.callback()
|
||||
return redirect(url_for(".me"))
|
||||
|
||||
|
||||
@app.errorhandler(Unauthorized)
|
||||
def redirect_unauthorized(e):
|
||||
async def redirect_unauthorized(e):
|
||||
return redirect(url_for("login"))
|
||||
|
||||
|
||||
@app.route("/me/")
|
||||
@requires_authorization
|
||||
def me():
|
||||
user = discord.fetch_user()
|
||||
async def me():
|
||||
user = await discord.fetch_user()
|
||||
return f"""
|
||||
<html>
|
||||
<head>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import cachetools
|
||||
import requests
|
||||
import aiohttp
|
||||
import typing
|
||||
import json
|
||||
import os
|
||||
import abc
|
||||
|
||||
@@ -10,7 +9,7 @@ from . import exceptions
|
||||
|
||||
from quart import session, request
|
||||
from collections.abc import Mapping
|
||||
from requests_oauthlib import OAuth2Session
|
||||
from async_oauthlib import OAuth2Session
|
||||
|
||||
|
||||
class DiscordOAuth2HttpClient(abc.ABC):
|
||||
@@ -56,23 +55,23 @@ class DiscordOAuth2HttpClient(abc.ABC):
|
||||
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
def save_authorization_token(token: dict):
|
||||
async def save_authorization_token(token: dict):
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
def get_authorization_token() -> dict:
|
||||
async def get_authorization_token() -> dict:
|
||||
raise NotImplementedError
|
||||
|
||||
def _fetch_token(self, state):
|
||||
discord = self._make_session(state=state)
|
||||
return discord.fetch_token(
|
||||
async def _fetch_token(self, state):
|
||||
discord = await self._make_session(state=state)
|
||||
return await discord.fetch_token(
|
||||
configs.DISCORD_TOKEN_URL,
|
||||
client_secret=self.__client_secret,
|
||||
authorization_response=request.url
|
||||
)
|
||||
|
||||
def _make_session(self, token: str = None, state: str = None, scope: list = None) -> OAuth2Session:
|
||||
async def _make_session(self, token: str = None, state: str = None, scope: list = None) -> OAuth2Session:
|
||||
"""A low level method used for creating OAuth2 session.
|
||||
|
||||
Parameters
|
||||
@@ -93,7 +92,7 @@ class DiscordOAuth2HttpClient(abc.ABC):
|
||||
"""
|
||||
return OAuth2Session(
|
||||
client_id=self.client_id,
|
||||
token=token or self.get_authorization_token(),
|
||||
token=token or await self.get_authorization_token(),
|
||||
state=state or session.get("DISCORD_OAUTH2_STATE"),
|
||||
scope=scope,
|
||||
redirect_uri=self.redirect_uri,
|
||||
@@ -104,7 +103,7 @@ class DiscordOAuth2HttpClient(abc.ABC):
|
||||
auto_refresh_url=configs.DISCORD_TOKEN_URL,
|
||||
token_updater=self.save_authorization_token)
|
||||
|
||||
def request(self, route: str, method="GET", data=None, oauth=True, **kwargs) -> typing.Union[dict, str]:
|
||||
async def request(self, route: str, method="GET", data=None, oauth=True, **kwargs) -> typing.Union[dict, str]:
|
||||
"""Sends HTTP request to provided route or discord endpoint.
|
||||
|
||||
Note
|
||||
@@ -137,20 +136,22 @@ class DiscordOAuth2HttpClient(abc.ABC):
|
||||
|
||||
"""
|
||||
route = configs.DISCORD_API_BASE_URL + route
|
||||
response = self._make_session(
|
||||
).request(method, route, data, **kwargs) if oauth else requests.request(method, route, data=data, **kwargs)
|
||||
discord = await self._make_session()
|
||||
async with (await discord.request(
|
||||
method, route, data, **kwargs
|
||||
) if oauth else aiohttp.request(method, route, data=data, **kwargs)) as response:
|
||||
|
||||
if response.status_code == 401:
|
||||
raise exceptions.Unauthorized
|
||||
if response.status_code == 429:
|
||||
raise exceptions.RateLimited(response)
|
||||
if response.status == 401:
|
||||
raise exceptions.Unauthorized
|
||||
if response.status == 429:
|
||||
raise exceptions.RateLimited(response)
|
||||
|
||||
try:
|
||||
return response.json()
|
||||
except json.JSONDecodeError:
|
||||
return response.text
|
||||
try:
|
||||
return await response.json()
|
||||
except aiohttp.ContentTypeError:
|
||||
return await response.text()
|
||||
|
||||
def bot_request(self, route: str, method="GET", **kwargs) -> typing.Union[dict, str]:
|
||||
async def bot_request(self, route: str, method="GET", **kwargs) -> typing.Union[dict, str]:
|
||||
"""Make HTTP request to specified endpoint with bot token as authorization headers.
|
||||
|
||||
Parameters
|
||||
@@ -175,4 +176,4 @@ class DiscordOAuth2HttpClient(abc.ABC):
|
||||
|
||||
"""
|
||||
headers = {"Authorization": f"Bot {self.__bot_token}"}
|
||||
return self.request(route, method=method, oauth=False, headers=headers, **kwargs)
|
||||
return await self.request(route, method=method, oauth=False, headers=headers, **kwargs)
|
||||
|
||||
@@ -57,7 +57,7 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||
def __get_state():
|
||||
return session.pop("DISCORD_OAUTH2_STATE", str())
|
||||
|
||||
def create_session(
|
||||
async def create_session(
|
||||
self, scope: list = None, *, data: dict = None, prompt: bool = True,
|
||||
permissions: typing.Union[discord.Permissions, int] = 0, **params
|
||||
):
|
||||
@@ -95,7 +95,7 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||
|
||||
state = jwt.encode(data or dict(), current_app.config["SECRET_KEY"]).decode(encoding="utf-8")
|
||||
|
||||
discord_session = self._make_session(scope=scope, state=state)
|
||||
discord_session = await self._make_session(scope=scope, state=state)
|
||||
authorization_url, state = discord_session.authorization_url(configs.DISCORD_AUTHORIZATION_BASE_URL)
|
||||
|
||||
self.__save_state(state)
|
||||
@@ -117,7 +117,7 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||
return redirect(authorization_url)
|
||||
|
||||
@staticmethod
|
||||
def save_authorization_token(token: dict):
|
||||
async def save_authorization_token(token: dict):
|
||||
"""A staticmethod which saves a dict containing Discord OAuth2 token and other secrets to the user's cookies.
|
||||
Meaning by default, it uses client side session handling.
|
||||
|
||||
@@ -128,7 +128,7 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||
session["DISCORD_OAUTH2_TOKEN"] = token
|
||||
|
||||
@staticmethod
|
||||
def get_authorization_token() -> dict:
|
||||
async def get_authorization_token() -> dict:
|
||||
"""A static method which returns a dict containing Discord OAuth2 token and other secrets which was saved
|
||||
previously by `:py:meth:`quart_discord.DiscordOAuth2Session.save_authorization_token` from user's cookies.
|
||||
|
||||
@@ -151,8 +151,8 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||
raise exceptions.HttpException(error)
|
||||
|
||||
state = self.__get_state()
|
||||
token = self._fetch_token(state)
|
||||
self.save_authorization_token(token)
|
||||
token = await self._fetch_token(state)
|
||||
await self.save_authorization_token(token)
|
||||
|
||||
return jwt.decode(state, current_app.config["SECRET_KEY"])
|
||||
|
||||
@@ -172,13 +172,12 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
@property
|
||||
def authorized(self):
|
||||
async def authorized(self):
|
||||
"""A boolean indicating whether current session has authorization token or not."""
|
||||
return self._make_session().authorized
|
||||
return (await self._make_session()).authorized
|
||||
|
||||
@staticmethod
|
||||
def fetch_user() -> models.User:
|
||||
async def fetch_user() -> models.User:
|
||||
"""This method returns user object from the internal cache if it exists otherwise makes an API call to do so.
|
||||
|
||||
Returns
|
||||
@@ -186,10 +185,10 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||
quart_discord.models.User
|
||||
|
||||
"""
|
||||
return models.User.get_from_cache() or models.User.fetch_from_api()
|
||||
return models.User.get_from_cache() or await models.User.fetch_from_api()
|
||||
|
||||
@staticmethod
|
||||
def fetch_connections() -> list:
|
||||
async def fetch_connections() -> list:
|
||||
"""This method returns list of user connection objects from internal cache if it exists otherwise
|
||||
makes an API call to do so.
|
||||
|
||||
@@ -206,10 +205,10 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return models.UserConnection.fetch_from_api()
|
||||
return await models.UserConnection.fetch_from_api()
|
||||
|
||||
@staticmethod
|
||||
def fetch_guilds() -> list:
|
||||
async def fetch_guilds() -> list:
|
||||
"""This method returns list of guild objects from internal cache if it exists otherwise makes an API
|
||||
call to do so.
|
||||
|
||||
@@ -226,4 +225,4 @@ class DiscordOAuth2Session(_http.DiscordOAuth2HttpClient):
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return models.Guild.fetch_from_api()
|
||||
return await models.Guild.fetch_from_api()
|
||||
|
||||
@@ -12,7 +12,7 @@ class RateLimited(HttpException):
|
||||
|
||||
Attributes
|
||||
----------
|
||||
response : requests.Response
|
||||
response : aiohttp.Response
|
||||
The actual response object received from Discord API.
|
||||
json : dict
|
||||
The actual JSON data received. Shorthand to ``response.json()``.
|
||||
|
||||
@@ -22,20 +22,20 @@ class DiscordModelsBase(metaclass=DiscordModelsMeta):
|
||||
self._payload = payload
|
||||
|
||||
@staticmethod
|
||||
def _request(*args, **kwargs):
|
||||
async def _request(*args, **kwargs):
|
||||
"""A shorthand to :py:func:quart_discord.request`. It uses Quart current_app local proxy to get the
|
||||
Quart-Discord client.
|
||||
|
||||
"""
|
||||
return current_app.discord.request(*args, **kwargs)
|
||||
return await current_app.discord.request(*args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def _bot_request(*args, **kwargs):
|
||||
async def _bot_request(*args, **kwargs):
|
||||
"""A shorthand to :py:func:quart_discord.bot_request`."""
|
||||
return current_app.discord.bot_request(*args, **kwargs)
|
||||
return await current_app.discord.bot_request(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def fetch_from_api(cls):
|
||||
async def fetch_from_api(cls):
|
||||
"""A class method which returns an instance or list of instances of this model by implicitly making an
|
||||
API call to Discord.
|
||||
|
||||
@@ -48,7 +48,7 @@ class DiscordModelsBase(metaclass=DiscordModelsMeta):
|
||||
|
||||
"""
|
||||
request_method = cls._bot_request if cls.BOT else cls._request
|
||||
payload = request_method(cls.ROUTE)
|
||||
payload = await request_method(cls.ROUTE)
|
||||
if cls.MANY:
|
||||
return [cls(_) for _ in payload]
|
||||
return cls(payload)
|
||||
|
||||
@@ -57,7 +57,7 @@ class UserConnection(DiscordModelsBase):
|
||||
return bool(self.visibility)
|
||||
|
||||
@classmethod
|
||||
def fetch_from_api(cls, cache=True):
|
||||
async def fetch_from_api(cls, cache=True):
|
||||
"""A class method which returns an instance or list of instances of this model by implicitly making an
|
||||
API call to Discord. If an instance of :py:class:`quart_discord.User` exists in the users internal cache
|
||||
who are attached to these connections then, the cached property :py:attr:`quart_discord.User.connections`
|
||||
@@ -74,7 +74,7 @@ class UserConnection(DiscordModelsBase):
|
||||
List of instances of :py:class:`quart_discord.UserConnection` to which this user belongs.
|
||||
|
||||
"""
|
||||
connections = super().fetch_from_api()
|
||||
connections = await super().fetch_from_api()
|
||||
|
||||
if cache:
|
||||
user = current_app.discord.users_cache.get(current_app.discord.user_id)
|
||||
|
||||
@@ -66,7 +66,7 @@ class Guild(DiscordModelsBase):
|
||||
return configs.DISCORD_GUILD_ICON_BASE_URL.format(guild_id=self.id, icon_hash=self.icon_hash)
|
||||
|
||||
@classmethod
|
||||
def fetch_from_api(cls, cache=True):
|
||||
async def fetch_from_api(cls, cache=True):
|
||||
"""A class method which returns an instance or list of instances of this model by implicitly making an
|
||||
API call to Discord. If an instance of :py:class:`quart_discord.User` exists in the users internal cache
|
||||
who belongs to these guilds then, the cached property :py:attr:`quart_discord.User.guilds` is updated.
|
||||
@@ -82,7 +82,7 @@ class Guild(DiscordModelsBase):
|
||||
List of instances of :py:class:`quart_discord.Guild` to which this user belongs.
|
||||
|
||||
"""
|
||||
guilds = super().fetch_from_api()
|
||||
guilds = await super().fetch_from_api()
|
||||
|
||||
if cache:
|
||||
user = current_app.discord.users_cache.get(current_app.discord.user_id)
|
||||
|
||||
@@ -125,7 +125,7 @@ class User(DiscordModelsBase):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def fetch_from_api(cls, guilds=False, connections=False):
|
||||
async def fetch_from_api(cls, guilds=False, connections=False):
|
||||
"""A class method which returns an instance of this model by implicitly making an
|
||||
API call to Discord. The user returned from API will always be cached and update in internal cache.
|
||||
|
||||
@@ -144,14 +144,14 @@ class User(DiscordModelsBase):
|
||||
An instance of this model itself.
|
||||
[cls, ...]
|
||||
List of instances of this model when many of these models exist."""
|
||||
self = super().fetch_from_api()
|
||||
self = await super().fetch_from_api()
|
||||
current_app.discord.users_cache.update({self.id: self})
|
||||
session["DISCORD_USER_ID"] = self.id
|
||||
|
||||
if guilds:
|
||||
self.fetch_guilds()
|
||||
await self.fetch_guilds()
|
||||
if connections:
|
||||
self.fetch_connections()
|
||||
await self.fetch_connections()
|
||||
|
||||
return self
|
||||
|
||||
@@ -169,7 +169,7 @@ class User(DiscordModelsBase):
|
||||
"""
|
||||
return current_app.discord.users_cache.get(current_app.discord.user_id)
|
||||
|
||||
def add_to_guild(self, guild_id) -> dict:
|
||||
async def add_to_guild(self, guild_id) -> dict:
|
||||
"""Method to add user to the guild, provided OAuth2 session has already been created with ``guilds.join`` scope.
|
||||
|
||||
Parameters
|
||||
@@ -189,12 +189,12 @@ class User(DiscordModelsBase):
|
||||
|
||||
"""
|
||||
try:
|
||||
data = {"access_token": current_app.discord.get_authorization_token()["access_token"]}
|
||||
data = {"access_token": (await current_app.discord.get_authorization_token())["access_token"]}
|
||||
except KeyError:
|
||||
raise exceptions.Unauthorized
|
||||
return self._bot_request(f"/guilds/{guild_id}/members/{self.id}", method="PUT", json=data) or dict()
|
||||
return await self._bot_request(f"/guilds/{guild_id}/members/{self.id}", method="PUT", json=data) or dict()
|
||||
|
||||
def fetch_guilds(self) -> list:
|
||||
async def fetch_guilds(self) -> list:
|
||||
"""A method which makes an API call to Discord to get user's guilds. It prepares the internal guilds cache
|
||||
and returns list of all guilds the user is member of.
|
||||
|
||||
@@ -204,10 +204,10 @@ class User(DiscordModelsBase):
|
||||
List of :py:class:`quart_discord.Guilds` instances.
|
||||
|
||||
"""
|
||||
self._guilds = {guild.id: guild for guild in Guild.fetch_from_api(cache=False)}
|
||||
self._guilds = {guild.id: guild for guild in await Guild.fetch_from_api(cache=False)}
|
||||
return self.guilds
|
||||
|
||||
def fetch_connections(self) -> list:
|
||||
async def fetch_connections(self) -> list:
|
||||
"""A method which makes an API call to Discord to get user's connections. It prepares the internal connection
|
||||
cache and returns list of all connection instances.
|
||||
|
||||
@@ -217,7 +217,7 @@ class User(DiscordModelsBase):
|
||||
A list of :py:class:`quart_discord.UserConnection` instances.
|
||||
|
||||
"""
|
||||
self.connections = UserConnection.fetch_from_api(cache=False)
|
||||
self.connections = await UserConnection.fetch_from_api(cache=False)
|
||||
return self.connections
|
||||
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ def requires_authorization(view):
|
||||
|
||||
@functools.wraps(view)
|
||||
async def wrapper(*args, **kwargs):
|
||||
if not current_app.discord.authorized:
|
||||
if not await current_app.discord.authorized():
|
||||
raise exceptions.Unauthorized
|
||||
return await view(*args, **kwargs)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Quart
|
||||
pyjwt
|
||||
requests
|
||||
aiohttp
|
||||
oauthlib
|
||||
discord.py
|
||||
cachetools
|
||||
setuptools
|
||||
requests_oauthlib
|
||||
Async-OAuthlib
|
||||
|
||||
3
setup.py
3
setup.py
@@ -20,9 +20,8 @@ requirements = [
|
||||
'Quart',
|
||||
'pyjwt',
|
||||
'oauthlib',
|
||||
'requests_oauthlib',
|
||||
'Async-OAuthlib',
|
||||
'cachetools',
|
||||
'requests',
|
||||
'discord.py',
|
||||
]
|
||||
|
||||
|
||||
20
tests/__init__.py
Normal file
20
tests/__init__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import os
|
||||
|
||||
from quart import Quart
|
||||
from quart_discord import DiscordOAuth2Session
|
||||
|
||||
|
||||
def get_app():
|
||||
app = Quart(__name__)
|
||||
|
||||
app.secret_key = b"%\xe0'\x01\xdeH\x8e\x85m|\xb3\xffCN\xc9g"
|
||||
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "true" # !! Only in development environment.
|
||||
|
||||
# app.config["DISCORD_CLIENT_ID"] = 490732332240863233
|
||||
app.config["DISCORD_CLIENT_SECRET"] = os.getenv("DISCORD_CLIENT_SECRET")
|
||||
app.config["DISCORD_BOT_TOKEN"] = os.getenv("DISCORD_BOT_TOKEN")
|
||||
app.config["DISCORD_REDIRECT_URI"] = "http://127.0.0.1:5000/callback"
|
||||
|
||||
app.discord = DiscordOAuth2Session(app, client_id=490732332240863233)
|
||||
|
||||
return app
|
||||
@@ -7,6 +7,7 @@ from quart_discord import DiscordOAuth2Session, requires_authorization
|
||||
app = Quart(__name__)
|
||||
|
||||
app.secret_key = b"%\xe0'\x01\xdeH\x8e\x85m|\xb3\xffCN\xc9g"
|
||||
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "true" # !! Only in development environment.
|
||||
|
||||
app.config["DISCORD_CLIENT_ID"] = 490732332240863233
|
||||
app.config["DISCORD_CLIENT_SECRET"] = os.getenv("DISCORD_CLIENT_SECRET")
|
||||
@@ -21,7 +22,7 @@ HYPERLINK = '<a href="{}">{}</a>'
|
||||
|
||||
@app.route("/")
|
||||
async def index():
|
||||
if not discord.authorized:
|
||||
if not await discord.authorized():
|
||||
return f"""
|
||||
{HYPERLINK.format(url_for(".login"), "Login")} <br />
|
||||
{HYPERLINK.format(url_for(".login_with_data"), "Login with custom data")} <br />
|
||||
@@ -39,22 +40,24 @@ async def index():
|
||||
|
||||
@app.route("/login/")
|
||||
async def login():
|
||||
return discord.create_session()
|
||||
return await discord.create_session()
|
||||
|
||||
|
||||
@app.route("/login-data/")
|
||||
async def login_with_data():
|
||||
return discord.create_session(data=dict(redirect="/me/", coupon="15off", number=15, zero=0, status=False))
|
||||
return await discord.create_session(data=dict(redirect="/me/", coupon="15off", number=15, zero=0, status=False))
|
||||
|
||||
|
||||
@app.route("/invite-bot/")
|
||||
async def invite_bot():
|
||||
return discord.create_session(scope=["bot"], permissions=8, guild_id=464488012328468480, disable_guild_select=True)
|
||||
return await discord.create_session(
|
||||
scope=["bot"], permissions=8, guild_id=464488012328468480, disable_guild_select=True
|
||||
)
|
||||
|
||||
|
||||
@app.route("/invite-oauth/")
|
||||
async def invite_oauth():
|
||||
return discord.create_session(scope=["bot", "identify"], permissions=8)
|
||||
return await discord.create_session(scope=["bot", "identify"], permissions=8)
|
||||
|
||||
|
||||
@app.route("/callback/")
|
||||
@@ -66,7 +69,7 @@ async def callback():
|
||||
|
||||
@app.route("/me/")
|
||||
async def me():
|
||||
user = discord.fetch_user()
|
||||
user = await discord.fetch_user()
|
||||
return f"""
|
||||
<html>
|
||||
<head>
|
||||
@@ -84,20 +87,20 @@ async def me():
|
||||
|
||||
@app.route("/me/guilds/")
|
||||
async def user_guilds():
|
||||
guilds = discord.fetch_guilds()
|
||||
guilds = await discord.fetch_guilds()
|
||||
return "<br />".join([f"[ADMIN] {g.name}" if g.permissions.administrator else g.name for g in guilds])
|
||||
|
||||
|
||||
@app.route("/add_to/<int:guild_id>/")
|
||||
async def add_to_guild(guild_id):
|
||||
user = discord.fetch_user()
|
||||
return user.add_to_guild(guild_id)
|
||||
user = await discord.fetch_user()
|
||||
return await user.add_to_guild(guild_id)
|
||||
|
||||
|
||||
@app.route("/me/connections/")
|
||||
async def my_connections():
|
||||
user = discord.fetch_user()
|
||||
connections = discord.fetch_connections()
|
||||
user = await discord.fetch_user()
|
||||
connections = await discord.fetch_connections()
|
||||
return f"""
|
||||
<html>
|
||||
<head>
|
||||
|
||||
Reference in New Issue
Block a user