initial framework
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								.bot_storage/db.sqlite
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.bot_storage/db.sqlite
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										26
									
								
								.drone.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								.drone.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | kind: pipeline | ||||||
|  | type: kubernetes | ||||||
|  | name: docker-build | ||||||
|  |  | ||||||
|  | node_selector: | ||||||
|  |   kubernetes.io/arch: arm64 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | steps: | ||||||
|  | - name: docker   | ||||||
|  |   image: plugins/docker | ||||||
|  |   settings: | ||||||
|  |     username:  | ||||||
|  |       from_secret: docker_uname | ||||||
|  |     password: | ||||||
|  |       from_secret: docker_pw | ||||||
|  |  | ||||||
|  |     repo: mollre/journal-bot | ||||||
|  |     tags: latest | ||||||
|  |  | ||||||
|  |  | ||||||
|  | trigger: | ||||||
|  |   branch: | ||||||
|  |   - main | ||||||
|  |   event: | ||||||
|  |   - push | ||||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,7 @@ | |||||||
|  | # Secrets | ||||||
|  | dev.env | ||||||
|  | secret.yaml | ||||||
|  |  | ||||||
| # ---> Python | # ---> Python | ||||||
| # Byte-compiled / optimized / DLL files | # Byte-compiled / optimized / DLL files | ||||||
| __pycache__/ | __pycache__/ | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | FROM python:3.10 | ||||||
|  | ENV dockerized=true | ||||||
|  |  | ||||||
|  | WORKDIR /app | ||||||
|  |  | ||||||
|  | COPY Pipfile Pipfile.lock ./ | ||||||
|  |  | ||||||
|  | RUN pip install pipenv && pipenv install --system --deploy | ||||||
|  |  | ||||||
|  | COPY bot . | ||||||
|  |  | ||||||
|  | CMD ["python", "main.py"] | ||||||
							
								
								
									
										7
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | CURRENT_DIR := $(shell pwd) | ||||||
|  | DOTENV := ${CURRENT_DIR}/dev.env | ||||||
|  | PIPENV_CMD_PREFIX := PIPENV_DOTENV_LOCATION=${DOTENV} pipenv run | ||||||
|  |  | ||||||
|  |  | ||||||
|  | run: | ||||||
|  | 	${PIPENV_CMD_PREFIX} python bot/main.py | ||||||
							
								
								
									
										13
									
								
								Pipfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Pipfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | [[source]] | ||||||
