Compare commits
No commits in common. "master" and "4.0.0" have entirely different histories.
@ -4,14 +4,14 @@ on: [push]
|
|||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: python:3.12.6
|
container: python:3.11
|
||||||
steps:
|
steps:
|
||||||
- run: apt-get update
|
- run: apt-get update
|
||||||
- run: apt-get install -y git nodejs
|
- run: apt-get install -y git nodejs
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: Gr1N/setup-poetry@v9
|
- uses: Gr1N/setup-poetry@v8
|
||||||
- run: poetry install
|
- run: poetry install
|
||||||
- run: poetry run ruff check .
|
- run: poetry run flake8 .
|
||||||
- run: poetry run mypy .
|
- run: poetry run mypy .
|
||||||
- run: poetry run djlint .
|
- run: poetry run djlint .
|
||||||
|
|
||||||
@ -35,22 +35,22 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- uses: docker/build-push-action@v6
|
- uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
push: ${{ gitea.ref_name == gitea.event.repository.default_branch || gitea.ref_type == 'tag' }}
|
push: ${{ gitea.ref == 'refs/heads/master' || startsWith(gitea.ref, 'refs/tags') }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
pypi:
|
pypi:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: python:3.12.6
|
container: python:3.11
|
||||||
needs: [lint]
|
needs: [lint]
|
||||||
if: gitea.ref_type == 'tag'
|
if: startsWith(gitea.ref, 'refs/tags')
|
||||||
env:
|
env:
|
||||||
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.POETRY_PYPI_TOKEN_PYPI }}
|
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.POETRY_PYPI_TOKEN_PYPI }}
|
||||||
steps:
|
steps:
|
||||||
- run: apt-get update
|
- run: apt-get update
|
||||||
- run: apt-get install -y git nodejs
|
- run: apt-get install -y git nodejs
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: Gr1N/setup-poetry@v9
|
- uses: Gr1N/setup-poetry@v8
|
||||||
- run: poetry publish --build
|
- run: poetry publish --build
|
||||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -107,10 +107,8 @@ ipython_config.py
|
|||||||
#pdm.lock
|
#pdm.lock
|
||||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
# in version control.
|
# in version control.
|
||||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
# https://pdm.fming.dev/#use-with-ide
|
||||||
.pdm.toml
|
.pdm.toml
|
||||||
.pdm-python
|
|
||||||
.pdm-build/
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
__pypackages__/
|
__pypackages__/
|
||||||
@ -160,4 +158,4 @@ cython_debug/
|
|||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
.idea/
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
FROM python:3.12.6 as build
|
FROM python:3.11.6 as build
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN pip install poetry && poetry build
|
RUN pip install poetry && poetry build
|
||||||
|
|
||||||
FROM python:3.12.6
|
FROM python:3.11.5
|
||||||
|
|
||||||
COPY --from=build /app/dist /tmp/dist
|
COPY --from=build /app/dist /tmp/dist
|
||||||
RUN pip install /tmp/dist/*.whl && rm -rf /tmp/dist
|
RUN pip install /tmp/dist/*.whl && rm -rf /tmp/dist
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
from divent.bot import run
|
|
||||||
|
|
||||||
run()
|
|
@ -3,17 +3,18 @@ import logging
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from os import getenv, path
|
from os import getenv, path
|
||||||
from typing import Dict, Optional, Union
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from disnake import Asset, Client, Guild, Intents, Member, User
|
from disnake import Asset, Client, Guild
|
||||||
from disnake.guild_scheduled_event import GuildScheduledEvent
|
from disnake.guild_scheduled_event import GuildScheduledEvent
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from hypercorn.middleware import ProxyFixMiddleware
|
|
||||||
from ics import Calendar, ContentLine, Event
|
from ics import Calendar, ContentLine, Event
|
||||||
from ics.alarm import DisplayAlarm
|
from ics.alarm import DisplayAlarm
|
||||||
from oauthlib.oauth2 import OAuth2Error
|
from oauthlib.oauth2 import OAuth2Error
|
||||||
from quart import Quart, redirect, render_template, request, session, url_for
|
from quart import Quart, redirect, render_template, request, session, url_for
|
||||||
from requests_oauthlib import OAuth2Session # type: ignore
|
from requests_oauthlib import OAuth2Session # type: ignore
|
||||||
|
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
|
||||||
|
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@ -35,51 +36,17 @@ API_BASE_URL = getenv("API_BASE_URL", "https://discordapp.com/api")
|
|||||||
AUTHORIZATION_BASE_URL = f"{API_BASE_URL}/oauth2/authorize"
|
AUTHORIZATION_BASE_URL = f"{API_BASE_URL}/oauth2/authorize"
|
||||||
TOKEN_URL = f"{API_BASE_URL}/oauth2/token"
|
TOKEN_URL = f"{API_BASE_URL}/oauth2/token"
|
||||||
|
|
||||||
CATALOG_CACHE = {}
|
|
||||||
EVENTS_CACHE = {}
|
|
||||||
|
|
||||||
|
|
||||||
class Discord(Client):
|
class Discord(Client):
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
print(f"Logged on as {self.user}!", flush=True)
|
print(f"Logged on as {self.user}!", flush=True)
|
||||||
|
|
||||||
for guild in self.guilds:
|
|
||||||
for scheduled_event in guild.scheduled_events:
|
|
||||||
EVENTS_CACHE[scheduled_event.id] = [
|
|
||||||
member.id
|
|
||||||
for member in await scheduled_event.fetch_users().flatten()
|
|
||||||
]
|
|
||||||
|
|
||||||
print("Events synchronised!", flush=True)
|
|
||||||
|
|
||||||
async def on_guild_scheduled_event_subscribe(
|
|
||||||
self, event: GuildScheduledEvent, user: Union[Member, User]
|
|
||||||
):
|
|
||||||
EVENTS_CACHE[event.id].append(user.id)
|
|
||||||
|
|
||||||
async def on_guild_scheduled_event_unsubscribe(
|
|
||||||
self, event: GuildScheduledEvent, user: Union[Member, User]
|
|
||||||
):
|
|
||||||
EVENTS_CACHE[event.id].remove(user.id)
|
|
||||||
|
|
||||||
async def on_guild_scheduled_event_create(self, event: GuildScheduledEvent):
|
|
||||||
EVENTS_CACHE[event.id] = [
|
|
||||||
member.id for member in await event.fetch_users().flatten()
|
|
||||||
]
|
|
||||||
|
|
||||||
async def on_guild_scheduled_event_delete(self, event: GuildScheduledEvent):
|
|
||||||
EVENTS_CACHE.pop(event.id)
|
|
||||||
|
|
||||||
|
|
||||||
intents = Intents.default()
|
|
||||||
intents.guild_scheduled_events = True
|
|
||||||
intents.members = True
|
|
||||||
client = Discord(intents=intents)
|
|
||||||
|
|
||||||
|
client = Discord()
|
||||||
app = Quart(__name__)
|
app = Quart(__name__)
|
||||||
app.config["SECRET_KEY"] = OAUTH2_CLIENT_SECRET
|
app.config["SECRET_KEY"] = OAUTH2_CLIENT_SECRET
|
||||||
app.config["EXPLAIN_TEMPLATE_LOADING"] = QUART_DEBUG
|
app.config["EXPLAIN_TEMPLATE_LOADING"] = QUART_DEBUG
|
||||||
app.asgi_app = ProxyFixMiddleware(app.asgi_app) # type: ignore
|
app.asgi_app = ProxyHeadersMiddleware(app.asgi_app, "*") # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def get_guild_by_id(guild_id: str) -> Optional[Guild]:
|
def get_guild_by_id(guild_id: str) -> Optional[Guild]:
|
||||||
@ -90,6 +57,9 @@ def get_guild_by_id(guild_id: str) -> Optional[Guild]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
CATALOG_CACHE = {}
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(500)
|
@app.errorhandler(500)
|
||||||
async def errorhandler(error: Exception):
|
async def errorhandler(error: Exception):
|
||||||
print(f"\33[31m{error}\33[m", flush=True)
|
print(f"\33[31m{error}\33[m", flush=True)
|
||||||
@ -251,10 +221,7 @@ async def subscribe(entity_id: str):
|
|||||||
entity_id=guild.vanity_url_code or guild.id,
|
entity_id=guild.vanity_url_code or guild.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
user = await client.get_or_fetch_user(int(entity_id))
|
||||||
user = await client.get_or_fetch_user(int(entity_id))
|
|
||||||
except ValueError:
|
|
||||||
return redirect(url_for(".login"))
|
|
||||||
|
|
||||||
if user and str(user.id) == entity_id:
|
if user and str(user.id) == entity_id:
|
||||||
return await render_template(
|
return await render_template(
|
||||||
@ -314,10 +281,7 @@ async def ical(entity_id: str):
|
|||||||
|
|
||||||
return calendar.serialize()
|
return calendar.serialize()
|
||||||
|
|
||||||
try:
|
user = await client.get_or_fetch_user(int(entity_id))
|
||||||
user = await client.get_or_fetch_user(int(entity_id))
|
|
||||||
except ValueError:
|
|
||||||
return redirect(url_for(".login"))
|
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
calendar = Calendar()
|
calendar = Calendar()
|
||||||
@ -331,16 +295,21 @@ async def ical(entity_id: str):
|
|||||||
)
|
)
|
||||||
|
|
||||||
for guild in client.guilds:
|
for guild in client.guilds:
|
||||||
for scheduled_event in guild.scheduled_events:
|
if await guild.get_or_fetch_member(int(entity_id)):
|
||||||
if user.id in EVENTS_CACHE[scheduled_event.id]:
|
for scheduled_event in guild.scheduled_events:
|
||||||
event = make_event(scheduled_event)
|
if user.id in [
|
||||||
calendar.events.append(event)
|
member.id
|
||||||
|
for member in await scheduled_event.fetch_users().flatten()
|
||||||
|
]:
|
||||||
|
event = make_event(scheduled_event)
|
||||||
|
calendar.events.append(event)
|
||||||
|
|
||||||
return calendar.serialize()
|
return calendar.serialize()
|
||||||
|
|
||||||
return redirect(url_for(".login"))
|
return redirect(url_for(".login"))
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def __main__():
|
||||||
client.loop.create_task(client.start(DISCORD_TOKEN))
|
quart_task = client.loop.create_task(app.run_task("0.0.0.0"))
|
||||||
app.run("0.0.0.0", loop=client.loop)
|
quart_task.add_done_callback(lambda f: client.loop.stop())
|
||||||
|
client.run(DISCORD_TOKEN)
|
||||||
|
1678
poetry.lock
generated
1678
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "divent"
|
name = "divent"
|
||||||
version = "4.1.4"
|
version = "4.0.0"
|
||||||
description = "The discord scheduled event calendar generator"
|
description = "The discord scheduled event calendar generator"
|
||||||
authors = ["Xéfir Destiny <xefir@crystalyx.net>"]
|
authors = ["Xéfir Destiny <xefir@crystalyx.net>"]
|
||||||
license = "WTFPL"
|
license = "WTFPL"
|
||||||
@ -9,29 +9,34 @@ homepage = "https://divent.crystalyx.net/"
|
|||||||
repository = "https://git.crystalyx.net/Xefir/Divent"
|
repository = "https://git.crystalyx.net/Xefir/Divent"
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
divent = 'divent.bot:run'
|
divent = 'divent.bot:__main__'
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = ">=3.8,<4.0"
|
python = ">=3.8.1,<3.12"
|
||||||
disnake = "^2.9.2"
|
disnake = "^2.9.1"
|
||||||
ics = "0.8.0.dev0"
|
ics = "0.8.0.dev0"
|
||||||
python-dotenv = "^1.0.1"
|
python-dotenv = "^1.0.0"
|
||||||
quart = "^0.19.6"
|
quart = "^0.19.3"
|
||||||
requests-oauthlib = "^2.0.0"
|
requests-oauthlib = "^1.3.1"
|
||||||
|
uvicorn = "^0.24.0"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
djlint = "^1.35.2"
|
black = "^23.10.1"
|
||||||
mypy = "^1.11.2"
|
djlint = "^1.34.0"
|
||||||
ruff = "^0.6.5"
|
flake8 = "^6.1.0"
|
||||||
types-oauthlib = "^3.2.0"
|
flake8-alphabetize = "^0.0.21"
|
||||||
|
flake8-black = "^0.3.6"
|
||||||
|
flake8-pyproject = "^1.2.3"
|
||||||
|
mypy = "^1.6.1"
|
||||||
|
types-oauthlib = "^3.2.0.10"
|
||||||
|
|
||||||
|
[tool.flake8]
|
||||||
|
max-line-length = 88
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
[tool.ruff.lint]
|
|
||||||
select = ["E", "F", "I"]
|
|
||||||
|
|
||||||
[tool.djlint]
|
[tool.djlint]
|
||||||
extension = "j2"
|
extension = "j2"
|
||||||
profile = "jinja"
|
profile = "jinja"
|
||||||
|
Loading…
Reference in New Issue
Block a user