reorganise plugins and add date arg to journal cmd
This commit is contained in:
parent
24fa84dfef
commit
8d3e24f443
|
@ -118,6 +118,17 @@ category = "main"
|
|||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "feedparser"
|
||||
version = "6.0.10"
|
||||
description = "Universal feed parser, handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
sgmllib3k = "*"
|
||||
|
||||
[[package]]
|
||||
name = "flask"
|
||||
version = "2.1.1"
|
||||
|
@ -174,6 +185,29 @@ category = "main"
|
|||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "pendulum"
|
||||
version = "2.1.2"
|
||||
description = "Python datetimes made easy"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[package.dependencies]
|
||||
python-dateutil = ">=2.6,<3.0"
|
||||
pytzdata = ">=2020.1"
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.8.2"
|
||||
description = "Extensions to the standard Python datetime module"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.5"
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "0.20.0"
|
||||
|
@ -224,6 +258,14 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
|||
[package.dependencies]
|
||||
tzdata = {version = "*", markers = "python_version >= \"3.6\""}
|
||||
|
||||
[[package]]
|
||||
name = "pytzdata"
|
||||
version = "2020.1"
|
||||
description = "The Olson timezone database for Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.27.1"
|
||||
|
@ -242,6 +284,14 @@ urllib3 = ">=1.21.1,<1.27"
|
|||
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
||||
|
||||
[[package]]
|
||||
name = "sgmllib3k"
|
||||
version = "1.0.0"
|
||||
description = "Py3k port of sgmllib."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
|
@ -329,7 +379,7 @@ watchdog = ["watchdog"]
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "aaeab26d780c5079dc962e4c086cbde44389716a5c642c36bedfaeaea3fd7621"
|
||||
content-hash = "2e482c8851ca14e2a5a862af70863b9875e65584bbaf49d048fcc446091d92ad"
|
||||
|
||||
[metadata.files]
|
||||
apscheduler = [
|
||||
|
@ -371,6 +421,7 @@ dokuwiki = [
|
|||
{file = "dokuwiki-1.3.2-py3-none-any.whl", hash = "sha256:0720b9fef9cbcb01879b2723b65a5f5bef63a68e9bfc362b09b2e3d9ba7cdedb"},
|
||||
{file = "dokuwiki-1.3.2.tar.gz", hash = "sha256:af01bf878da69d915bf15a003cd9ef0d364a706a87acf74d00c6bb337636d350"},
|
||||
]
|
||||
feedparser = []
|
||||
flask = [
|
||||
{file = "Flask-2.1.1-py3-none-any.whl", hash = "sha256:8a4cf32d904cf5621db9f0c9fbcd7efabf3003f22a04e4d0ce790c7137ec5264"},
|
||||
{file = "Flask-2.1.1.tar.gz", hash = "sha256:a8c9bd3e558ec99646d177a9739c41df1ded0629480b4c8d2975412f3c9519c8"},
|
||||
|
@ -429,6 +480,8 @@ markupsafe = [
|
|||
{file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"},
|
||||
{file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"},
|
||||
]
|
||||
pendulum = []
|
||||
python-dateutil = []
|
||||
python-dotenv = [
|
||||
{file = "python-dotenv-0.20.0.tar.gz", hash = "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f"},
|
||||
{file = "python_dotenv-0.20.0-py3-none-any.whl", hash = "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938"},
|
||||
|
@ -445,10 +498,12 @@ pytz-deprecation-shim = [
|
|||
{file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"},
|
||||
{file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"},
|
||||
]
|
||||
pytzdata = []
|
||||
requests = [
|
||||
{file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
|
||||
{file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
|
||||
]
|
||||
sgmllib3k = []
|
||||
six = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
|
|
|
@ -17,6 +17,8 @@ python-telegram-bot = "^13.11"
|
|||
todoist-api-python = "^1.1.1"
|
||||
python-dotenv = "^0.20.0"
|
||||
bs4 = "^0.0.1"
|
||||
feedparser = "^6.0.10"
|
||||
pendulum = "^2.1.2"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
@ -21,7 +21,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
@ -31,10 +31,38 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
"source": [
|
||||
"r = session.get(\"https://wiki.jamesravey.me/api/books\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"1 Microcosm\n",
|
||||
"2 PhD\n",
|
||||
"4 House Stuff\n",
|
||||
"5 Personal Stuff\n",
|
||||
"7 🌱 Digital Garden Seed Propagator\n",
|
||||
"8 ML and Data Science\n",
|
||||
"9 Software Engineering\n",
|
||||
"10 Devices and Tech\n",
|
||||
"11 Journal\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for book in r.json()['data']:\n",
|
||||
" print(book['id'], book['name'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
|
@ -45,28 +73,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"# Bookmarks\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"[example](http://www.google.com)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(r.json()['markdown'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"execution_count": 28,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
|
@ -75,18 +82,12 @@
|
|||
"<Response [200]>"
|
||||
]
|
||||
},
|
||||
"execution_count": 26,
|
||||
"execution_count": 28,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"r = session.get(\"https://wiki.jamesravey.me/api/pages/58\")\n",
|
||||
"\n",
|
||||
"session.put(\"https://wiki.jamesravey.me/api/pages/58\", json={\n",
|
||||
" \"markdown\": r.json()['markdown'] + \"\\n\\n - [example](http://www.google.com)\"\n",
|
||||
"})"
|
||||
]
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
from collections import defaultdict
|
||||
import dotenv
|
||||
import os
|
||||
import dokuwiki
|
||||
import requests
|
||||
import io
|
||||
import tempfile
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from flask import Flask
|
||||
|
||||
|
@ -10,11 +13,13 @@ from telegram import Update, PhotoSize, File, BotCommand
|
|||
from telegram.ext import Updater, MessageHandler, CommandHandler, Filters, CallbackContext, ConversationHandler
|
||||
|
||||
|
||||
|
||||
app = Flask("rafael")
|
||||
RAFAEL_UA = "RAFAEL/0.1"
|
||||
|
||||
|
||||
from rafael.bookmarks import RafaelBookmarkPlugin
|
||||
from rafael.journal import JournalPlugin
|
||||
|
||||
def handle(update: Update, context: CallbackContext):
|
||||
|
||||
|
@ -40,39 +45,7 @@ def handle(update: Update, context: CallbackContext):
|
|||
|
||||
update.message.reply_text("done m8")
|
||||
|
||||
ADDING = 0
|
||||
|
||||
class JournalPlugin():
|
||||
|
||||
def init_convo(self, update: Update, context: CallbackContext):
|
||||
update.message.reply_text("Add photos for your journal")
|
||||
return ADDING
|
||||
|
||||
def handle_file(self, update: Update, context: CallbackContext):
|
||||
update.message.reply_text("Got your update m8")
|
||||
return ADDING
|
||||
|
||||
def done_handler(self, update: Update, context: CallbackContext):
|
||||
update.message.reply_text("Great storing your images...")
|
||||
return ConversationHandler.END
|
||||
|
||||
def invalid_handler(self, update: Update, context: CallbackContext):
|
||||
update.message.reply_text("Sorry, I don't understand. Please upload photos or type 'Done' to exit")
|
||||
|
||||
def register(self, updater: Updater):
|
||||
|
||||
updater.dispatcher.add_handler(ConversationHandler(
|
||||
entry_points=[
|
||||
CommandHandler("journal", self.init_convo)
|
||||
],
|
||||
states={
|
||||
ADDING: [MessageHandler(Filters.attachment, self.handle_file)]
|
||||
},
|
||||
fallbacks=[
|
||||
MessageHandler(Filters.regex("^Done$"), self.done_handler),
|
||||
MessageHandler(Filters.all, self.invalid_handler)
|
||||
]
|
||||
))
|
||||
|
||||
class RafaelBot:
|
||||
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
import os
|
||||
import io
|
||||
|
||||
import pendulum
|
||||
from datetime import datetime
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
from telegram import Update, PhotoSize, File, BotCommand
|
||||
from telegram.ext import Updater, MessageHandler, CommandHandler, Filters, CallbackContext, ConversationHandler
|
||||
|
||||
from rafael.util.bookstack import BookstackClient, Page
|
||||
|
||||
|
||||
SELECT_DATE, ADDING = range(2)
|
||||
|
||||
class JournalPlugin():
|
||||
|
||||
|
||||
def init_convo(self, update: Update, context: CallbackContext):
|
||||
|
||||
print("Args:", context.args)
|
||||
|
||||
journal_date = datetime.now()
|
||||
|
||||
if len(context.args) > 0 :
|
||||
try:
|
||||
if context.args[0] == "yesterday":
|
||||
journal_date = pendulum.yesterday()
|
||||
|
||||
elif context.args[0] == "tomorrow":
|
||||
journal_date = pendulum.tomorrow()
|
||||
|
||||
else:
|
||||
journal_date = pendulum.parse(context.args[0])
|
||||
except:
|
||||
update.message.reply_text("""If you're passing a journal date you must use YYYY/MM/DD
|
||||
You can also use 'yesterday' or 'tomorrow'""")
|
||||
return
|
||||
|
||||
|
||||
self.api = BookstackClient(os.getenv('BOOKSTACK_URL'), os.getenv('BOOKSTACK_TOKEN_ID'), os.getenv('BOOKMARK_TOKEN_SECRET'))
|
||||
|
||||
chapter_name = journal_date.strftime("%B %Y")
|
||||
|
||||
|
||||
page_name = journal_date.strftime("%Y-%m-%d")
|
||||
|
||||
chapters = self.api.get_chapters(filters={"name":chapter_name, "book_id": os.getenv('BOOKSTACK_JOURNAL_BOOK')})['data']
|
||||
|
||||
chapter = chapters[0]
|
||||
|
||||
pages = self.api.get_pages(filters={"name": page_name, "chapter_id": chapter['id']})['data']
|
||||
|
||||
if len(pages)<1:
|
||||
print("Create Page")
|
||||
|
||||
page = self.api.create_page(Page(chapter_id=chapter['id'], name=page_name, markdown=f"Journal for {page_name}"))
|
||||
|
||||
context.chat_data['page_id'] = page['id']
|
||||
|
||||
print(page)
|
||||
else:
|
||||
print("Update Page")
|
||||
|
||||
context.chat_data['page_id'] = pages[0]['id']
|
||||
|
||||
print(f"Use page {context.chat_data['page_id']}")
|
||||
|
||||
|
||||
|
||||
update.message.reply_text("Journal Mode On: Add text and files")
|
||||
return ADDING
|
||||
|
||||
def handle_md_update(self, update: Update, context: CallbackContext):
|
||||
|
||||
page = self.api.get_page(context.chat_data['page_id'])
|
||||
|
||||
content = page['markdown'] + f"\n\n----------\n\n{update.message.text_markdown}"
|
||||
|
||||
self.api.update_page(Page(id=page['id'], markdown=content))
|
||||
|
||||
update.message.reply_text(f"Added text to journal page {page['id']}")
|
||||
|
||||
|
||||
def handle_file(self, update: Update, context: CallbackContext):
|
||||
|
||||
if update.message.document is not None:
|
||||
|
||||
file_meta = update.message.document.get_file()
|
||||
file_name = update.message.document.file_name
|
||||
|
||||
elif update.message.effective_attachment:
|
||||
|
||||
versions = defaultdict(lambda:[])
|
||||
|
||||
biggest = 0
|
||||
biggest_i = -1
|
||||
|
||||
for i, att in enumerate(update.message.effective_attachment):
|
||||
|
||||
if isinstance(att, PhotoSize):
|
||||
|
||||
if att.width > biggest:
|
||||
biggest = att.width
|
||||
biggest_i = i
|
||||
|
||||
|
||||
file_meta = update.message.effective_attachment[i].get_file()
|
||||
file_name = update.message.effective_attachment[i].get_file().file_id
|
||||
|
||||
|
||||
buf = io.BytesIO(file_meta.download_as_bytearray())
|
||||
|
||||
r = self.api.add_attachment_from_upload(context.chat_data['page_id'], file_name, buf)
|
||||
|
||||
page = self.api.get_page(context.chat_data['page_id'])
|
||||
|
||||
content = page['markdown'] + "\n\n-------\n\n" + f"![{r['name']}]({self.api.wiki_url}/attachments/{r['id']}?open=true)"
|
||||
|
||||
self.api.update_page(Page(id=page['id'], markdown=content))
|
||||
|
||||
update.message.reply_text(f"Added file attachment id={r['id']} name={r['name']}")
|
||||
|
||||
|
||||
|
||||
return ADDING
|
||||
|
||||
def done_handler(self, update: Update, context: CallbackContext):
|
||||
update.message.reply_text("Journal mode off")
|
||||
return ConversationHandler.END
|
||||
|
||||
def invalid_handler(self, update: Update, context: CallbackContext):
|
||||
update.message.reply_text("Sorry, I don't understand. Please upload photos or type 'Done' to exit")
|
||||
|
||||
def register(self, updater: Updater):
|
||||
|
||||
updater.dispatcher.add_handler(ConversationHandler(
|
||||
entry_points=[
|
||||
CommandHandler("journal", self.init_convo)
|
||||
],
|
||||
states={
|
||||
ADDING: [
|
||||
MessageHandler(Filters.attachment, self.handle_file),
|
||||
|
||||
MessageHandler(Filters.regex("^Done$"), self.done_handler),
|
||||
MessageHandler(Filters.all, self.handle_md_update),
|
||||
]
|
||||
},
|
||||
fallbacks=[
|
||||
MessageHandler(Filters.regex("^Done$"), self.done_handler),
|
||||
|
||||
]
|
||||
))
|
|
@ -0,0 +1,88 @@
|
|||
from typing import BinaryIO, List, Optional
|
||||
import requests
|
||||
import dataclasses
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Tag:
|
||||
name: str
|
||||
value: Optional[str]
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Page:
|
||||
|
||||
id: Optional[int] = dataclasses.field(default=None)
|
||||
book_id: Optional[int] = dataclasses.field(default=None)
|
||||
chapter_id: Optional[int] = dataclasses.field(default=None)
|
||||
name: Optional[str] = dataclasses.field(default=None)
|
||||
html: Optional[str] = dataclasses.field(default=None)
|
||||
markdown: Optional[str] = dataclasses.field(default=None)
|
||||
tags: List[Tag] = dataclasses.field(default=None)
|
||||
|
||||
class BookstackClient:
|
||||
|
||||
def __init__(self, url, token_id, token_secret):
|
||||
|
||||
self.wiki_url = url
|
||||
self.token_id = token_id
|
||||
self.token_secret = token_secret
|
||||
|
||||
|
||||
self.session = requests.Session()
|
||||
self.session.headers = {'Authorization': f"Token {self.token_id}:{self.token_secret}"}
|
||||
|
||||
|
||||
def _get(self, datatype, filters={}):
|
||||
|
||||
query = {}
|
||||
for key,value in filters.items():
|
||||
query[f'filter[{key}]']=value
|
||||
|
||||
|
||||
r = self.session.get(self.wiki_url + f"/api/{datatype}", params=query)
|
||||
|
||||
return r.json()
|
||||
|
||||
def add_attachment_from_url(self, page_id: int, name: str, link: str):
|
||||
|
||||
r = self.session.post(self.wiki_url + f"/api/attachments",
|
||||
data={'name':name, 'uploaded_to':page_id, 'link':link}
|
||||
)
|
||||
|
||||
return r.json()
|
||||
|
||||
def add_attachment_from_upload(self, page_id: int, name: str, file: BinaryIO):
|
||||
|
||||
r = self.session.post(self.wiki_url + f"/api/attachments",
|
||||
data={'name':name, 'uploaded_to':page_id},
|
||||
files={'file': file}
|
||||
)
|
||||
|
||||
return r.json()
|
||||
|
||||
|
||||
|
||||
def get_pages(self, filters={}):
|
||||
return self._get('pages', filters)
|
||||
|
||||
def get_page(self, id: int):
|
||||
r = self.session.get(self.wiki_url + f"/api/pages/{id}")
|
||||
return r.json()
|
||||
|
||||
def create_page(self, page: Page):
|
||||
|
||||
r = self.session.post(self.wiki_url + "/api/pages", data=dataclasses.asdict(page) )
|
||||
return r.json()
|
||||
|
||||
def update_page(self, page: Page):
|
||||
r = self.session.put(self.wiki_url + f"/api/pages/{page.id}", data=dataclasses.asdict(page) )
|
||||
return r.json()
|
||||
|
||||
def get_chapters(self, filters={}):
|
||||
return self._get('chapters', filters)
|
||||
|
||||
def get_books(self, filters={}):
|
||||
return self._get('books', filters)
|
||||
|
||||
|
||||
def get_shelves(self, filters={}):
|
||||
return self._get('shelves', filters)
|
|
@ -0,0 +1,2 @@
|
|||
import feedparser
|
||||
|
Loading…
Reference in New Issue