|  | url = "https://pypi.org/simple" | ||||||
|  | verify_ssl = true | ||||||
|  | name = "pypi" | ||||||
|  |  | ||||||
|  | [packages] | ||||||
|  | python-telegram-bot = "*" | ||||||
|  | peewee = "*" | ||||||
|  |  | ||||||
|  | [dev-packages] | ||||||
|  |  | ||||||
|  | [requires] | ||||||
|  | python_version = "3.10" | ||||||
							
								
								
									
										101
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | { | ||||||
|  |     "_meta": { | ||||||
|  |         "hash": { | ||||||
|  |             "sha256": "b71137ebde2ce3e6bcde400dad601555ccee09d26530c8e928d76d49aae43fee" | ||||||
|  |         }, | ||||||
|  |         "pipfile-spec": 6, | ||||||
|  |         "requires": { | ||||||
|  |             "python_version": "3.10" | ||||||
|  |         }, | ||||||
|  |         "sources": [ | ||||||
|  |             { | ||||||
|  |                 "name": "pypi", | ||||||
|  |                 "url": "https://pypi.org/simple", | ||||||
|  |                 "verify_ssl": true | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     "default": { | ||||||
|  |         "anyio": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421", | ||||||
|  |                 "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3" | ||||||
|  |             ], | ||||||
|  |             "markers": "python_full_version >= '3.6.2'", | ||||||
|  |             "version": "==3.6.2" | ||||||
|  |         }, | ||||||
|  |         "certifi": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", | ||||||
|  |                 "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" | ||||||
|  |             ], | ||||||
|  |             "markers": "python_version >= '3.6'", | ||||||
|  |             "version": "==2022.12.7" | ||||||
|  |         }, | ||||||
|  |         "h11": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", | ||||||
|  |                 "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" | ||||||
|  |             ], | ||||||
|  |             "markers": "python_version >= '3.7'", | ||||||
|  |             "version": "==0.14.0" | ||||||
|  |         }, | ||||||
|  |         "httpcore": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb", | ||||||
|  |                 "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0" | ||||||
|  |             ], | ||||||
|  |             "markers": "python_version >= '3.7'", | ||||||
|  |             "version": "==0.16.3" | ||||||
|  |         }, | ||||||
|  |         "httpx": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9", | ||||||
|  |                 "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6" | ||||||
|  |             ], | ||||||
|  |             "markers": "python_version >= '3.7'", | ||||||
|  |             "version": "==0.23.3" | ||||||
|  |         }, | ||||||
|  |         "idna": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", | ||||||
|  |                 "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" | ||||||
|  |             ], | ||||||
|  |             "version": "==3.4" | ||||||
|  |         }, | ||||||
|  |         "peewee": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:1800c0a04962ee99d161c07f5a12fc49549caf5cfcda426a9103e34e37f854ba" | ||||||
|  |             ], | ||||||
|  |             "index": "pypi", | ||||||
|  |             "version": "==3.16.0" | ||||||
|  |         }, | ||||||
|  |         "python-telegram-bot": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:4d1d4b643ce158aa17a0987b84005eaf25fe0ce8b38fd234099594985611c198", | ||||||
|  |                 "sha256:d0aa53e1f06d7cb7919cc0e2d6c81a02d968fc29921aeaa962edd1efb816a9bd" | ||||||
|  |             ], | ||||||
|  |             "index": "pypi", | ||||||
|  |             "version": "==20.2" | ||||||
|  |         }, | ||||||
|  |         "rfc3986": { | ||||||
|  |             "extras": [ | ||||||
|  |                 "idna2008" | ||||||
|  |             ], | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835", | ||||||
|  |                 "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97" | ||||||
|  |             ], | ||||||
|  |             "version": "==1.5.0" | ||||||
|  |         }, | ||||||
|  |         "sniffio": { | ||||||
|  |             "hashes": [ | ||||||
|  |                 "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101", | ||||||
|  |                 "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384" | ||||||
|  |             ], | ||||||
|  |             "markers": "python_version >= '3.7'", | ||||||
|  |             "version": "==1.3.0" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     "develop": {} | ||||||
|  | } | ||||||
							
								
								
									
										76
									
								
								bot/commands/journal.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								bot/commands/journal.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | import datetime | ||||||
