Refactoring
This commit is contained in:
parent
2907553f8e
commit
8769d063d4
10 changed files with 18 additions and 206 deletions
|
@ -1,66 +0,0 @@
|
|||
"""
|
||||
Configuration:
|
||||
Options:
|
||||
token - Discord access token
|
||||
"""
|
||||
|
||||
from requests.models import Response
|
||||
from pronoun_update import PronounUpdate
|
||||
from typing import Any, Dict
|
||||
from plugin import InvalidPluginDefinitionException, Plugin
|
||||
import requests
|
||||
|
||||
|
||||
class DiscordApiException(Exception):
|
||||
def __init__(self, error: str) -> None:
|
||||
super().__init__(f"Discord api returned an error: {error}")
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class DiscordApiClient:
|
||||
host: str
|
||||
s = requests.Session()
|
||||
|
||||
def __init__(self, token: str):
|
||||
self.s.headers.update({"Authorization": token})
|
||||
|
||||
def verify_credentials(self) -> Response:
|
||||
user_data = self.s.get("https://discord.com/api/v9/users/@me")
|
||||
if not user_data.ok:
|
||||
raise DiscordApiException(user_data.json()["message"])
|
||||
print(user_data.json())
|
||||
return user_data
|
||||
|
||||
def updated_data(self, updated_data: Dict[str, Any]) -> Response:
|
||||
resp = self.s.patch(
|
||||
"https://discord.com/api/v9/users/@me", json=updated_data,
|
||||
)
|
||||
if not resp.ok:
|
||||
raise DiscordApiException(resp.json()["message"])
|
||||
return resp
|
||||
|
||||
|
||||
class DiscordPlugin(Plugin):
|
||||
s = requests.Session()
|
||||
api_client:DiscordApiClient
|
||||
|
||||
@classmethod
|
||||
def name(cls) -> str:
|
||||
return "discord"
|
||||
|
||||
def _load_from_config(self, config: dict[str, Any]) -> None:
|
||||
access_token = config.get("token", None)
|
||||
if not isinstance(access_token, str):
|
||||
raise InvalidPluginDefinitionException(
|
||||
f"Access token needs to be set to a string with an access token, got {type(access_token)}"
|
||||
)
|
||||
self.api_client = DiscordApiClient(access_token)
|
||||
|
||||
self.api_client.verify_credentials()
|
||||
|
||||
def update_bio(self, update_pronouns: PronounUpdate) -> None:
|
||||
current_bio = self.api_client.verify_credentials().json()["bio"]
|
||||
bio = update_pronouns.replace_pronouns_in_bio(current_bio)
|
||||
# TODO: discord seems to be getting a pronoun field, maybe use that
|
||||
self.api_client.updated_data({"bio": bio})
|
|
@ -1,121 +0,0 @@
|
|||
"""
|
||||
Configuration:
|
||||
Options:
|
||||
host - the url of a mastodon api compatible server(for example: https://mastodon.example/)
|
||||
token - Access token obtained by authenticating the user. Needs to have access to at least the read:accounts and write:accounts
|
||||
|
||||
In order to obtain an access token you can either copy it from for example a browser cookie set by logging in with another client(not recommended, but simpler and easier) or registering an app and asking a client for authorization
|
||||
|
||||
First register an application by doing
|
||||
```
|
||||
curl -X POST \
|
||||
-F 'client_name=Pronoun-o-matic' \
|
||||
-F 'redirect_uris=urn:ietf:wg:oauth:2.0:oob' \
|
||||
-F 'scopes=read:accounts write:accounts' \
|
||||
https://mastodon.example/api/v1/apps
|
||||
```
|
||||
That should return a json object with a client_id and a client_secret values.
|
||||
|
||||
Open an url in your browser:
|
||||
```
|
||||
https://mastodon.example/oauth/authorize
|
||||
?client_id=CLIENT_ID
|
||||
&scope=read:accounts+write:accounts
|
||||
&redirect_uri=urn:ietf:wg:oauth:2.0:oob
|
||||
&response_type=code
|
||||
```
|
||||
|
||||
You should recieve a client secret which you can use get the access token. Simply place them in a curl command like:
|
||||
```
|
||||
curl -X POST \
|
||||
-F 'client_id=your_client_id_here' \
|
||||
-F 'client_secret=your_client_secret_here' \
|
||||
-F 'redirect_uri=urn:ietf:wg:oauth:2.0:oob' \
|
||||
-F 'grant_type=client_credentials' \
|
||||
https://mastodon.example/oauth/token
|
||||
```
|
||||
"""
|
||||
|
||||
from requests.models import Response
|
||||
from pronoun_update import PronounUpdate
|
||||
from typing import Any, Dict
|
||||
from plugin import InvalidPluginDefinitionException, Plugin
|
||||
import requests
|
||||
|
||||
|
||||
class MastodonApiException(Exception):
|
||||
def __init__(self, error: str) -> None:
|
||||
super().__init__(f"Mastodon api returned an error: {error}")
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class MastodonApiClient:
|
||||
host: str
|
||||
s = requests.Session()
|
||||
|
||||
def __init__(self, host: str, token: str):
|
||||
self.host = host
|
||||
self.s.headers.update({"Authorization": f"Bearer {token}"})
|
||||
|
||||
def verify_credentials(self) -> Response:
|
||||
creds = self.s.get(f"{self.host}/api/v1/accounts/verify_credentials")
|
||||
if not creds.ok:
|
||||
error = creds.json().get("error", "the server didn't return an error")
|
||||
raise MastodonApiException(error)
|
||||
return creds
|
||||
|
||||
def update_credentials(self, updated_credentials: Dict[str, Any]) -> Response:
|
||||
creds = self.s.patch(
|
||||
f"{self.host}/api/v1/accounts/update_credentials", data=updated_credentials
|
||||
)
|
||||
if not creds.ok:
|
||||
error = creds.json().get("error", "the server didn't return an error")
|
||||
raise InvalidPluginDefinitionException(
|
||||
f"Provided token is invalid. {error}"
|
||||
)
|
||||
return creds
|
||||
|
||||
|
||||
class MastodonPlugin(Plugin):
|
||||
s = requests.Session()
|
||||
api_client: MastodonApiClient
|
||||
|
||||
@classmethod
|
||||
def name(cls) -> str:
|
||||
return "mastodon"
|
||||
|
||||
def _load_from_config(self, config: dict[str, Any]) -> None:
|
||||
host = config.get("host", None)
|
||||
if not isinstance(host, str):
|
||||
raise InvalidPluginDefinitionException(
|
||||
f"Host needs to be set to a string with the url to the mastodon compatible server, got {type(host)}"
|
||||
)
|
||||
self.host = host
|
||||
|
||||
access_token = config.get("token", None)
|
||||
if not isinstance(access_token, str):
|
||||
raise InvalidPluginDefinitionException(
|
||||
f"Access token needs to be set to a string with an access token, got {type(host)}"
|
||||
)
|
||||
self.access_token = access_token
|
||||
|
||||
self.api_client = MastodonApiClient(host, access_token)
|
||||
|
||||
# Verify the credentials
|
||||
self.api_client.verify_credentials()
|
||||
|
||||
def update_bio(self, update_pronouns: PronounUpdate) -> None:
|
||||
credentials = self.api_client.verify_credentials().json()["source"]
|
||||
new_credentials = {}
|
||||
new_credentials["note"] = update_pronouns.replace_pronouns_in_bio(
|
||||
credentials["note"]
|
||||
)
|
||||
|
||||
for idx, field in enumerate(credentials["fields"]):
|
||||
name = update_pronouns.replace_pronouns_in_bio(field["name"])
|
||||
value = update_pronouns.replace_pronouns_in_bio(field["value"])
|
||||
new_credentials[f"fields_attributes[{idx}][name]"] = name
|
||||
new_credentials[f"fields_attributes[{idx}][value]"] = value
|
||||
|
||||
self.api_client.update_credentials(new_credentials)
|
13
setup.py
13
setup.py
|
@ -6,15 +6,14 @@ setup(
|
|||
name="pronoun-o-matic",
|
||||
version="1.0",
|
||||
# Modules to import from other scripts:
|
||||
packages=find_packages() + ["."],
|
||||
package_dir={"": "./"},
|
||||
packages=find_packages() + ["pronounomatic.core", "pronounomatic.plugins"],
|
||||
package_dir={"pronounomatic": "src"},
|
||||
entry_points={
|
||||
"console_scripts": ["pronounomatic=pronounomatic.core.app:main"],
|
||||
"pronounomatic.plugins": [
|
||||
"log = plugins.log_plugin:LogPlugin",
|
||||
"mastodon = plugins.mastodon:MastodonPlugin",
|
||||
"discord = plugins.discord:DiscordPlugin",
|
||||
"log = pronounomatic.plugins.log_plugin:LogPlugin",
|
||||
# "mastodon = pronounomatic.plugins.mastodon:MastodonPlugin",
|
||||
# "discord = pronounomatic.plugins.discord:DiscordPlugin",
|
||||
],
|
||||
},
|
||||
# Executables
|
||||
scripts=["app.py"],
|
||||
)
|
||||
|
|
0
src/core/__init__.py
Normal file
0
src/core/__init__.py
Normal file
|
@ -1,17 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
if __name__ == "__main__":
|
||||
import logging
|
||||
import logging
|
||||
logging.getLogger().setLevel("INFO")
|
||||
|
||||
logging.getLogger().setLevel("INFO")
|
||||
|
||||
from plugin import Plugin, load_plugins_for_config
|
||||
from typing import Tuple
|
||||
from flask import Flask, request
|
||||
from pronoun_update import PronounUpdate
|
||||
from .plugin import Plugin, load_plugins_for_config
|
||||
from .pronoun_update import PronounUpdate
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_envvar("PRONOUNOMATIC_SETTINGS")
|
||||
#app.config.from_envvar("PRONOUNOMATIC_SETTINGS")
|
||||
|
||||
plugins = load_plugins_for_config(app.config.get("PLUGINS", [{"name": "log"}]))
|
||||
|
||||
|
@ -30,6 +28,9 @@ def update_pronouns() -> Tuple[str, int]:
|
|||
trigger_update_pronouns(pronouns)
|
||||
return pronouns, 200
|
||||
|
||||
def main():
|
||||
app.run(host="0.0.0.0", port=8080)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8080)
|
||||
main()
|
||||
|
|
@ -4,7 +4,7 @@ from importlib.metadata import entry_points
|
|||
import logging
|
||||
from typing import Any, Callable, List
|
||||
|
||||
from pronoun_update import PronounUpdate
|
||||
from .pronoun_update import PronounUpdate
|
||||
|
||||
|
||||
class Plugin:
|
||||
|
@ -33,7 +33,6 @@ def load_plugins() -> dict[str, type[Plugin]]:
|
|||
# See: https://github.com/python/typeshed/pull/7331
|
||||
for plugin in entry_points(group="pronounomatic.plugins"): # type: ignore
|
||||
pl = plugin.load() # type: ignore
|
||||
assert issubclass(pl, Plugin)
|
||||
plugins[pl.name()] = pl
|
||||
|
||||
return plugins
|
0
src/plugins/__init__.py
Normal file
0
src/plugins/__init__.py
Normal file
|
@ -1,7 +1,7 @@
|
|||
import logging
|
||||
from pronoun_update import PronounUpdate
|
||||
from typing import Any
|
||||
from plugin import Plugin
|
||||
from ..core.pronoun_update import PronounUpdate
|
||||
from ..core.plugin import Plugin
|
||||
|
||||
|
||||
class LogPlugin(Plugin):
|
Loading…
Reference in a new issue