init project
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Michel Roux 2022-05-08 16:02:19 +02:00 committed by Michel Roux
commit 6458b234da
28 changed files with 4957 additions and 0 deletions

34
.drone.yml Normal file
View File

@ -0,0 +1,34 @@
kind: pipeline
name: default
type: docker
steps:
- name: lint
image: python:3.8-slim
commands:
- pip install poetry
- poetry install
- poetry run flake8
- poetry run mypy .
- poetry run djlint .
- name: docker
image: plugins/docker
settings:
repo: xefir/divent
auto_tag: true
username:
from_secret: docker_username
password:
from_secret: docker_password
- name: publish
image: python:3.8-slim
commands:
- pip install poetry
- poetry publish --build
environment:
POETRY_PYPI_TOKEN_PYPI:
from_secret: pypi_token
when:
event: tag

1
.env.dist Normal file
View File

@ -0,0 +1 @@
DISCORD_TOKEN=

2
.flake8 Normal file
View File

@ -0,0 +1,2 @@
[flake8]
max-line-length = 100

161
.gitignore vendored Normal file
View File

@ -0,0 +1,161 @@
# https://github.com/github/gitignore/blob/main/Python.gitignore
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# 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
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

12
Dockerfile Normal file
View File

@ -0,0 +1,12 @@
FROM python:3.10.7-slim as build
WORKDIR /app
COPY . .
RUN pip install poetry && poetry build
FROM python:3.10.7-slim
COPY --from=build /app/dist /tmp/dist
RUN pip install /tmp/dist/*.whl && rm -rf /tmp/dist
CMD ["divent"]

40
README.md Normal file
View File

@ -0,0 +1,40 @@
# Divent
> The discord scheduled event calendar generator
[![Build Status](https://ci.crystalyx.net/api/badges/Xefir/Divent/status.svg)](https://ci.crystalyx.net/Xefir/Divent)
[![Docker Hub](https://img.shields.io/docker/pulls/xefir/divent)](https://hub.docker.com/r/xefir/divent)
Simple website that guides you to invite a bot to read and format scheduled events to a subscribable calendar.
## Installing / Getting started
### 1) Create the bot
- Go to the [Discord Developer Portal](https://discord.com/developers/applications) and create a new application.
- Enable the `Build-A-Bot` option in the `Bot` panel.
- Click on `Reset Token` and keep it in a safe place, you will need it.
- Configure the rest of your app and bot as you like (name, icon, username, etc.)
### 2) With Docker
- Install [Docker](https://docs.docker.com/get-docker/)
- Run `docker run -p 5000 -e DISCORD_TOKEN=your_bot_token xefir/divent`
- The app is accessible at http://localhost:5000
### 2) Without Docker
- Install [Python 3](https://www.python.org/downloads/)
- Install [Pip](https://pip.pypa.io/en/stable/installing/)
- Run `pip install divent`
- Run `DISCORD_TOKEN=your_bot_token divent`
- The app is accessible at http://localhost:5000
## Links
- [Project homepage](https://divent.crystalyx.net/)
- [Source repository](https://git.crystalyx.net/Xefir/Divent)
- [Issue tracker](https://git.crystalyx.net/Xefir/Divent/issues)
- [My other projects](https://git.crystalyx.net/Xefir)
- [Docker hub](https://hub.docker.com/r/xefir/divent)
- [Pypi](https://pypi.org/project/Divent/)
- [Donations](https://paypal.me/Xefir)

146
divent/bot.py Normal file
View File

@ -0,0 +1,146 @@
import json
import logging
from datetime import datetime, timedelta
from os import environ, path
from typing import Optional
from disnake import Client, Guild
from dotenv import load_dotenv
from ics import Calendar, Event
from ics.alarm import DisplayAlarm
from quart import Quart, redirect, render_template, request, url_for
import sentry_sdk
from sentry_sdk.integrations.quart import QuartIntegration
load_dotenv()
QUART_DEBUG = environ.get("QUART_DEBUG", False)
DISCORD_TOKEN = environ.get("DISCORD_TOKEN")
if not DISCORD_TOKEN:
raise Exception("Missing DISCORD_TOKEN")
if QUART_DEBUG:
logging.basicConfig(level=logging.DEBUG)
SENTRY_DSN = environ.get("SENTRY_DSN")
if SENTRY_DSN:
sentry_sdk.init(SENTRY_DSN, integrations=[QuartIntegration()])
class Discord(Client):
async def on_ready(self):
print(f"Logged on as {self.user}!")
client = Discord()
app = Quart(__name__)
def get_guild_by_id(guild_id: str) -> Optional[Guild]:
if guild_id:
for guild in client.guilds:
if str(guild.id) == guild_id or guild.vanity_url_code == guild_id:
return guild
return None
CATALOG_CACHE = {}
@app.errorhandler(500)
async def errorhandler(error: Exception):
print(f"\33[31m{error}\33[m")
return await render_template("error.html.j2", error=str(error)), 500
@app.errorhandler(404)
async def not_found(error: Exception):
return await render_template("error.html.j2", error=str(error)), 404
def i18n(str: str) -> str:
lang = request.accept_languages.best_match(["en", "fr"])
if lang not in CATALOG_CACHE:
catalog_file = f"{path.dirname(__file__)}/translations/{lang}.json"
if path.exists(catalog_file):
with open(catalog_file) as catalog_json:
catalog = json.load(catalog_json)
CATALOG_CACHE[lang] = catalog
if lang in CATALOG_CACHE and str in CATALOG_CACHE[lang]:
return CATALOG_CACHE[lang][str]
return str
def days_before_failure() -> int:
nextYear = datetime.today().year + 5 - ((datetime.today().year + 5) % 5)
nextDate = datetime(year=nextYear, month=6, day=3)
nextDelta = nextDate - datetime.now()
return nextDelta.days
@app.context_processor
def context_processor():
return dict(_=i18n, client=client, days_before_failure=days_before_failure())
@app.route("/")
async def index():
guild_id = request.args.get("guild")
guild = get_guild_by_id(guild_id)
if guild:
return redirect(url_for(".subscribe", guild_id=guild_id))
return await render_template("index.html.j2")
@app.route("/subscribe/<guild_id>")
async def subscribe(guild_id: str):
guild = get_guild_by_id(guild_id)
if guild is None:
return redirect(url_for(".index"))
return await render_template("subscribe.html.j2", guild=guild)
@app.route("/<guild_id>.ics")
async def ical(guild_id: str):
guild = get_guild_by_id(guild_id)
if guild is None:
return redirect(url_for(".index"))
calendar = Calendar()
for scheduled_event in guild.scheduled_events:
event = Event()
event.name = scheduled_event.name
event.begin = scheduled_event.scheduled_start_time
event.end = (
scheduled_event.scheduled_end_time
or scheduled_event.scheduled_start_time + timedelta(hours=2)
)
event.uid = str(scheduled_event.id)
event.description = scheduled_event.description
event.url = f"https://discord.com/events/{guild_id}/{scheduled_event.id}"
event.location = (
scheduled_event.entity_metadata.location
if scheduled_event.entity_metadata
else None
)
alarm = DisplayAlarm()
alarm.trigger = timedelta(hours=1)
event.alarms.append(alarm)
calendar.events.append(event)
return str(calendar)
quart_task = client.loop.create_task(app.run_task())
quart_task.add_done_callback(lambda f: client.loop.stop())
client.run(DISCORD_TOKEN)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,210 @@
/* https://google-webfonts-helper.herokuapp.com/fonts/open-sans?subsets=latin */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local(''),
url('../fonts/open-sans-v29-latin-regular.woff2') format('woff2'),
url('../fonts/open-sans-v29-latin-regular.woff') format('woff');
}
html,
body {
height: 100%;
}
a {
text-decoration: none;
}
body {
background-color: #2f3136;
margin: 0;
font-family: Whitney, "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #b9bbbe;
display: flex;
flex-direction: column;
justify-content: space-between;
}
#logo {
position: relative;
left: 24px;
top: 24px;
height: 36px;
width: 130px;
}
footer,
h1,
h2 {
text-align: center;
}
#avatars {
display: flex;
justify-content: center;
}
#avatars img {
border-radius: 50%;
}
#content {
min-width: 280px;
max-width: 400px;
background-color: #18191c;
border-radius: 5px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.24);
align-self: center;
}
#box {
padding: 32px 16px 24px;
}
#dots {
font-size: xx-large;
opacity: 0.2;
align-self: center;
margin: 0 24px;
}
.hr-sect {
display: flex;
align-items: center;
color: rgba(79, 84, 92);
margin: 8px 0;
}
.hr-sect:before,
.hr-sect:after {
content: "";
flex-grow: 1;
background: rgba(79, 84, 92);
height: 1px;
margin: 0 8px;
}
#scopes li {
margin: 8px;
font-size: 14px;
}
.black_input {
width: 100%;
background-color: #202225;
border: 0;
border-radius: 3px;
color: white;
font-size: 15px;
padding: 10px;
box-sizing: border-box;
}
#permissions {
font-size: 12px;
margin-top: 8px;
}
#providers li {
margin: 12px;
}
ul {
list-style-type: none;
padding: 0;
}
ul li a {
color: #a3a6aa;
}
footer ul {
font-size: 12px;
}
footer ul li {
display: inline-block;
}
footer ul li:last-child {
display: block;
}
footer ul li i,
#providers li a i {
margin: 4px;
}
.fa-custom-circle {
border-radius: 20px;
width: 24px;
height: 24px;
text-align: center;
line-height: 22px;
font-size: 20px;
float: left;
margin-right: 12px;
margin-top: 6px;
}
.fa-check {
background-color: green;
}
.fa-times {
background-color: grey;
}
h1 {
font-size: 20px;
color: white;
}
h2 {
font-size: 16px;
}
h3 {
text-transform: uppercase;
font-size: 12px;
}
hr {
color: rgba(79, 84, 92, 0.48);
margin: 24px 0;
}
#buttons {
background-color: #2f3136;
padding: 16px;
text-align: right;
border-radius: 0 0 5px 5px;
display: flex;
justify-content: flex-end;
}
.button {
background-color: #5865f2;
line-height: 38px;
font-size: 14px;
padding: 0 16px;
border-radius: 3px;
color: white;
border: 0;
display: block;
text-align: center;
}
@media only screen and (max-width : 320px) {
#logo {
align-self: center;
top: inherit;
left: inherit;
}
footer ul li {
display: block;
}
}

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,23 @@
<svg width="292" height="80" viewBox="0 0 292 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<g clip-path="url(#clip1)">
<path d="M61.7958 16.494C57.0736 14.2846 52.0244 12.6789 46.7456 11.7646C46.0973 12.9367 45.3399 14.5132 44.8177 15.7673C39.2062 14.9234 33.6463 14.9234 28.138 15.7673C27.6159 14.5132 26.8413 12.9367 26.1872 11.7646C20.9027 12.6789 15.8477 14.2905 11.1255 16.5057C1.60078 30.8988 -0.981215 44.9344 0.309785 58.7707C6.62708 63.4883 12.7493 66.3541 18.7682 68.2294C20.2543 66.1841 21.5797 64.0099 22.7215 61.7185C20.5469 60.8922 18.4641 59.8725 16.4961 58.6887C17.0182 58.3019 17.5289 57.8975 18.0223 57.4814C30.0257 63.0957 43.0677 63.0957 54.9277 57.4814C55.4269 57.8975 55.9375 58.3019 56.4539 58.6887C54.4801 59.8783 52.3916 60.898 50.217 61.7244C51.3588 64.0099 52.6785 66.19 54.1703 68.2352C60.195 66.3599 66.3229 63.4942 72.6402 58.7707C74.155 42.7309 70.0525 28.8242 61.7958 16.494ZM24.3568 50.2615C20.7535 50.2615 17.7985 46.8976 17.7985 42.8012C17.7985 38.7048 20.6904 35.3351 24.3568 35.3351C28.0233 35.3351 30.9782 38.6989 30.9151 42.8012C30.9208 46.8976 28.0233 50.2615 24.3568 50.2615ZM48.5932 50.2615C44.9899 50.2615 42.0349 46.8976 42.0349 42.8012C42.0349 38.7048 44.9267 35.3351 48.5932 35.3351C52.2596 35.3351 55.2146 38.6989 55.1515 42.8012C55.1515 46.8976 52.2596 50.2615 48.5932 50.2615Z" fill="white"/>
<path d="M98.0293 26.1707H113.693C117.469 26.1707 120.659 26.7743 123.276 27.9757C125.886 29.177 127.843 30.8531 129.14 32.998C130.436 35.1429 131.09 37.5984 131.09 40.3645C131.09 43.072 130.413 45.5275 129.059 47.7251C127.705 49.9286 125.645 51.6692 122.874 52.9526C120.103 54.236 116.671 54.8806 112.569 54.8806H98.0293V26.1707ZM112.408 47.5845C114.95 47.5845 116.907 46.934 118.272 45.6388C119.638 44.3378 120.321 42.568 120.321 40.3235C120.321 38.243 119.712 36.5845 118.496 35.3421C117.28 34.0997 115.438 33.4727 112.976 33.4727H108.076V47.5845H112.408Z" fill="white"/>
<path d="M154.541 54.8456C152.372 54.2713 150.415 53.4391 148.677 52.3432V45.5335C149.991 46.5707 151.752 47.4264 153.961 48.1003C156.17 48.7684 158.305 49.1024 160.37 49.1024C161.334 49.1024 162.063 48.9735 162.556 48.7156C163.05 48.4578 163.297 48.1472 163.297 47.7897C163.297 47.3795 163.165 47.0396 162.895 46.7641C162.625 46.4887 162.103 46.2601 161.329 46.0667L156.509 44.9591C153.749 44.3028 151.792 43.3944 150.628 42.2282C149.463 41.0678 148.883 39.5441 148.883 37.6571C148.883 36.0689 149.388 34.6918 150.41 33.5138C151.425 32.3359 152.871 31.4275 154.747 30.7887C156.624 30.1441 158.815 29.8218 161.334 29.8218C163.583 29.8218 165.643 30.0679 167.52 30.5602C169.396 31.0525 170.945 31.6795 172.179 32.4472V38.8878C170.916 38.1201 169.47 37.5165 167.818 37.0593C166.171 36.6081 164.479 36.3854 162.734 36.3854C160.215 36.3854 158.959 36.8249 158.959 37.6981C158.959 38.1084 159.154 38.4131 159.544 38.6182C159.934 38.8233 160.651 39.0343 161.69 39.257L165.706 39.9954C168.329 40.4584 170.285 41.273 171.57 42.4333C172.856 43.5937 173.498 45.3108 173.498 47.5846C173.498 50.0752 172.437 52.0502 170.308 53.5153C168.179 54.9804 165.161 55.7129 161.248 55.7129C158.947 55.7071 156.71 55.4199 154.541 54.8456Z" fill="white"/>
<path d="M182.978 53.9839C180.678 52.8352 178.939 51.2764 177.78 49.3073C176.621 47.3382 176.036 45.123 176.036 42.6616C176.036 40.2003 176.638 37.9968 177.843 36.057C179.048 34.1172 180.815 32.5935 183.145 31.4859C185.474 30.3783 188.257 29.8274 191.499 29.8274C195.515 29.8274 198.849 30.6889 201.5 32.4118V39.919C200.565 39.2626 199.474 38.7293 198.229 38.3191C196.984 37.9089 195.653 37.7037 194.23 37.7037C191.74 37.7037 189.795 38.1667 188.389 39.0985C186.983 40.0303 186.278 41.2434 186.278 42.7495C186.278 44.2263 186.96 45.4336 188.326 46.383C189.692 47.3265 191.671 47.8012 194.27 47.8012C195.607 47.8012 196.927 47.6019 198.229 47.2093C199.526 46.8108 200.645 46.3244 201.58 45.75V53.011C198.637 54.816 195.223 55.7185 191.338 55.7185C188.068 55.7068 185.279 55.1325 182.978 53.9839Z" fill="white"/>
<path d="M211.518 53.9841C209.2 52.8355 207.433 51.2649 206.216 49.2665C205 47.2681 204.386 45.0412 204.386 42.5798C204.386 40.1185 204.994 37.9208 206.216 35.9928C207.438 34.0647 209.194 32.5527 211.501 31.4568C213.801 30.3609 216.55 29.8159 219.734 29.8159C222.919 29.8159 225.667 30.3609 227.968 31.4568C230.269 32.5527 232.025 34.053 233.23 35.9693C234.435 37.8857 235.037 40.0833 235.037 42.574C235.037 45.0353 234.435 47.2623 233.23 49.2606C232.025 51.259 230.263 52.8296 227.945 53.9782C225.627 55.1269 222.89 55.7012 219.729 55.7012C216.567 55.7012 213.83 55.1327 211.518 53.9841ZM223.722 46.7055C224.698 45.7093 225.191 44.3907 225.191 42.7498C225.191 41.1089 224.703 39.802 223.722 38.835C222.747 37.8622 221.415 37.3758 219.729 37.3758C218.013 37.3758 216.67 37.8622 215.689 38.835C214.714 39.8079 214.226 41.1089 214.226 42.7498C214.226 44.3907 214.714 45.7093 215.689 46.7055C216.665 47.7018 218.013 48.2058 219.729 48.2058C221.415 48.1999 222.747 47.7018 223.722 46.7055Z" fill="white"/>
<path d="M259.17 31.3395V40.2004C258.149 39.5147 256.829 39.1748 255.194 39.1748C253.053 39.1748 251.401 39.8371 250.253 41.1615C249.1 42.486 248.526 44.5488 248.526 47.3383V54.8865H238.686V30.8883H248.326V38.5185C248.859 35.7289 249.726 33.672 250.919 32.3416C252.107 31.0172 253.644 30.355 255.515 30.355C256.932 30.355 258.149 30.6832 259.17 31.3395Z" fill="white"/>
<path d="M291.864 25.3503V54.8866H282.023V49.5127C281.191 51.5345 279.929 53.0758 278.231 54.1306C276.532 55.1797 274.432 55.7071 271.942 55.7071C269.716 55.7071 267.777 55.1562 266.118 54.0486C264.46 52.941 263.181 51.4232 262.28 49.4951C261.385 47.567 260.931 45.387 260.931 42.9491C260.903 40.435 261.379 38.1787 262.36 36.1803C263.336 34.1819 264.718 32.6231 266.497 31.5037C268.276 30.3844 270.307 29.8218 272.585 29.8218C277.273 29.8218 280.417 31.9022 282.023 36.0572V25.3503H291.864ZM280.555 46.5415C281.559 45.5452 282.058 44.2501 282.058 42.6678C282.058 41.1382 281.57 39.8899 280.595 38.9347C279.619 37.9795 278.282 37.4989 276.601 37.4989C274.943 37.4989 273.618 37.9853 272.625 38.9581C271.632 39.931 271.139 41.1909 271.139 42.7498C271.139 44.3087 271.632 45.5804 272.625 46.5649C273.618 47.5494 274.926 48.0417 276.561 48.0417C278.219 48.0359 279.55 47.5377 280.555 46.5415Z" fill="white"/>
<path d="M139.382 33.4432C142.091 33.4432 144.288 31.4281 144.288 28.9424C144.288 26.4567 142.091 24.4417 139.382 24.4417C136.672 24.4417 134.476 26.4567 134.476 28.9424C134.476 31.4281 136.672 33.4432 139.382 33.4432Z" fill="white"/>
<path d="M134.472 36.5435C137.478 37.8679 141.208 37.9265 144.283 36.5435V55.0154H134.472V36.5435Z" fill="white"/>
</g>
</g>
<defs>
<clipPath id="clip0">
<rect width="292" height="56.4706" fill="white" transform="translate(0 11.7646)"/>
</clipPath>
<clipPath id="clip1">
<rect width="292" height="56.4706" fill="white" transform="translate(0 11.7646)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<title>{{ client.user.display_name }} - {{ _('The discord scheduled event calendar generator') }}</title>
<link rel="stylesheet"
href="{{ url_for('static', filename='css/font-awesome.min.css') }}"/>
<link rel="stylesheet"
href="{{ url_for('static', filename='css/global.css') }}"/>
</head>
<body>
<img src="{{ url_for('static', filename='img/Discord-Logo+Wordmark-White.svg') }}"
id="logo"
height="36"
width="130"
alt="{{ _('Discord Logo') }}"/>
<div id="content">
{% block content %}
{% endblock content %}
</div>
<footer>
{% include 'footer.html.j2' %}
</footer>
</body>
</html>

View File

@ -0,0 +1,19 @@
{% extends "base.html.j2" %}
{% block content %}
<div id="box">
<div id="avatars">
<img src="{{ url_for('static', filename='img/deadlink.png') }}"
alt="{{ _('Link is dead') }}"
height="179"
width="173"/>
</div>
<hr />
<span>{{ error }}</span>
</div>
<div id="buttons">
<a href="{{ url_for('index') }}">
<i class="fa fa-arrow-left"></i>
{{ _('Back to the beginning') }}
</a>
</div>
{% endblock content %}

View File

@ -0,0 +1,30 @@
<ul>
<li>
<a href="https://discord.com/users/133305654512320513" target="_blank">
<i class="fa fa-user-plus"></i>
{{ _('Add author on Discord') }}
</a>
</li>
<li>
<a href="http://www.wtfpl.net" target="_blank">
<i class="fa fa-book"></i>
{{ _('Read the licence') }}
</a>
</li>
<li>
<a href="https://git.crystalyx.net/Xefir/Divent" target="_blank">
<i class="fa fa-code-fork"></i>
{{ _('View the source code') }}
</a>
</li>
<li>
<a href="https://hub.docker.com/r/xefir/divent" target="_blank">
<i class="fa fa-cubes"></i>
{{ _('Host it yourself') }}
</a>
</li>
<li>
<i class="fa fa-heartbeat"></i>
{{ _('Next castastrophic life failure in about %days% days') | replace('%days%', days_before_failure) }}
</li>
</ul>

View File

@ -0,0 +1,62 @@
{% extends "base.html.j2" %}
{% block content %}
<form action="" method="get">
<div id="box">
<div id="avatars">
<img src="{{ client.user.display_avatar }}"
alt="{{ _('Bot Logo') }}"
width="80"
height="80"/>
</div>
<h1>{{ client.user.display_name }}</h1>
<h2>{{ _('The discord scheduled event calendar generator') }}</h2>
<hr />
<h3>{{ _('This will allow you to:') }}</h3>
<ul id="scopes">
<li>
<i class="fa fa-custom-circle fa-check"></i>
{{ _('Subscribe to a calendar on Google, Outlook, Apple or any ICS complient software') }}
</li>
<li>
<i class="fa fa-custom-circle fa-times"></i>
{{ _('Throwing you to a new isekai world') }}
</li>
</ul>
<hr />
<h3>{{ _('Choose a server:') }}</h3>
<select name="guild" class="black_input">
<option>
&nbsp;
</option>
{% for guild in client.guilds %}
<option value="{{ guild.vanity_url_code|default(guild.id, True) }}">
{{ guild.name }}
</option>
{% endfor %}
</select>
<div class="hr-sect">{{ _("OR") }}</div>
<a class="button"
target="_blank"
href="https://discord.com/api/oauth2/authorize?client_id={{ client.user.id }}&permissions=536870912&scope=bot">
{{ _("Add the bot on your server") }}
</a>
<ul id="permissions">
<li>
{{ _("You must have") }}
<strong>{{ _("Manage Server") }}</strong>
{{ _("permission on this server to perform this action") }}
</li>
<li>
{{ _("After adding the bot,") }}
<a href="">
<i class="fa fa-refresh"></i>
<strong>{{ _("reload the page") }}</strong>
</a>
</li>
</ul>
</div>
<div id="buttons">
<input type="submit" class="button" value="{{ _("Let's go!") }}"/>
</div>
</form>
{% endblock content %}

View File

@ -0,0 +1,53 @@
{% extends "base.html.j2" %}
{% block content %}
<div id="box">
<div id="avatars">
<img src="{{ client.user.display_avatar }}"
alt="{{ _('Bot Logo') }}"
width="80"
height="80"/>
<span id="dots">…</span>
<img src="{{ guild.icon.url }}"
alt="{{ _('Guild Logo') }}"
width="80"
height="80"/>
</div>
<h1>{{ client.user.display_name }}</h1>
<h2>{{ _('The discord scheduled event calendar generator') }}</h2>
<hr />
<ul id="providers">
<li>
<a class="button"
target="_blank"
href="https://calendar.google.com/calendar/u/0/r?cid={{ request.host_url }}{{ guild.vanity_url_code|default(guild.id, True) }}.ics">
<i class="fa fa-google"></i>
{{ _("Subscribe to") }} Google
</a>
</li>
<li>
<a class="button"
target="_blank"
href="https://outlook.live.com/owa?path=/calendar/action/compose&rru=addsubscription&url={{ request.host_url }}{{ guild.vanity_url_code|default(guild.id, True) }}.ics">
<i class="fa fa-windows"></i>
{{ _("Subscribe to") }} Outlook
</a>
</li>
<li>
<a class="button"
target="_blank"
href="webcal://{{ request.host }}/{{ guild.vanity_url_code|default(guild.id, True) }}.ics">
<i class="fa fa-apple"></i>
{{ _("Subscribe to") }} Apple
</a>
</li>
</ul>
<div class="hr-sect">{{ _("OR") }}</div>
<div>
<h3>{{ _("Use the direct link:") }}</h3>
<input type="text"
readonly
class="black_input"
value="webcal://{{ request.host }}/{{ guild.vanity_url_code|default(guild.id, True) }}.ics">
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,25 @@
{
"Discord Logo": "Logo Discord",
"Bot Logo": "Logo du robot",
"The discord scheduled event calendar generator": "Générateur de calendrier pour les évènements Discord",
"This will allow you to:": "Ceci te permettra de :",
"Subscribe to a calendar on Google, Outlook, Apple or any ICS complient software": "T'abonner à un calendrier sur Google, Outlook, Apple ou tout autre logiciel compatible",
"Throwing you to a new isekai world": "T'envoyer dans un monde fantaisiste armée d'une poêle à frire",
"Choose a server:": "Choisi un serveur :",
"You must have": "Tu dois avoir la permission",
"Manage Server": "Gérer le serveur",
"permission on this server to perform this action": "sur ce serveur pour effectuer cette action",
"OR": "OU",
"Add the bot on your server": "Ajoute le bot sur ton serveur",
"After adding the bot,": "Après avoir ajouté le bot sur ton serveur,",
"reload the page": "actualise la page",
"Use the direct link:": "Utiliser le lien direct :",
"Subscribe to": "S'abonner via",
"Let's go!": "C'est parti !",
"Back to the beginning": "Retour à l'accueil",
"Add author on Discord": "Ajoute moi sur Discord ;)",
"Read the licence": "Va voir la licence",
"View the source code" : "Jette un œil au code source",
"Host it yourself": "Héberge ça chez toi",
"Next castastrophic life failure in about %days% days": "Prochaine vie de merde dans environ %days% jours"
}

1391
poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

40
pyproject.toml Normal file
View File

@ -0,0 +1,40 @@
[tool.poetry]
name = "divent"
version = "1.0.0"
description = "The discord scheduled event calendar generator"
authors = ["Xéfir Destiny"]
license = "WTFPL"
readme = "README.md"
homepage = "https://divent.crystalyx.net/"
repository = "https://git.crystalyx.net/Xefir/Divent"
classifiers = [
"Programming Language :: Python :: 3",
"Operating System :: OS Independent"
]
[tool.poetry.scripts]
divent = 'divent.bot:__main__'
[tool.poetry.dependencies]
python = "^3.8"
disnake = "2.5.2"
ics = "0.8.0.dev0"
python-dotenv = "0.21.0"
quart = "0.18.0"
sentry-sdk = "1.9.8"
[tool.poetry.dev-dependencies]
flake8 = "5.0.4"
black = "22.8.0"
mypy = "0.971"
flake8-alphabetize = "0.0.17"
flake8-black = "0.3.3"
djlint = "1.12.3"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.djlint]
extension = "j2"
profile = "jinja"

4
renovate.json Normal file
View File

@ -0,0 +1,4 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"ignorePaths": [".drone.yml"]
}