|  |  | ||||||
|  | from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, filters, CallbackQueryHandler, CallbackContext | ||||||
|  | from telegram import InlineKeyboardButton, InlineKeyboardMarkup | ||||||
|  | DATE_CHOICE, DATE_ENTRY, CONTENT = range(3) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class JournalHandler: | ||||||
|  |     def __init__(self, entry_string, models): | ||||||
|  |         self.models = models | ||||||
|  |  | ||||||
|  |         self.handler = ConversationHandler( | ||||||
|  |             entry_points=[CommandHandler(entry_string, self.start)], | ||||||
|  |             states={ | ||||||
|  |                 DATE_CHOICE: [ | ||||||
|  |                     CallbackQueryHandler(self.date_choice), | ||||||
|  |                     ], | ||||||
|  |                 DATE_ENTRY: [ | ||||||
|  |                     MessageHandler(filters.TEXT, self.date_entry), | ||||||
|  |                     ], | ||||||
|  |                 CONTENT: [ | ||||||
|  |                     MessageHandler(filters.TEXT, self.content_text), | ||||||
|  |                     MessageHandler(filters.ATTACHMENT, self.content_media), | ||||||
|  |                     ], | ||||||
|  |             }, | ||||||
|  |             fallbacks=[], | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         self.current_model = None | ||||||
|  |  | ||||||
|  |     async def start(self, update, context): | ||||||
|  |         """Send a message when the command /start is issued.""" | ||||||
|  |  | ||||||
|  |         options = [ | ||||||
|  |             InlineKeyboardButton("Today", callback_data="today"), | ||||||
|  |             InlineKeyboardButton("Yesterday", callback_data="yesterday"), | ||||||
|  |             InlineKeyboardButton("Custom date", callback_data="custom"), | ||||||
|  |         ] | ||||||
|  |         keyboard = InlineKeyboardMarkup([options]) | ||||||
|  |         await update.message.reply_text("Please choose an option for the entry:", reply_markup=keyboard) | ||||||
|  |         return DATE_CHOICE | ||||||
|  |  | ||||||
|  |     async def date_choice(self, update, context): | ||||||
|  |         query = update.callback_query | ||||||
|  |         query.answer() | ||||||
|  |         if query.data == "today" or query.data == "yesterday": | ||||||
|  |             date = datetime.datetime.now().date() if query.data == "today" else datetime.datetime.now().date() - datetime.timedelta(days=1) | ||||||
|  |             self.current_model = self.models.JournalEntry( | ||||||
|  |                 date = date | ||||||
|  |             ) | ||||||
|  |             return CONTENT | ||||||
|  |         else: | ||||||
|  |             await query.edit_message_text(text="Please enter the date in the format DDMMYYYY") | ||||||
|  |             return DATE_ENTRY | ||||||
|  |  | ||||||
|  |     async def date_entry(self, update, context): | ||||||
|  |         # create an inline keyboard with the option today and yesterday and custom | ||||||
|  |         # date | ||||||
|  |         date = update.message.text | ||||||
|  |         try: | ||||||
|  |             date = datetime.datetime.strptime(date, "%d%m%Y").date() | ||||||
|  |             self.current_model = self.models.JournalEntry( | ||||||
|  |                 date = date | ||||||
|  |             ) | ||||||
|  |         except ValueError: | ||||||
|  |             await update.message.reply_text("Please enter the date in the format DDMMYYYY") | ||||||
|  |             return DATE_ENTRY | ||||||
|  |  | ||||||
|  |         await update.message.reply_text("Please enter the content for the entry") | ||||||
|  |         return CONTENT | ||||||
|  |  | ||||||
|  |     async def content_text(self, update, context): | ||||||
|  |      | ||||||
|  |         return  | ||||||
|  |     async def content_media(self, update, context): | ||||||
|  |         return   | ||||||
							
								
								
									
										35
									
								
								bot/main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								bot/main.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | import os | ||||||
|  | from telegram.ext import Application | ||||||
|  | import logging | ||||||
|  |  | ||||||
|  | from commands import journal | ||||||
|  | import models | ||||||
|  |  | ||||||
|  | logging.basicConfig( | ||||||
|  |     format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | logger = logging.getLogger(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def main() -> None: | ||||||
|  |     """Run the bot.""" | ||||||
|  |  | ||||||
|  |     token = os.getenv("BOT_TOKEN") | ||||||
|  |     db_path = os.getenv("DB_PATH") | ||||||
|  |     models.set_db(db_path) | ||||||
|  |     application = Application.builder().token(token).build() | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     application.add_handler(journal.JournalHandler("journal", models).handler) | ||||||
|  |     # application.add_handler(CommandHandler("help", help_command)) | ||||||
|  |     # on non command i.e message - echo the message on Telegram | ||||||
|  |     # application.add_handler(InlineQueryHandler(inline_query)) | ||||||
|  |  | ||||||
|  |     # Run the bot until the user presses Ctrl-C | ||||||
|  |     application.run_polling() | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     main() | ||||||
							
								
								
									
										35
									
								
								bot/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								bot/models.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | from peewee import * | ||||||
|  | from pathlib import Path | ||||||
|  |  | ||||||
|  | db = DatabaseProxy() | ||||||
|  |  | ||||||
|  | class BaseModel(Model): | ||||||
|  |     class Meta: | ||||||
|  |         database = db | ||||||
|  |         db_table = 'journal' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # model for a single journal entry | ||||||
|  | class JournalEntry(BaseModel): | ||||||
|  |     # the date of the entry | ||||||
|  |     date = DateField() | ||||||
|  |     # the text of the entry | ||||||
|  |     text = TextField() | ||||||
|  |     media_path = TextField() | ||||||
|  |     author = TextField() | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     def media(self): | ||||||
|  |         return Path(self.media_path).open('rb') | ||||||
|  |      | ||||||
|  |     @media.setter | ||||||
|  |     def media(self, media): | ||||||
|  |         self.media_path = Path(media).absolute() | ||||||
|  |         self.save() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def set_db(db_path): | ||||||
|  |     db.initialize(SqliteDatabase(db_path)) | ||||||
|  |     db.connect() | ||||||
|  |     db.create_tables([JournalEntry], safe=True) | ||||||
							
								
								
									
										0
									
								
								deployment/deployment.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								deployment/deployment.yaml
									
									
									
									
									
										Normal file
									
								
							
		Reference in New Issue
	
	Block a user