Initial commit
This commit is contained in:
commit
7427007520
7 changed files with 837 additions and 0 deletions
246
.gitignore
vendored
Normal file
246
.gitignore
vendored
Normal file
|
@ -0,0 +1,246 @@
|
|||
|
||||
# Created by https://www.gitignore.io/api/vim,macos,emacs,python,sublimetext
|
||||
|
||||
### Emacs ###
|
||||
# -*- mode: gitignore; -*-
|
||||
*~
|
||||
\#*\#
|
||||
/.emacs.desktop
|
||||
/.emacs.desktop.lock
|
||||
*.elc
|
||||
auto-save-list
|
||||
tramp
|
||||
.\#*
|
||||
|
||||
# Org-mode
|
||||
.org-id-locations
|
||||
*_archive
|
||||
|
||||
# flymake-mode
|
||||
*_flymake.*
|
||||
|
||||
# eshell files
|
||||
/eshell/history
|
||||
/eshell/lastdir
|
||||
|
||||
# elpa packages
|
||||
/elpa/
|
||||
|
||||
# reftex files
|
||||
*.rel
|
||||
|
||||
# AUCTeX auto folder
|
||||
/auto/
|
||||
|
||||
# cask packages
|
||||
.cask/
|
||||
dist/
|
||||
|
||||
# Flycheck
|
||||
flycheck_*.el
|
||||
|
||||
# server auth directory
|
||||
/server/
|
||||
|
||||
# projectiles files
|
||||
.projectile
|
||||
projectile-bookmarks.eld
|
||||
|
||||
# directory configuration
|
||||
.dir-locals.el
|
||||
|
||||
# saveplace
|
||||
places
|
||||
|
||||
# url cache
|
||||
url/cache/
|
||||
|
||||
# cedet
|
||||
ede-projects.el
|
||||
|
||||
# smex
|
||||
smex-items
|
||||
|
||||
# company-statistics
|
||||
company-statistics-cache.el
|
||||
|
||||
# anaconda-mode
|
||||
anaconda-mode/
|
||||
|
||||
### macOS ###
|
||||
*.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# 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/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# 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/
|
||||
|
||||
### SublimeText ###
|
||||
# cache files for sublime text
|
||||
*.tmlanguage.cache
|
||||
*.tmPreferences.cache
|
||||
*.stTheme.cache
|
||||
|
||||
# workspace files are user-specific
|
||||
*.sublime-workspace
|
||||
|
||||
# project files should be checked into the repository, unless a significant
|
||||
# proportion of contributors will probably not be using SublimeText
|
||||
# *.sublime-project
|
||||
|
||||
# sftp configuration file
|
||||
sftp-config.json
|
||||
|
||||
# Package control specific files
|
||||
Package Control.last-run
|
||||
Package Control.ca-list
|
||||
Package Control.ca-bundle
|
||||
Package Control.system-ca-bundle
|
||||
Package Control.cache/
|
||||
Package Control.ca-certs/
|
||||
Package Control.merged-ca-bundle
|
||||
Package Control.user-ca-bundle
|
||||
oscrypto-ca-bundle.crt
|
||||
bh_unicode_properties.cache
|
||||
|
||||
# Sublime-github package stores a github token in this file
|
||||
# https://packagecontrol.io/packages/sublime-github
|
||||
GitHub.sublime-settings
|
||||
|
||||
### Vim ###
|
||||
# swap
|
||||
[._]*.s[a-v][a-z]
|
||||
[._]*.sw[a-p]
|
||||
[._]s[a-v][a-z]
|
||||
[._]sw[a-p]
|
||||
# session
|
||||
Session.vim
|
||||
# temporary
|
||||
.netrwhist
|
||||
# auto-generated tag files
|
||||
tags
|
||||
|
||||
config.py
|
||||
|
||||
# End of https://www.gitignore.io/api/vim,macos,emacs,python,sublimetext
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "telewalrus"]
|
||||
path = telewalrus
|
||||
url = git@github.com:SijmenSchoon/telewalrus.git
|
102
api.py
Normal file
102
api.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
import urllib.parse
|
||||
import aiohttp
|
||||
|
||||
SCHEME = 'http'
|
||||
NETLOC = 'localhost:5000'
|
||||
|
||||
|
||||
class ApiError(Exception): pass
|
||||
|
||||
class BadRequestError(ApiError): pass
|
||||
class PermissionDeniedError(ApiError): pass
|
||||
class NotFoundError(ApiError): pass
|
||||
class InternalServerError(ApiError): pass
|
||||
|
||||
|
||||
def build_url(path, query_args=None):
|
||||
query = urllib.parse.urlencode(query_args if query_args else {})
|
||||
parse_result = urllib.parse.ParseResult(
|
||||
scheme=SCHEME, netloc=NETLOC, path=path,
|
||||
params='', query=query, fragment='')
|
||||
return urllib.parse.urlunparse(parse_result)
|
||||
|
||||
def check_status(status):
|
||||
if status == 400:
|
||||
raise BadRequestError
|
||||
elif status == 403:
|
||||
raise PermissionDeniedError
|
||||
elif status == 404:
|
||||
raise NotFoundError
|
||||
elif status == 500:
|
||||
raise InternalServerError
|
||||
|
||||
|
||||
async def get_json(url, token=None):
|
||||
headers = {'Authorization': f'Bearer {token}'} if token else {}
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, headers=headers) as resp:
|
||||
check_status(resp.status)
|
||||
return await resp.json()
|
||||
|
||||
|
||||
async def post_json(url, obj, token=None):
|
||||
headers = {'Authorization': f'Bearer {token}'} if token else {}
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(url, json=obj, headers=headers) as resp:
|
||||
check_status(resp.status)
|
||||
return await resp.json()
|
||||
|
||||
|
||||
async def put_json(url, obj, token=None):
|
||||
headers = {'Authorization': f'Bearer {token}'} if token else {}
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.put(url, json=obj, headers=headers) as resp:
|
||||
check_status(resp.status)
|
||||
return await resp.json()
|
||||
|
||||
|
||||
async def get_tasks(token, group_id=None):
|
||||
args = {'group_id': group_id} if group_id else {}
|
||||
url = build_url('/pimpy/api/tasks/', args)
|
||||
return await get_json(url, token=token)
|
||||
|
||||
|
||||
async def get_group_tasks(token, group_id):
|
||||
url = build_url(f'/pimpy/api/groups/{group_id:d}/tasks/')
|
||||
return await get_json(url, token=token)
|
||||
|
||||
|
||||
async def get_group_user_tasks(token, group_id, user_id='me'):
|
||||
url = build_url(f'/pimpy/api/groups/{group_id:d}/users/{user_id}/tasks/')
|
||||
return await get_json(url, token=token)
|
||||
|
||||
|
||||
async def get_group_task(token, group_id, task_id):
|
||||
url = build_url(f'/pimpy/api/groups/{group_id:d}/tasks/{task_id:d}/')
|
||||
return await get_json(url, token=token)
|
||||
|
||||
|
||||
async def add_group_task(token, group_id, owners, title):
|
||||
url = build_url(f'/pimpy/api/groups/{group_id:d}/tasks/')
|
||||
obj = {'owners': owners, 'title': title}
|
||||
return await post_json(url, obj, token=token)
|
||||
|
||||
|
||||
async def get_group_users(token, group_id):
|
||||
url = build_url(f'/pimpy/api/groups/{group_id:d}/users/')
|
||||
return await get_json(url, token=token)
|
||||
|
||||
|
||||
async def get_task(token, task_id):
|
||||
url = build_url(f'/pimpy/api/tasks/{task_id:d}/')
|
||||
return await get_json(url, token=token)
|
||||
|
||||
|
||||
async def set_group_task_status(token, group_id, task_id, status):
|
||||
url = build_url(f'/pimpy/api/groups/{group_id:d}/tasks/{task_id:d}/status/')
|
||||
return await put_json(url, {'status': status}, token=token)
|
||||
|
||||
|
||||
async def set_task_status(token, task_id, status):
|
||||
url = build_url(f'/pimpy/api/tasks/{task_id:d}/status/')
|
||||
return await put_json(url, {'status': status}, token=token)
|
326
app.py
Normal file
326
app.py
Normal file
|
@ -0,0 +1,326 @@
|
|||
#!/usr/bin/env python3
|
||||
import json
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from math import ceil
|
||||
|
||||
import baas32
|
||||
import telewalrus.bot
|
||||
|
||||
import api
|
||||
import messages
|
||||
|
||||
|
||||
from config import VIA_USERS, VIA_GROUPS, TG_TOKEN, USER_TOKENS
|
||||
BOT = telewalrus.bot.Bot(TG_TOKEN)
|
||||
|
||||
|
||||
@BOT.command('start')
|
||||
async def cmd_start(message):
|
||||
name = message.from_user.first_name
|
||||
|
||||
if message.from_user.id not in VIA_USERS:
|
||||
await message.chat.message(messages.stranger_message(name))
|
||||
return
|
||||
|
||||
await message.chat.message(
|
||||
f'Heya, {name}! Zie /tasks om te zien welke taken je open hebt staan.')
|
||||
|
||||
|
||||
@BOT.command('chatinfo')
|
||||
async def cmd_chatinfo(message):
|
||||
chat = message.chat
|
||||
|
||||
if message.chat.type == 'private':
|
||||
admins = []
|
||||
else:
|
||||
admins = [admin.user for admin in await chat.administrators()]
|
||||
|
||||
msg = f'''
|
||||
id: {chat.id}
|
||||
type: {chat.type}
|
||||
title: {chat.title}
|
||||
username: {chat.username}
|
||||
first_name: {chat.first_name}
|
||||
last_name: {chat.last_name}
|
||||
admins: {admins}
|
||||
'''
|
||||
await message.chat.message(msg)
|
||||
|
||||
|
||||
@BOT.command('tasks')
|
||||
async def cmd_tasks(message):
|
||||
token = USER_TOKENS.get(message.from_user.id)
|
||||
if not token:
|
||||
msg = messages.stranger_message(message.from_user.first_name)
|
||||
await message.chat.message(msg)
|
||||
return
|
||||
|
||||
is_group = message.chat.type != 'private'
|
||||
if not is_group:
|
||||
tasks = await api.get_tasks(token)
|
||||
else:
|
||||
group_id = VIA_GROUPS.get(message.chat.id)
|
||||
if group_id is None:
|
||||
await message.chat.message(
|
||||
'pimpy is nog niet ingeschakeld voor deze groep :/')
|
||||
return
|
||||
|
||||
tasks = await api.get_group_user_tasks(token, group_id)
|
||||
print(json.dumps(tasks, indent=4))
|
||||
|
||||
msg = messages.tasks_message(tasks, is_group)
|
||||
await message.chat.message(msg, parse_mode='HTML')
|
||||
|
||||
|
||||
@BOT.command('grouptasks')
|
||||
async def cmd_grouptasks(message):
|
||||
token = USER_TOKENS.get(message.from_user.id)
|
||||
if not token:
|
||||
msg = messages.stranger_message(message.from_user.first_name)
|
||||
await message.chat.message(msg)
|
||||
return
|
||||
|
||||
if message.chat.type == 'private':
|
||||
await message.chat.message(
|
||||
'Dit commando werkt alleen in commissiechats.')
|
||||
return
|
||||
|
||||
group_id = VIA_GROUPS.get(message.chat.id)
|
||||
if not group_id:
|
||||
await message.chat.message(
|
||||
'pimpy is nog niet ingeschakeld voor deze groep :/')
|
||||
return
|
||||
|
||||
user_tasks = await api.get_group_tasks(token, group_id)
|
||||
|
||||
msg = ''
|
||||
for i, (name, tasks) in enumerate(user_tasks.items()):
|
||||
status = defaultdict(int)
|
||||
for task in tasks:
|
||||
status[task['status']] += 1
|
||||
|
||||
msg += f'<b>{name}</b>:\n' \
|
||||
f' ⏸ {status["Niet begonnen"]}, ▶️ {status["Begonnen"]}, ' \
|
||||
f'✅ {status["Done"]}, ❌ {status["Niet Done"]}\n'
|
||||
|
||||
users = await api.get_group_users(token, group_id)
|
||||
keyboard = []
|
||||
for i, user in enumerate(users):
|
||||
if i % 3 == 0:
|
||||
keyboard.append([])
|
||||
|
||||
keyboard[-1].append({
|
||||
'text': user['name'],
|
||||
'callback_data': f'tasks {user["id"]} {user["name"]}'
|
||||
})
|
||||
|
||||
msg += '\nKlik op een naam hieronder om zijn/haar taken weer te geven.'
|
||||
reply_markup = {'inline_keyboard': keyboard}
|
||||
|
||||
await message.chat.message(msg, parse_mode='HTML',
|
||||
disable_web_page_preview=True,
|
||||
reply_markup=json.dumps(reply_markup))
|
||||
|
||||
|
||||
async def get_task_from_args(token, message, group_id=None):
|
||||
task_code = baas32.normalize(message.args)
|
||||
if not task_code:
|
||||
await message.chat.message(
|
||||
'Welke taak? Protip: zet de taakcode achter het commando.')
|
||||
return
|
||||
|
||||
try:
|
||||
task_id = baas32.decode(task_code)
|
||||
except ValueError:
|
||||
await message.chat.message(f'{task_code} is geen geldige taakcode.')
|
||||
return
|
||||
|
||||
try:
|
||||
if group_id:
|
||||
task = await api.get_group_task(token, group_id, task_id)
|
||||
else:
|
||||
task = await api.get_task(token, task_id)
|
||||
except api.NotFoundError:
|
||||
await message.chat.message(f'Kan taak {task_code} niet vinden :(')
|
||||
return
|
||||
except api.PermissionDeniedError:
|
||||
await message.chat.message(
|
||||
f'Je hebt geen rechten voor taak {task_code}.')
|
||||
return
|
||||
|
||||
return task, task_code
|
||||
|
||||
|
||||
@BOT.command('task')
|
||||
async def cmd_task(message):
|
||||
token = USER_TOKENS.get(message.from_user.id)
|
||||
if not token:
|
||||
msg = messages.stranger_message(message.from_user.first_name)
|
||||
await message.chat.message(msg)
|
||||
return
|
||||
|
||||
group_id = None
|
||||
if message.chat.type != 'private':
|
||||
group_id = VIA_GROUPS.get(message.chat.id)
|
||||
if not group_id:
|
||||
await message.chat.message(
|
||||
'pimpy is nog niet ingeschakeld voor deze groep :/')
|
||||
return
|
||||
|
||||
task, _ = await get_task_from_args(token, message, group_id)
|
||||
if not task:
|
||||
return
|
||||
|
||||
msg, reply_markup = messages.task_message(task, group_id is not None)
|
||||
|
||||
await message.chat.message(msg, parse_mode='HTML',
|
||||
reply_markup=json.dumps(reply_markup),
|
||||
disable_web_page_preview=True)
|
||||
|
||||
|
||||
@BOT.command('done')
|
||||
async def cmd_done(message):
|
||||
user_id = VIA_USERS.get(message.from_user.id)
|
||||
if not user_id:
|
||||
msg = messages.stranger_message(message.from_user.first_name)
|
||||
await message.chat.message(msg)
|
||||
return
|
||||
|
||||
task, task_code = await get_task_from_args(message)
|
||||
if not task:
|
||||
return
|
||||
|
||||
if not user_id in (user['id'] for user in task['users']):
|
||||
msg = f'Je bent geen eigenaar van de taak {task_code}!'
|
||||
await message.chat.message(msg, parse_mode='HTML')
|
||||
return
|
||||
|
||||
await api.set_task_status(task['id'], 'done')
|
||||
|
||||
msg = f'Taak {task_code} staat nu op done!'
|
||||
await message.chat.message(msg)
|
||||
|
||||
|
||||
@BOT.command('addtask')
|
||||
async def cmd_addtask(message):
|
||||
user_id = VIA_USERS.get(message.from_user.id)
|
||||
if not user_id:
|
||||
msg = messages.stranger_message(message.from_user.first_name)
|
||||
await message.chat.message(msg)
|
||||
return
|
||||
|
||||
match = re.match(r'^([^"\' ]+|["\'][^"\']+["\']) (.*)$', message.args)
|
||||
group = match.group(1).strip('\'"')
|
||||
title = match.group(2).strip('\'"')
|
||||
|
||||
await message.chat.message(f'Groep: {group}\nTitel: {title}')
|
||||
|
||||
|
||||
@BOT.command('actie')
|
||||
async def cmd_actie(message):
|
||||
if message.chat.type == 'private':
|
||||
await message.chat.message(
|
||||
'Deze functie werkt alleen in commissiechats.')
|
||||
return
|
||||
|
||||
group_id = VIA_GROUPS.get(message.chat.id)
|
||||
if not group_id:
|
||||
await message.chat.message(
|
||||
'pimpy is nog niet ingeschakeld voor deze groep :/')
|
||||
return
|
||||
|
||||
match = re.match(r'^([^:]+): (.*)$', message.args)
|
||||
if not match:
|
||||
match = re.match(r'^([^ ]+) (.*)$', message.args)
|
||||
if match:
|
||||
owner = match.group(1)
|
||||
title = match.group(2)
|
||||
await message.chat.message(
|
||||
f'Incorrecte syntax. Misschien bedoelde je /actie {owner}: {title}?')
|
||||
else:
|
||||
await message.chat.message(
|
||||
f'Incorrecte syntax. Probeer eens /actie [naam]: [titel].')
|
||||
|
||||
return
|
||||
|
||||
task = await api.add_group_task(group_id, match.group(1), match.group(2))
|
||||
msg, reply_markup = messages.task_message(task, None, True)
|
||||
task_code = baas32.encode(task['id'])
|
||||
msg = f'Taak <code>[{task_code}]</code> aangemaakt!\n\n' + msg
|
||||
|
||||
await message.chat.message(msg, parse_mode='HTML',
|
||||
reply_markup=json.dumps(reply_markup),
|
||||
disable_web_page_preview=True)
|
||||
|
||||
|
||||
async def callback_status(query, _, args):
|
||||
token = USER_TOKENS.get(query.from_user.id)
|
||||
if not token:
|
||||
msg = messages.stranger_message(message.from_user.first_name)
|
||||
await message.chat.message(msg)
|
||||
return
|
||||
|
||||
status, task_id = args
|
||||
task_id = int(task_id)
|
||||
|
||||
if query.message.chat.type == 'private':
|
||||
await api.set_task_status(token, task_id, status)
|
||||
task = await api.get_task(token, task_id)
|
||||
else:
|
||||
group_id = VIA_GROUPS.get(query.message.chat.id)
|
||||
if not group_id:
|
||||
return
|
||||
|
||||
await api.set_group_task_status(token, group_id, task_id, status)
|
||||
task = await api.get_group_task(token, group_id, task_id)
|
||||
|
||||
|
||||
msg, reply_markup = messages.task_message(task, False)
|
||||
await query.message.edit(msg, parse_mode='HTML',
|
||||
reply_markup=json.dumps(reply_markup),
|
||||
disable_web_page_preview=True)
|
||||
await query.answer()
|
||||
|
||||
|
||||
async def callback_tasks(query, _, args):
|
||||
token = USER_TOKENS.get(query.from_user.id)
|
||||
if not token:
|
||||
msg = messages.stranger_message(message.from_user.first_name)
|
||||
await message.chat.message(msg)
|
||||
return
|
||||
|
||||
group_id = VIA_GROUPS.get(query.message.chat.id)
|
||||
if not group_id:
|
||||
await query.answer()
|
||||
return
|
||||
|
||||
user_id = int(args[0])
|
||||
user_name = ' '.join(args[1:])
|
||||
|
||||
tasks = await api.get_group_user_tasks(token, group_id, user_id)
|
||||
print(json.dumps(tasks, indent=4))
|
||||
msg = messages.tasks_message(tasks, True, user_name)
|
||||
await query.message.chat.message(msg, parse_mode='HTML')
|
||||
|
||||
|
||||
CALLBACK_HANDLERS = {
|
||||
'status': callback_status,
|
||||
'tasks': callback_tasks
|
||||
}
|
||||
|
||||
@BOT.callback
|
||||
async def callback(query):
|
||||
command, *args = query.data.split(' ')
|
||||
handler = CALLBACK_HANDLERS.get(command)
|
||||
if handler:
|
||||
await handler(query, command, args)
|
||||
|
||||
while True:
|
||||
try:
|
||||
BOT.run()
|
||||
except KeyboardInterrupt:
|
||||
print('\nhee doei hè')
|
||||
break
|
||||
except:
|
||||
pass
|
153
messages.py
Normal file
153
messages.py
Normal file
|
@ -0,0 +1,153 @@
|
|||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
import random
|
||||
import locale
|
||||
import baas32
|
||||
|
||||
locale.setlocale(locale.LC_TIME, 'nl_NL')
|
||||
|
||||
STATUS_EMOJI = {
|
||||
'Niet begonnen': '⏸',
|
||||
'Begonnen': '▶️',
|
||||
'Done': '✅',
|
||||
'Niet Done': '❌'
|
||||
}
|
||||
|
||||
def stranger_message(name):
|
||||
return f'''
|
||||
Heya, {name}! Cool dat je even komt kijken!
|
||||
|
||||
Voor nu is deze bot nog even afgesloten voor het publiek,
|
||||
maar kom later vooral een keertje terug.
|
||||
|
||||
Joe!'''
|
||||
|
||||
|
||||
def me_message(user_id):
|
||||
return f'''
|
||||
Dit weet ik over je:
|
||||
|
||||
svia.nl user_id: {user_id}
|
||||
'''
|
||||
|
||||
|
||||
def tasks_message(tasks, is_group=False, user_name=None):
|
||||
groups = defaultdict(list)
|
||||
for task in tasks:
|
||||
groups[task['group']['id']].append(task)
|
||||
|
||||
if not user_name:
|
||||
user_name = 'Je'
|
||||
else:
|
||||
user_name += '\'s'
|
||||
|
||||
if is_group:
|
||||
msg = f'<strong>{user_name} taken voor deze groep:</strong>\n\n'
|
||||
else:
|
||||
msg = f'<strong>{user_name} taken:</strong>\n\n'
|
||||
|
||||
for _, group_tasks in groups.items():
|
||||
if not group_tasks:
|
||||
continue
|
||||
|
||||
group_name = group_tasks[0]['group']['name'] if not is_group else None
|
||||
msg += taskset_message(group_name, group_tasks)
|
||||
|
||||
random_task = baas32.encode(random.choice(tasks)['id'])
|
||||
msg += f'Gebruik /task <task_id> voor meer informatie. ' \
|
||||
f'Bijvoorbeeld: /task {random_task}'
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
def taskset_message(name, tasks):
|
||||
msg = f'<strong>{name}:</strong>\n' if name else ''
|
||||
for task in tasks:
|
||||
task_code = baas32.encode(task['id'])
|
||||
emoji = STATUS_EMOJI[task['status']]
|
||||
if len(task['users']) == 2:
|
||||
emoji += ' 👨👦'
|
||||
elif len(task['users']) == 3:
|
||||
emoji += ' 👨👧👦'
|
||||
elif len(task['users']) > 3:
|
||||
emoji += ' 👨👩👧👧'
|
||||
|
||||
msg += f'• <code>[{task_code}]</code> ' \
|
||||
f'{emoji} {task["title"].strip()}'
|
||||
|
||||
msg += '\n'
|
||||
|
||||
msg += '\n'
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
def task_message(task, is_group):
|
||||
task_code = baas32.encode(task['id'])
|
||||
msg = f'<code>[{task_code}]</code> <strong>{task["title"]}</strong>\n'
|
||||
|
||||
timestamp = datetime.strptime(task["timestamp"], "%Y-%m-%dT%H:%M:%S")
|
||||
msg += f'<em>{timestamp.strftime("%d %B %Y, %H:%M")}</em>\n\n'
|
||||
|
||||
# Print the task group
|
||||
msg += f'<strong>Groep:</strong> {task["group"]["name"]}\n'
|
||||
|
||||
# Print the task state
|
||||
msg += f'<strong>Status:</strong> {task["status"]}\n'
|
||||
|
||||
# Print task owner(s)
|
||||
users = task['users']
|
||||
if not users:
|
||||
msg += f'<em>Geen eigenaren</em>\n'
|
||||
elif len(users) == 1:
|
||||
msg += f'<strong>Eigenaar:</strong> {users[0]["name"]}\n'
|
||||
elif 1 < len(users) <= 2:
|
||||
msg += f'<strong>Eigenaren:</strong> ' \
|
||||
f'{users[0]["name"]} en {users[1]["name"]}\n'
|
||||
else:
|
||||
msg += '\n<strong>Eigenaren:</strong>\n'
|
||||
for user in task['users']:
|
||||
msg += f'• {user["name"]}\n'
|
||||
msg += '\n'
|
||||
|
||||
# Print the description, if available
|
||||
try:
|
||||
msg += f'<strong>Beschrijving:</strong>\n{task["content"]}\n\n'
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# Print the minute URL, if available
|
||||
try:
|
||||
minute = task['minute']
|
||||
minute_url = f'http://svia.nl/pimpy/minutes/single/{minute["id"]}/'
|
||||
minute_url += str(minute['line']) if 'line' in minute else ''
|
||||
|
||||
msg += f'<a href="{minute_url}">Bijbehorende notulen</a>\n'
|
||||
except KeyError:
|
||||
msg += f'<em>Geen bijbehorende notulen</em>\n'
|
||||
|
||||
keyboard = []
|
||||
if task['status'] != 'Niet begonnen':
|
||||
keyboard.append({
|
||||
'text': '⏸ Niet begonnen',
|
||||
'callback_data': f'status unstarted {task["id"]}'
|
||||
})
|
||||
if task['status'] != 'Begonnen':
|
||||
keyboard.append({
|
||||
'text': '▶️ Begonnen',
|
||||
'callback_data': f'status started {task["id"]}'
|
||||
})
|
||||
if task['status'] != 'Done':
|
||||
keyboard.append({
|
||||
'text': '✅ Done',
|
||||
'callback_data': f'status done {task["id"]}'
|
||||
})
|
||||
if task['status'] != 'Niet Done':
|
||||
keyboard.append({
|
||||
'text': '❌ Niet Done',
|
||||
'callback_data': f'status notdone {task["id"]}'
|
||||
})
|
||||
|
||||
reply_markup = {'inline_keyboard': [keyboard]}
|
||||
return msg, reply_markup
|
6
requirements.txt
Normal file
6
requirements.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
aiohttp==2.3.2
|
||||
async-timeout==2.0.0
|
||||
baas32==0.3.2
|
||||
chardet==3.0.4
|
||||
multidict==3.3.2
|
||||
yarl==0.13.0
|
1
telewalrus
Submodule
1
telewalrus
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 244c7ed6e6658dfb09dbae45446e132f9bc144c5
|
Loading…
Reference in a new issue