readme and docker-compose
This commit is contained in:
parent
4d85b32efd
commit
34f375989c
13
Dockerfile
13
Dockerfile
@ -0,0 +1,13 @@
|
||||
FROM python:3.10
|
||||
|
||||
RUN apt-get install libpq-dev -y
|
||||
|
||||
ADD requirements.txt requirements.txt
|
||||
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
ADD src /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT [ "gunicorn", "--chdir=/app/src", "--bond=127.0.0.1:8080", "main:app" ]
|
45
README.md
45
README.md
@ -0,0 +1,45 @@
|
||||
# JeDoIst клиент
|
||||
|
||||
## Что это?
|
||||
|
||||
- это клиент для телеграм-бота [JeDoIst](https://t.me/jedoist)
|
||||
|
||||
## Зачем вам это?
|
||||
|
||||
- [JeDoIst](https://t.me/jedoist) - это автоматизатор входящей очереди задач
|
||||
|
||||
Не так давно я прочитал книгу Максима Дорофеева "[Джедайские техники](https://t.me/bvn13_blog/108)", данный проект основан на идеях, описанных в данной книге.
|
||||
|
||||
## Какие идеи?
|
||||
|
||||
- каждый человек работает с задачами
|
||||
- чтобы быть успешным, нужно **правильно** работать со своими задачами
|
||||
- очередь входящий задач должна быть одна: должно быть одно место, куда складываются все входящие задачи
|
||||
- **работа** заключается в постоянной проработке и декомпозиции этой очереди по правилам, описанным в книге, по принципу "для того, чтобы обезьянке стало проще выполнять"
|
||||
|
||||
### Улучшения
|
||||
|
||||
- часто идеи приходят в совершенно неподходящий для записывания "от руки" время
|
||||
- хочется иметь инструмент, который послужит входящей очередью, в которую можно буквально **надиктовать** задачу
|
||||
- но очередь задач должна быть одна, поэтому...
|
||||
- голосовые записи должны быть расшифрованы и сложены в единую очередь
|
||||
|
||||
## Поэтому
|
||||
|
||||
- [JeDoIst](https://t.me/jedoist) является этой входящей очередью, в которую можно "надиктовать" свою идею или задачу
|
||||
- он бережно расшифрует голосовое сообщение и передаст его в callback-е на любой удаленный сервер
|
||||
- с одним ограничением: протокол диктует [JeDoIst](https://t.me/jedoist), и должна быть авторизация
|
||||
|
||||
### И поэтому...
|
||||
|
||||
- этот репозиторий предназначен для быстрого развертывания веб-сервера, в который будут отправляться ваши задачи
|
||||
|
||||
## Но!
|
||||
|
||||
- Вопрос: но где же опубликовать этот веб-сервер?
|
||||
- Ответ: на любом VPS
|
||||
- Вопрос: как сохраняются задачи?
|
||||
- Ответ: в одном файле в формате Markdown
|
||||
- Вопрос: файл на сервере, я работаю на ноутбуке - где логика?
|
||||
- Ответ: есть Synkthing, который позволит синхронизировать файл с задачми на сервере и на ноутбуке. И на смартфоне.
|
||||
|
@ -0,0 +1,19 @@
|
||||
version: '3.3'
|
||||
|
||||
networks:
|
||||
jedoist:
|
||||
external: true
|
||||
|
||||
services:
|
||||
|
||||
bot:
|
||||
# build: ./
|
||||
image: localhost:5001/jedoist-client:${APP_VERSION}
|
||||
environment:
|
||||
- TODO_PATH=/mnt/todo
|
||||
- TODO_FILE=${TODO_FILE}
|
||||
volumes:
|
||||
- ${TODO_PATH}:/mnt/todo
|
||||
restart: on-failure
|
||||
networks:
|
||||
- jedoist
|
69
src/main.py
69
src/main.py
@ -1,5 +1,41 @@
|
||||
import falcon
|
||||
import json
|
||||
import os
|
||||
|
||||
# https://falcon.readthedocs.io/en/stable/user/quickstart.html#learning-by-example
|
||||
|
||||
class AuthMiddleware:
|
||||
def process_request(self, req, resp):
|
||||
token = req.get_header('Authorization')
|
||||
account_id = req.get_header('Account-ID')
|
||||
|
||||
challenges = ['Token type="Fernet"']
|
||||
|
||||
if token is None:
|
||||
description = 'Please provide an auth token as part of the request.'
|
||||
|
||||
raise falcon.HTTPUnauthorized(
|
||||
title='Auth token required',
|
||||
description=description,
|
||||
challenges=challenges,
|
||||
href='http://docs.example.com/auth',
|
||||
)
|
||||
|
||||
if not self._token_is_valid(token, account_id):
|
||||
description = (
|
||||
'The provided auth token is not valid. '
|
||||
'Please request a new token and try again.'
|
||||
)
|
||||
|
||||
raise falcon.HTTPUnauthorized(
|
||||
title='Authentication required',
|
||||
description=description,
|
||||
challenges=challenges,
|
||||
href='http://docs.example.com/auth',
|
||||
)
|
||||
|
||||
def _token_is_valid(self, token, account_id):
|
||||
return os.environ["TOKEN"] # Suuuuuure it's valid...
|
||||
|
||||
|
||||
class RequireJSON:
|
||||
@ -17,6 +53,7 @@ class RequireJSON:
|
||||
href='http://docs.examples.com/api/json',
|
||||
)
|
||||
|
||||
|
||||
class JSONTranslator:
|
||||
# NOTE: Normally you would simply use req.media and resp.media for
|
||||
# this particular use case; this example serves only to illustrate
|
||||
@ -72,18 +109,46 @@ def max_body(limit):
|
||||
|
||||
return hook
|
||||
|
||||
########################################################################################################
|
||||
|
||||
class CreateTaskResource:
|
||||
|
||||
TODO_HEADER = '# ToDo'
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.__todo_path = "{0}/{1}".format(os.environ['TODO_PATH'], os.environ['TODO_FILE'])
|
||||
|
||||
def on_post(self, req, resp):
|
||||
task = req.context.doc['task']
|
||||
self.__create_task(task)
|
||||
quote = {
|
||||
'title': 'Получена задача',
|
||||
'description': req.context.doc['task']
|
||||
'description': task
|
||||
}
|
||||
|
||||
resp.media = quote
|
||||
|
||||
def __create_task(self, text: str) -> None:
|
||||
content = []
|
||||
section_found = False
|
||||
is_waiting_empty_line = False
|
||||
with open(self.__todo_path, 'r', encoding='UTF-8') as file:
|
||||
while line := file.readline():
|
||||
if section_found == False:
|
||||
if line.strip() == CreateTaskResource.TODO_HEADER:
|
||||
section_found = True
|
||||
is_waiting_empty_line = True
|
||||
content.append(line)
|
||||
if section_found and is_waiting_empty_line == True and line.strip() == '':
|
||||
content.append("- [ ] {0}\n".format(text))
|
||||
is_waiting_empty_line = False
|
||||
with open(self.__todo_path, 'w', encoding='utf-8') as file:
|
||||
file.writelines(content)
|
||||
|
||||
########################################################################################################
|
||||
|
||||
app = falcon.App(
|
||||
middleware=[
|
||||
AuthMiddleware(),
|
||||
RequireJSON(),
|
||||
JSONTranslator()
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user