Compare commits

...

97 Commits

Author SHA1 Message Date
b12eb62b41 [CI SKIP] Update mollre/journal-bot Docker tag to v1.0.68 2024-03-12 20:52:02 +00:00
f5c3d767c0 [CI SKIP] update 2024-03-12 20:50:54 +00:00
d8407bac65 Update renovate.json
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-12 20:41:31 +00:00
2f9d94406c fix syntax
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-12 19:20:11 +01:00
1ca13a9451 Merge pull request 'add day rating feature' (#6) from feature/day-rating into main
Reviewed-on: #6
2024-03-12 18:15:23 +00:00
0cdc359463 add day rating feature 2024-03-12 19:14:29 +01:00
2d923df965 [CI SKIP] Update mollre/journal-bot Docker tag to v1.0.66
Reviewed-on: #5
2024-01-02 21:11:40 +00:00
421c3a7e1f [CI SKIP] Update mollre/journal-bot Docker tag to v1.0.66 2024-01-02 21:00:12 +00:00
Lia Schöneweiß
9eafa55dd8 fix date check
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-02 21:50:15 +01:00
2a344817f7 [CI SKIP] update 2023-12-11 16:12:51 +00:00
27656c21ae Update renovate.json
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-12-11 16:03:04 +00:00
argocd-image-updater
b733d1040c [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.63' to '1.0.64'
2023-12-08 17:46:23 +00:00
6d9c60b0d7 Merge pull request 'Configure Renovate' (#4) from renovate/configure into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #4
2023-12-08 17:44:11 +00:00
84fb43e836 Add renovate.json 2023-12-07 15:42:02 +00:00
argocd-image-updater
cfcea80a64 [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.62' to '1.0.63'
2023-12-02 18:05:07 +00:00
7daf30f851 Fixing what Rémy told me wrong.
All checks were successful
continuous-integration/drone/push Build is passing
2023-12-02 19:02:46 +01:00
argocd-image-updater
a030d06641 [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.61' to '1.0.62'
2023-11-28 15:36:10 +00:00
15304d565e update storage classes
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-28 16:33:50 +01:00
argocd-image-updater
6094112f48 [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.60' to '1.0.61'
2023-11-25 15:00:28 +00:00
Lia Schöneweiß
c75fb0b7a3 Merge branch 'main' of ssh://git.kluster.moll.re:2222/remoll/journal-bot
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-25 15:57:49 +01:00
Lia Schöneweiß
b2820ce902 bug fixes 2023-11-25 15:57:47 +01:00
argocd-image-updater
b605ce315b [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.59' to '1.0.60'
2023-11-25 14:09:51 +00:00
Lia Schöneweiß
dc14eb0aec upsiwupsi
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-25 15:07:39 +01:00
argocd-image-updater
393ac72191 [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.58' to '1.0.59'
2023-11-25 13:59:42 +00:00
Lia Schöneweiß
f235b27916 Merge branch 'main' of ssh://git.kluster.moll.re:2222/remoll/journal-bot
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-25 14:57:37 +01:00
Lia Schöneweiß
c4fbd089cc Merge branch 'secretbranch' 2023-11-25 14:56:19 +01:00
argocd-image-updater
ec87c6751c [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.57' to '1.0.58'
2023-11-18 12:00:35 +00:00
724b17c4b7 broadened regex
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-18 12:59:03 +01:00
argocd-image-updater
8b7a318e6b [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.56' to '1.0.57'
2023-11-18 11:50:25 +00:00
Lia Schöneweiß
a0e1aaa779 Merge branch 'feature/memory-redacted'
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-18 12:48:38 +01:00
c9254a3e88 memories are now redacted 2023-11-18 12:32:20 +01:00
argocd-image-updater
3097594482 [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.55' to '1.0.56'
2023-11-17 21:56:17 +00:00
49df5a4495 cleanup the model layout
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-17 22:53:06 +01:00
argocd-image-updater
9eb7f5bb77 [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.54' to '1.0.55'
2023-10-21 13:35:11 +00:00
35dbbe4ece cleaner journal date entry
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-21 15:34:24 +02:00
6b63276dd7 playing with regexes 2023-10-21 15:23:05 +02:00
argocd-image-updater
d40afca1a4 [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.53' to '1.0.54'
2023-10-12 21:04:35 +00:00
0e2b714848 Merge branch 'main'
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-12 23:03:29 +02:00
df55dbf6c7 improved journal date selection 2023-10-12 23:03:18 +02:00
argocd-image-updater
c1e7c0eb38 [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.52' to '1.0.53'
2023-10-12 10:45:03 +00:00
c58e256194 convert arg vars to env vars
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-12 12:42:40 +02:00
argocd-image-updater
cbaedb04cb [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.49' to '1.0.52'
2023-10-12 10:22:50 +00:00
008cf08163 Merge branch 'main'
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-12 12:20:35 +02:00
b1a9e5fa46 add version in status command 2023-10-12 12:19:35 +02:00
argocd-image-updater
7e3cf46765 [CI SKIP] automatic update of journal-application
updates image mollre/journal-bot tag '1.0.19' to '1.0.49'
2023-10-12 10:12:43 +00:00
d6447c54d1 Delete 'deployment/.argocd-source-journal-application.yaml'
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-10-12 10:11:18 +00:00
argocd-image-updater
db44a38eb7 build: automatic update of journal-application
Some checks reported errors
continuous-integration/drone/push Build was killed
updates image mollre/journal-bot tag '1.0.46' to '1.0.49'
2023-10-12 09:50:18 +00:00
argocd-image-updater
a77ab50f82 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.46' to '1.0.48'
2023-10-12 09:48:16 +00:00
argocd-image-updater
63daf6845c build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.46' to '1.0.47'
2023-10-12 09:46:14 +00:00
argocd-image-updater
7d793c571c build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.43' to '1.0.46'
2023-10-12 09:44:12 +00:00
argocd-image-updater
a805775707 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.43' to '1.0.45'
2023-10-12 09:42:10 +00:00
argocd-image-updater
9ee7302f65 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.43' to '1.0.44'
2023-10-12 09:40:07 +00:00
argocd-image-updater
58fb79820f build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.40' to '1.0.43'
2023-10-12 09:38:05 +00:00
argocd-image-updater
9518b813f6 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.40' to '1.0.42'
2023-10-12 09:36:03 +00:00
argocd-image-updater
122b090475 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.37' to '1.0.41'
2023-10-12 09:34:01 +00:00
argocd-image-updater
6a100e7364 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.37' to '1.0.40'
2023-10-12 09:31:59 +00:00
argocd-image-updater
0a14e8be4a build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.37' to '1.0.39'
2023-10-12 09:29:57 +00:00
argocd-image-updater
bdb58c8a5f build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.35' to '1.0.38'
2023-10-12 09:27:55 +00:00
argocd-image-updater
c526c23e3a build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.35' to '1.0.37'
2023-10-12 09:25:53 +00:00
argocd-image-updater
8ff3f05034 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.35' to '1.0.36'
2023-10-12 09:23:51 +00:00
argocd-image-updater
1ce47df5f4 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.32' to '1.0.35'
2023-10-12 09:21:49 +00:00
argocd-image-updater
fa5427ec09 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.32' to '1.0.34'
2023-10-12 09:19:47 +00:00
argocd-image-updater
378795d3ef build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.32' to '1.0.33'
2023-10-12 09:17:44 +00:00
argocd-image-updater
8ea0c2f517 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.29' to '1.0.32'
2023-10-12 09:15:42 +00:00
argocd-image-updater
3622e76639 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.29' to '1.0.31'
2023-10-12 09:13:40 +00:00
argocd-image-updater
d5349433d4 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.29' to '1.0.30'
2023-10-12 09:11:38 +00:00
argocd-image-updater
282a3d305d build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.26' to '1.0.29'
2023-10-12 09:09:36 +00:00
argocd-image-updater
e5d24b0171 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.26' to '1.0.28'
2023-10-12 09:07:34 +00:00
argocd-image-updater
0fb841fce4 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.26' to '1.0.27'
2023-10-12 09:05:32 +00:00
argocd-image-updater
3507d16394 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.23' to '1.0.26'
2023-10-12 09:03:30 +00:00
argocd-image-updater
6952e7f12f build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.23' to '1.0.25'
2023-10-12 09:01:28 +00:00
argocd-image-updater
674a88f6ab build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.23' to '1.0.24'
2023-10-12 08:59:26 +00:00
argocd-image-updater
11aefc0322 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.19' to '1.0.23'
2023-10-12 08:57:24 +00:00
argocd-image-updater
7273dd5121 build: automatic update of journal-application
All checks were successful
continuous-integration/drone/push Build is passing
updates image mollre/journal-bot tag '1.0.19' to '1.0.22'
2023-10-12 08:55:22 +00:00
argocd-image-updater
350bd19b08 build: automatic update of journal-application
Some checks reported errors
continuous-integration/drone/push Build encountered an error
updates image mollre/journal-bot tag '1.0.19' to '1.0.21'
2023-10-12 08:53:20 +00:00
e3f643e805 update tag manually
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-11 16:28:54 +02:00
970d6931db [CI SKIP] update deployment 2023-10-11 16:18:47 +02:00
b39aa6ecb1 [CI-skip] alter deployment information
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-10-10 18:21:38 +02:00
9b54f05d75 toggle option shows current status
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-10 17:08:58 +02:00
fluxcdbot
cd7594350f [CI SKIP] Bump registry.hub.docker.com/mollre/journal-bot:1.0.18 2023-10-02 18:04:35 +00:00
c202ad8035 More coherent button layout
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-02 19:48:59 +02:00
fluxcdbot
50e7226709 [CI SKIP] Bump registry.hub.docker.com/mollre/journal-bot:1.0.17 2023-10-02 15:04:25 +00:00
fluxcdbot
ae330eb389 Bump registry.hub.docker.com/mollre/journal-bot:1.0.16
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-02 14:55:40 +00:00
ebc89b48e2 manage image updates by flux
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-29 10:20:58 +02:00
0f49cbf4fb cleaner deployment using kustomize, to be managed by flux
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-29 09:57:14 +02:00
cd3bbe9b00 auto tagging images
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-28 16:57:37 +02:00
1bc829f53d Better chat id handling
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-14 11:47:13 +02:00
3975ca5997 small privacy improvements
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-14 11:36:39 +02:00
2afde219a9 Fixed kinda broken regex
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-03 09:05:45 +00:00
a666b8e9ae manually add anyio?
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-27 12:06:21 +02:00
e77c106813 toggleable lists also apply status to newly added items
All checks were successful
continuous-integration/drone/push Build is passing
2023-07-27 11:43:05 +02:00
86a9762f39 Merge pull request 'Lists with more functionality' (#3) from checklist into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #3
2023-06-23 11:02:23 +00:00
3455946996 use single database accross chats -> no storage leaks 2023-06-23 13:01:07 +02:00
3f58eab8c7 Merge pull request 'cronjobs' (#2) from cronjobs into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #2
2023-05-24 13:59:32 +00:00
Lia Schöneweiß
1613e05b61 chat photo improvements. 2023-05-24 13:59:32 +00:00
Lia Schöneweiß
0860196a53 fixed stuck in memory function. implemented random memory 2023-05-24 13:59:32 +00:00
49339ebcb9 cleanup
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-14 23:13:39 +02:00
23 changed files with 512 additions and 223 deletions

View File

@ -16,7 +16,10 @@ steps:
from_secret: docker_pw
repo: mollre/journal-bot
tags: latest
tags:
- 1.0.${DRONE_BUILD_NUMBER}
- latest
build_args: "BOT_VERSION=1.0.${DRONE_BUILD_NUMBER}"
trigger:

9
.vscode/launch.json vendored
View File

@ -4,15 +4,6 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
},
{
"name": "Python: Current project",
"type": "python",

View File

@ -1,11 +1,16 @@
FROM python:3.10-slim
FROM python:3-slim
ENV DOCKERIZED=true
ARG BOT_VERSION
# set at build time
ENV BOT_VERSION=$BOT_VERSION
WORKDIR /app
RUN pip install pipenv
COPY Pipfile Pipfile.lock ./
RUN pip install pipenv && pipenv install --system --deploy
RUN pipenv install --system --deploy
COPY bot .

View File

@ -4,7 +4,11 @@ verify_ssl = true
name = "pypi"
[packages]
python-telegram-bot = "*"
peewee = "*"
python-telegram-bot = {extras = ["job-queue"], version = "*"}
anyio = "*"
[dev-packages]
[pipenv]
allow_prereleases = true

79
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "e95b9deab62bd0c661f20a178b8701fc84420db5f663fa4416666e1d05f6ce76"
"sha256": "5458e81c4f85af776acc44f46af838644ef8c00ccf4223fbe06f9d76a4717fc6"
},
"pipfile-spec": 6,
"requires": {},
@ -16,19 +16,26 @@
"default": {
"anyio": {
"hashes": [
"sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421",
"sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"
"sha256:48d53f0b141f5757c38d648309e6fe254857fae092d67f938fa248d7c0f36804",
"sha256:596b09c520820e7eed961ddc889540972f92d5e8fcb081117fc054c409df34ae"
],
"markers": "python_full_version >= '3.6.2'",
"version": "==3.6.2"
"index": "pypi",
"version": "==4.0.0rc1"
},
"apscheduler": {
"hashes": [
"sha256:0293937d8f6051a0f493359440c1a1b93e882c57daf0197afeff0e727777b96e",
"sha256:e813ad5ada7aff36fb08cdda746b520531eaac7757832abc204868ba78e0c8f6"
],
"version": "==3.10.1"
},
"certifi": {
"hashes": [
"sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3",
"sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"
"sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
"sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
],
"markers": "python_version >= '3.6'",
"version": "==2022.12.7"
"version": "==2023.7.22"
},
"h11": {
"hashes": [
@ -40,19 +47,19 @@
},
"httpcore": {
"hashes": [
"sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb",
"sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"
"sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888",
"sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"
],
"markers": "python_version >= '3.7'",
"version": "==0.16.3"
"version": "==0.17.3"
},
"httpx": {
"hashes": [
"sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9",
"sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"
"sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd",
"sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"
],
"markers": "python_version >= '3.7'",
"version": "==0.23.3"
"version": "==0.24.1"
},
"idna": {
"hashes": [
@ -70,22 +77,38 @@
"version": "==3.16.2"
},
"python-telegram-bot": {
"extras": [
"job-queue"
],
"hashes": [
"sha256:4d1d4b643ce158aa17a0987b84005eaf25fe0ce8b38fd234099594985611c198",
"sha256:d0aa53e1f06d7cb7919cc0e2d6c81a02d968fc29921aeaa962edd1efb816a9bd"
"sha256:a6ac3f9c9674aaf7d1c7e652d8b75cde969fb872f75e9521b8516eceaba82b1b",
"sha256:e426404b0006989a5bcc05e11a7ef3ffe0c086b684a4e963db5bda1d361a049a"
],
"index": "pypi",
"version": "==20.2"
"version": "==20.4"
},
"rfc3986": {
"extras": [
"idna2008"
],
"pytz": {
"hashes": [
"sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835",
"sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"
"sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588",
"sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"
],
"version": "==1.5.0"
"version": "==2023.3"
},
"setuptools": {
"hashes": [
"sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f",
"sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"
],
"markers": "python_version >= '3.7'",
"version": "==68.0.0"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"sniffio": {
"hashes": [
@ -94,6 +117,14 @@
],
"markers": "python_version >= '3.7'",
"version": "==1.3.0"
},
"tzlocal": {
"hashes": [
"sha256:46eb99ad4bdb71f3f72b7d24f4267753e240944ecfc16f25d2719ba89827a803",
"sha256:f3596e180296aaf2dbd97d124fe76ae3a0e3d32b258447de7b939b3fd4be992f"
],
"markers": "python_version >= '3.7'",
"version": "==5.0.1"
}
},
"develop": {}

View File

@ -1,3 +1,9 @@
# journal-bot
Sharing memories, the digital way...
## Migration 10.03.24
```
ALTER TABLE journalentry ADD COLUMN rating INTEGER;
```

View File

@ -2,12 +2,21 @@ from datetime import date
from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, filters, CallbackQueryHandler, CallbackContext
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, InputMediaPhoto
import random
import os
from pathlib import Path
# ACTION_CHOICE, DATE_ENTRY, ADD_CONTENT = range(3)
ACTION, TUERCHEN_CHOICE = range(2)
from .basehandler import BaseHandler
MEDIA_DIR = Path(os.getenv("MEDIA_DIR"))
GIF_LOCATION = MEDIA_DIR / "advent" / "gifs"
# GIFS = list(GIF_LOCATION.glob("*.mp4"))
STICKER_LOCATION = MEDIA_DIR / "advent" / "stickers"
# STICKERS = list(STICKER_LOCATION.glob("*.tgs"))
PICTURE_LOCATION = MEDIA_DIR / "advent" / "pretty_pictures"
PICTURES = list(PICTURE_LOCATION.glob("*.jpg"))
class AdventsHandler(BaseHandler):
def __init__(self, entry_string):
self.entry_string = entry_string
@ -66,12 +75,11 @@ class AdventsHandler(BaseHandler):
keyboard = [[InlineKeyboardButton("Bubo Küsschen", callback_data="kuss")], [InlineKeyboardButton("Türchen öffnen", callback_data="tuer")], [InlineKeyboardButton("Pretty Bubo Picture", callback_data="picture")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_sticker(sticker=open(".bot_storage\stickers\stickerwhat.tgs", "rb"))
await update.message.reply_sticker(sticker=STICKER_LOCATION/"stickerwhat.tgs")
await update.message.reply_text(text="Hallo, mein süßer Weihnachts-Bubo! Ich bin dein Adventskalender ^^. Was möchtest du tun?", reply_markup=reply_markup)
return ACTION
async def kuesschen(self, update: Update, context: CallbackContext):
query = update.callback_query
await query.answer()
@ -79,7 +87,7 @@ class AdventsHandler(BaseHandler):
keyboard = [[InlineKeyboardButton("Kalendertürchen öffnen", callback_data="tuer")], [InlineKeyboardButton("Noch ein Küsschen!", callback_data="kuss")], [InlineKeyboardButton("Pretty Bubo Picture", callback_data="picture")], [InlineKeyboardButton("Bis zum nächsten Mal!", callback_data="bye")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.effective_message.reply_sticker(sticker=open(".bot_storage\stickers\stickerkiss.tgs", "rb"))
await update.effective_message.reply_sticker(sticker=STICKER_LOCATION/"stickerkiss.tgs")
await update.effective_message.reply_text(text="Mua!", reply_markup=reply_markup)
return ACTION
@ -101,7 +109,8 @@ class AdventsHandler(BaseHandler):
reply_markup = InlineKeyboardMarkup(keyboard)
picture_number = random.randint(1,31)
await update.effective_message.reply_photo(photo=open(".bot_storage\pretty_pictures\photo_"+f"{picture_number}"+"_2023-11-25_14-25-53.jpg", "rb"), caption="So ein cutes Foto!", reply_markup=reply_markup)
#print(picture_number-1)
await update.effective_message.reply_photo(photo=PICTURES[picture_number-1], caption="So ein cutes Foto!", reply_markup=reply_markup)
return ACTION
@ -116,11 +125,11 @@ class AdventsHandler(BaseHandler):
reply_markup = InlineKeyboardMarkup(keyboard)
#if tuer_nummer <= int(date.today().strftime("%d")):
if (tuer_nummer <= int(date.today().strftime("%d"))) and (int(date.today().strftime("%m"))==12):
await update.message.reply_document(document=open(".bot_storage\gifs\gif"+f"{tuer_nummer}"+".mp4", "rb"),caption=f"Türchen für den {tuer_nummer}. Dezember: \n" + self.tuerchen_texte[tuerchen], reply_markup=reply_markup)
datum_tuer_heute = date(2023, 12, tuer_nummer)
if (date.today() - datum_tuer_heute).days >= 0:
await update.message.reply_document(document=GIF_LOCATION/ f"gif{tuer_nummer}.mp4", caption=f"Türchen für den {tuer_nummer}. Dezember: \n" + self.tuerchen_texte[tuerchen], reply_markup=reply_markup)
else:
await update.message.reply_sticker(sticker=open(".bot_storage\stickers\stickerangry.tgs", "rb"))
await update.message.reply_sticker(sticker=STICKER_LOCATION/"stickerangry.tgs")
await update.message.reply_text(text="Hey, nicht schummeln! Dieses Türchen darfst du noch nicht sehen.", reply_markup=reply_markup)
return ACTION
@ -129,7 +138,7 @@ class AdventsHandler(BaseHandler):
query = update.callback_query
await query.answer()
await update.effective_message.reply_sticker(sticker=open(".bot_storage\stickers\stickerbye.tgs", "rb"))
await update.effective_message.reply_sticker(sticker=STICKER_LOCATION/"stickerbye.tgs")
await update.effective_message.reply_text(text="Bye bye, Bubo! Hab dich ganz doll lieb! 😘")
return ConversationHandler.END

View File

@ -5,4 +5,4 @@ class BaseHandler:
entry_string: str
async def entry_point(self, update, context) -> None:
self.logger.info(f"Chat said: {self.entry_string}")
self.logger.info(f"Chat ({update.message.chat_id}) said: {self.entry_string}")

View File

@ -2,28 +2,33 @@ import datetime
import os
from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, filters, CallbackQueryHandler
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
ACTION_CHOICE, DATE_ENTRY, ADD_CONTENT = range(3)
from telegram.constants import ParseMode
import models
ENTRY_OPTIONS, CONTENT_ENTRY, DAY_RATING = range(3)
BUTTON_COUNT = 5
from .basehandler import BaseHandler
class JournalHandler(BaseHandler):
def __init__(self, entry_string, models):
self.models = models
def __init__(self, entry_string):
self.entry_string = entry_string
self.handler = ConversationHandler(
entry_points=[CommandHandler(entry_string, self.entry_point)],
states={
ACTION_CHOICE: [
CallbackQueryHandler(self.date_choice, pattern="today|yesterday"),
CallbackQueryHandler(self.date_custom, pattern="custom"),
CallbackQueryHandler(self.option_delete, pattern="delete")
],
DATE_ENTRY: [
ENTRY_OPTIONS: [
CallbackQueryHandler(self.date_button, pattern=r"^\d{8}$"), # a serialized date
CallbackQueryHandler(self.date_custom, pattern=r"^\d{1,3}$"), # a ~ small delta, symbolizing a new range to show
CallbackQueryHandler(self.option_delete, pattern="delete"),
MessageHandler(filters.ALL, self.date_entry),
],
ADD_CONTENT: [
CONTENT_ENTRY: [
MessageHandler(filters.ALL, self.content_save),
]
],
DAY_RATING: [
CallbackQueryHandler(self.day_rating_save),
],
},
fallbacks=[],
)
@ -37,52 +42,74 @@ class JournalHandler(BaseHandler):
await update.message.reply_text("You are not authorized to use this bot")
return ConversationHandler.END
dates = [(datetime.datetime.now() - datetime.timedelta(days = i)).date() for i in range(BUTTON_COUNT + 2)][::-1]
# since there are two buttons additional buttons, we need to have two more days
names = get_names(dates)
callbacks = [d.strftime("%d%m%Y") for d in dates]
options = [[
InlineKeyboardButton("Today", callback_data="today"),
InlineKeyboardButton("Yesterday", callback_data="yesterday"),
InlineKeyboardButton("Custom date", callback_data="custom"),
options = [
[InlineKeyboardButton(n, callback_data=c)] for n,c in zip(names[::-1], callbacks[::-1])
] + [
[
InlineKeyboardButton("<<", callback_data=BUTTON_COUNT + 2)
],
[
InlineKeyboardButton("Delete", callback_data="delete")
]
]
keyboard = InlineKeyboardMarkup(options)
await update.message.reply_text("Please choose an option for the entry:", reply_markup=keyboard)
return ACTION_CHOICE
await update.message.reply_text("Please choose a date \(or type it in the format _DDMMYYYY_\)", reply_markup=keyboard, parse_mode=ParseMode.MARKDOWN_V2)
return ENTRY_OPTIONS
async def date_choice(self, update, context):
async def date_button(self, update, context):
query = update.callback_query
await query.answer()
if query.data == "today":
date = datetime.datetime.now().date()
elif query.data == "yesterday":
date = datetime.datetime.now().date() - datetime.timedelta(days=1)
else:
raise ValueError("Invalid date choice")
date = datetime.datetime.strptime(query.data, "%d%m%Y").date()
with self.models.db:
self.current_model, new = self.models.JournalEntry.get_or_create(
with models.db:
self.current_model, new = models.JournalEntry.get_or_create(
date = date
)
if new:
count = models.JournalEntry.select().count()
await query.edit_message_text(
text=f"What is your entry for {self.current_model.date_pretty}?"
text=f"Journal entry no. {count}. What happened on {self.current_model.date_pretty}?"
)
else:
await query.edit_message_text(text="An entry already exists for this date")
return ConversationHandler.END
return ADD_CONTENT
return CONTENT_ENTRY
async def date_custom(self, update, context):
query = update.callback_query
await query.answer()
await query.edit_message_text(text="Please enter the date in the format DDMMYYYY")
return DATE_ENTRY
delta = int(query.data)
dates = [(datetime.datetime.now() - datetime.timedelta(days = i + delta)).date() for i in range(BUTTON_COUNT)][::-1]
names = get_names(dates)
callbacks = [d.strftime("%d%m%Y") for d in dates]
options = [
[
InlineKeyboardButton(">>", callback_data=delta - BUTTON_COUNT)
]
] + [
[InlineKeyboardButton(n, callback_data=c)] for n,c in zip(names[::-1], callbacks[::-1])
] + [
[
InlineKeyboardButton("<<", callback_data=delta + BUTTON_COUNT)
],
[
InlineKeyboardButton("Delete", callback_data="delete")
]
]
keyboard = InlineKeyboardMarkup(options)
await query.edit_message_text("Please choose a date \(or type it in the format _DDMMYYYY_\)", parse_mode=ParseMode.MARKDOWN_V2, reply_markup=keyboard)
return ENTRY_OPTIONS
async def date_entry(self, update, context):
date = update.message.text
@ -90,12 +117,12 @@ class JournalHandler(BaseHandler):
try:
date = datetime.datetime.strptime(date, "%d%m%Y").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 date in the format _DDMMYYYY_", parse_mode=ParseMode.MARKDOWN_V2)
return ENTRY_OPTIONS
if context.chat_data.get("delete", False): # if not set, delete was not chosen
with self.models.db:
self.current_model = self.models.JournalEntry.get_or_none(
with models.db:
self.current_model = models.JournalEntry.get_or_none(
date = date
)
if self.current_model:
@ -105,20 +132,23 @@ class JournalHandler(BaseHandler):
context.chat_data["delete"] = False
return ConversationHandler.END
else:
with self.models.db:
self.current_model, new = self.models.JournalEntry.get_or_create(
with models.db:
self.current_model, new = models.JournalEntry.get_or_create(
date = date
)
if not new:
await update.message.reply_text("An entry already exists for this date")
return ConversationHandler.END
else:
await update.message.reply_text(f"What is your entry for {self.current_model.date_pretty}?")
return ADD_CONTENT
count = models.JournalEntry.select().count()
await update.message.reply_text(
text=f"Journal entry no. {count}. What happened on {self.current_model.date_pretty}?"
)
return CONTENT_ENTRY
async def content_save(self, update, context):
with self.models.db:
with models.db:
self.current_model.author_id = update.message.from_user.id
if update.message.text:
@ -137,20 +167,55 @@ class JournalHandler(BaseHandler):
self.current_model.save()
await update.message.reply_text(f"Saved entry ✅")
options = [
[InlineKeyboardButton(models.RATING_MAPPING[idx], callback_data=idx) for idx in [1,2,3,4,5]]
]
await update.message.reply_text(f"Saved entry ✅. How was the day?", reply_markup=InlineKeyboardMarkup(options))
return DAY_RATING
async def day_rating_save(self, update, context):
query = update.callback_query
await query.answer()
rating = int(query.data)
with models.db:
self.current_model.rating = rating
self.current_model.save()
await query.edit_message_text(text="Rating saved ✅")
return ConversationHandler.END
async def option_delete(self, update, context):
query = update.callback_query
await query.answer()
await query.edit_message_text(text="Please enter the date in the format DDMMYYYY")
await query.edit_message_text(text="Please enter the date in the format _DDMMYYYY_", parse_mode=ParseMode.MARKDOWN_V2)
context.chat_data["delete"] = True
return DATE_ENTRY
return ENTRY_OPTIONS
async def delete_entry(self, update, context):
with self.models.db:
with models.db:
self.current_model.delete_instance()
context.chat_data["delete"] = False
await update.message.reply_text(text="Entry deleted ✅")
### HELPERS
def get_names(dates: list):
names = []
for d in dates:
suffix = ""
if models.JournalEntry.get_or_none(date = d):
suffix = ""
if d == datetime.datetime.now().date():
names.append("Today" + suffix)
elif d == datetime.datetime.now().date() - datetime.timedelta(days = 1):
names.append("Yesterday" + suffix)
else:
names.append(d.strftime("%d.%m.") + suffix)
return names

View File

@ -5,10 +5,7 @@ from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from .models import ListModel, set_db, db
MEDIA_DIR = Path(os.getenv("MEDIA_DIR"))
DB_DIR = MEDIA_DIR / "lists_db"
DB_DIR.mkdir(parents=True, exist_ok=True)
PERSISTENCE_DIR = Path(os.getenv("PERSISTENCE_DIR"))
NAME, NEW, ACTION, ITEMADD, ITEMREMOVE, ITEMTOGGLE = range(6)
@ -18,16 +15,17 @@ from ..basehandler import BaseHandler
class ListHandler(BaseHandler):
"""Create and edit lists"""
def __init__(self, entry_string, models):
self.journal_models = models # not needed here
def __init__(self, entry_string):
self.entry_string = entry_string
set_db(PERSISTENCE_DIR / "lists.sqlite")
self.list_overview_keyboard = [
[InlineKeyboardButton("Print list", callback_data="print")],
[InlineKeyboardButton("Add item", callback_data="add")],
[InlineKeyboardButton("Toggle item", callback_data="toggle")],
[InlineKeyboardButton("Remove item", callback_data="remove")],
[InlineKeyboardButton("Clear list", callback_data="clear")],
[InlineKeyboardButton("Print list", callback_data="print")],
[InlineKeyboardButton("Delete list", callback_data="delete")],
]
@ -40,13 +38,13 @@ class ListHandler(BaseHandler):
],
NEW : [MessageHandler(filters.TEXT, callback=self.new_listname)],
ACTION: [
CallbackQueryHandler(self.list_print, pattern="^print$"),
CallbackQueryHandler(self.list_add, pattern="^add$"),
CallbackQueryHandler(self.list_toggle, pattern="^toggle$"),
CallbackQueryHandler(self.list_menu, pattern="^overview$"),
CallbackQueryHandler(self.list_remove, pattern="^remove$"),
CallbackQueryHandler(self.list_clear, pattern="^clear$"),
CallbackQueryHandler(self.list_delete, pattern="^delete$"),
CallbackQueryHandler(self.list_print, pattern="^print$"),
CallbackQueryHandler(self.list_menu, pattern="^overview$"),
],
ITEMADD : [MessageHandler(filters.TEXT, callback=self.list_add_item)],
ITEMTOGGLE: [CallbackQueryHandler(self.list_toggle_index)],
@ -58,10 +56,9 @@ class ListHandler(BaseHandler):
async def entry_point(self, update, context) -> None:
await super().entry_point(update, context)
set_db(DB_DIR / f"chat_{update.message.chat_id}.db")
with db:
lists = ListModel.select()
keyboard = [[InlineKeyboardButton(k.name, callback_data=f"list-{k.name}")] for k in lists] + \
lists = ListModel.select().where(ListModel.chat_id == update.effective_chat.id)
keyboard = [[InlineKeyboardButton(k.name, callback_data=f"list-{k.id}")] for k in lists] + \
[[InlineKeyboardButton("New list", callback_data="new")]]
reply_markup = InlineKeyboardMarkup(keyboard)
@ -72,13 +69,13 @@ class ListHandler(BaseHandler):
async def choose_list(self, update, context: CallbackContext) -> None:
query = update.callback_query
data = query.data
name = data.replace("list-","")
id = data.replace("list-","")
await query.answer()
context.user_data["current_list"] = ListModel.get(name = name)
context.user_data["current_list"] = ListModel.get(id = id)
reply_markup = InlineKeyboardMarkup(self.list_overview_keyboard)
await query.edit_message_text("Very well. For " + name + " the following actions are available:", reply_markup=reply_markup)
await query.edit_message_text(f"Using {context.user_data['current_list'].name}. Available actions:", reply_markup=reply_markup)
return ACTION
@ -88,7 +85,7 @@ class ListHandler(BaseHandler):
reply_markup = InlineKeyboardMarkup(self.list_overview_keyboard)
await query.edit_message_text(f"Very well. For {context.user_data['current_list'].name} the following actions are available:", reply_markup=reply_markup)
await query.edit_message_text(f"Using {context.user_data['current_list'].name}. Available actions:", reply_markup=reply_markup)
return ACTION
@ -103,7 +100,7 @@ class ListHandler(BaseHandler):
name = update.message.text
try:
with db:
context.user_data["current_list"] = ListModel.create(name = name)
context.user_data["current_list"] = ListModel.create(name = name, chat_id=update.effective_chat.id)
keyboard = [[InlineKeyboardButton("Add an item", callback_data="add"), InlineKeyboardButton("To the menu!", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text("Thanks. List " + name + " was successfully created.", reply_markup=reply_markup)
@ -125,10 +122,17 @@ class ListHandler(BaseHandler):
await query.answer()
list_object = context.user_data["current_list"]
keyboard = [[InlineKeyboardButton(v, callback_data=k)] for k,v in list_object.content.items()]
reply_markup = InlineKeyboardMarkup(keyboard)
readable_it = printable_list(list_object)
await query.edit_message_text("Which item would you like to toggle?", reply_markup = reply_markup)
if readable_it:
msg_content = "Which item would you like to toggle?"
keyboard = [[InlineKeyboardButton(v, callback_data=k)] for k,v in zip(list_object.content.keys(), readable_it)]
reply_markup = InlineKeyboardMarkup(keyboard)
else:
msg_content = "List empty"
reply_markup = None
await query.edit_message_text(msg_content, reply_markup = reply_markup)
return ITEMTOGGLE
@ -170,14 +174,10 @@ class ListHandler(BaseHandler):
await query.answer()
list_object = context.user_data["current_list"]
content_it = list_object.content.values()
done_it = [
"· " if e is None \
else "" if e \
else "" \
for e in list_object.done_dict.values()]
if content_it:
msg_content = "\n".join([f"{d} {c}" for d, c in zip(done_it, content_it)])
readable_it = printable_list(list_object)
if readable_it:
msg_content = "\n".join(readable_it)
else:
msg_content = "List empty"
@ -193,7 +193,6 @@ class ListHandler(BaseHandler):
new = list_object.content
new.update({"random_key": item})
list_object.content = new
# TODO test me!
keyboard = [[InlineKeyboardButton("Add some more", callback_data="add"), InlineKeyboardButton("Back to the menu", callback_data="overview")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(f"Added {item}", reply_markup=reply_markup)
@ -206,11 +205,10 @@ class ListHandler(BaseHandler):
await query.answer()
list_object = context.user_data["current_list"]
old = list_object.done_dict[toggle_key]
# if all None or all False (first toggle or all false) then set all dones to False
if not any(list_object.done_dict.values()):
new_done_dict = dict.fromkeys(list_object.done_dict, False)
else: new_done_dict = list_object.done_dict
old = list_object.done_dict[toggle_key] or False
# if it was previously unset (None), we can later on set it to not old = True
new_done_dict = list_object.done_dict
new_done_dict[toggle_key] = not old
list_object.done_dict = new_done_dict
@ -236,3 +234,22 @@ class ListHandler(BaseHandler):
await query.edit_message_text(f"Removed {name}", reply_markup=reply_markup)
return ACTION
def printable_list(list_object: ListModel):
content_it = list_object.content.values()
done_bool_it = list_object.done_dict.values()
# distinguish the enumeration:
# either all done_dict values are None -> the list is not toggleable
# or at least one value is of type bool -> the list is toggleable and None === False
if any([type(e) == bool for e in done_bool_it]):
done_it = [
"" if e else "" \
for e in list_object.done_dict.values()
]
else:
done_it = ["-" for e in done_bool_it]
readable_it = [f"{d} {c}" for d, c in zip(done_it, content_it)]
return readable_it

View File

@ -8,6 +8,7 @@ class BaseModel(Model):
class ListModel(BaseModel):
name = CharField(default="")
chat_id = IntegerField()
@property
def content(self) -> dict:
@ -45,22 +46,6 @@ class ListEntryModel(BaseModel):
done = BooleanField(default=None, null=True)
# class ListModel(BaseModel):
# name = CharField(unique=True)
# content = TextField(default="") # unlimited length, use to serialise list into
# @property
# def content_list(self):
# return json.loads(self.content or '[]')
# @content_list.setter
# def content_list(self, list_content):
# self.content = json.dumps(list_content)
# with db:
# self.save()
def set_db(db_path):
db.initialize(SqliteDatabase(db_path))
with db:

View File

@ -1,6 +1,8 @@
import datetime
import os
from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, filters, CallbackQueryHandler, CallbackContext
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, InputMediaPhoto
import models
from telegram.constants import ParseMode
# ACTION_CHOICE, DATE_ENTRY, ADD_CONTENT = range(3)
MEMORY_CHOICE = range(1)
@ -8,8 +10,7 @@ MEMORY_CHOICE = range(1)
from .basehandler import BaseHandler
class MemoryHandler(BaseHandler):
def __init__(self, entry_string, models):
self.models = models
def __init__(self, entry_string):
self.entry_string = entry_string
self.handler = ConversationHandler(
entry_points=[CommandHandler(entry_string, self.entry_point, )],
@ -27,20 +28,27 @@ class MemoryHandler(BaseHandler):
async def entry_point(self, update: Update, context: CallbackContext):
await super().entry_point(update, context)
if os.getenv("DOCKERIZED", "false") == "true" and os.getenv("CHAT_ID") != str(update.message.chat_id):
await update.message.reply_text("You are not authorized to use this bot")
return ConversationHandler.END
search_string = " ".join(context.args)
if search_string == '~photo':
matching_models = self.models.JournalEntry.select().where(self.models.JournalEntry.media_path != "").order_by(self.models.JournalEntry.date)
matching_models = models.JournalEntry.select().where(models.JournalEntry.media_path != "").order_by(models.JournalEntry.date)
else: # searching for text
matching_models = self.models.JournalEntry.select().where(
self.models.JournalEntry.text.contains(
matching_models = models.JournalEntry.select().where(
models.JournalEntry.text.contains(
search_string
)
).order_by(self.models.JournalEntry.date)
).order_by(models.JournalEntry.date)
# exit if no memory matches the string
if len(matching_models) == 0:
await update.message.reply_text(f"There is no matching memory yet.")
return ConversationHandler.END
options = [[InlineKeyboardButton(m.date_pretty, callback_data=i)] for i,m in enumerate(matching_models)]
keyboard = InlineKeyboardMarkup(options)
@ -61,20 +69,23 @@ class MemoryHandler(BaseHandler):
matching_models = context.chat_data["kept_matches"]
chosen_match = matching_models[ind]
rating_string = f" ({models.RATING_MAPPING[chosen_match.rating]})" if chosen_match.rating else ""
message_text = f"On {chosen_match.date_pretty}{rating_string}, " \
f"{chosen_match.author} wrote: \n" \
f"{chosen_match.spoiler_text}"
if chosen_match.media_path:
# context.bot.sendPhoto()
await update.effective_message.reply_photo(
photo = chosen_match.media_path,
caption=
f"On {chosen_match.date_pretty}, "
f"{chosen_match.author} wrote: \n"
f"{chosen_match.text}"
caption = message_text,
parse_mode=ParseMode.HTML
)
else:
await query.edit_message_text(
f"On {chosen_match.date_pretty}, "
f"{chosen_match.author} wrote: \n"
f"{chosen_match.text}"
message_text,
parse_mode=ParseMode.HTML
)
return ConversationHandler.END

View File

@ -4,18 +4,16 @@ import socket
from telegram.ext import ConversationHandler, CommandHandler, CallbackQueryHandler
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ParseMode
import os
FIRST = 1
from .basehandler import BaseHandler
class StatusHandler(BaseHandler):
"""Shows a short status of the program."""
def __init__(self, entry_string, models):
def __init__(self, entry_string):
self.start_time = datetime.datetime.now()
self.entry_string = entry_string
self.models = models
self.handler = ConversationHandler(
entry_points=[CommandHandler(self.entry_string, self.entry_point)],
states={
@ -50,9 +48,11 @@ class StatusHandler(BaseHandler):
local_ips = "not fetchable"
message += "Status: Running 🟢\n"
message += f"Version: `{os.getenv('BOT_VERSION', 'dev')}`\n"
message += f"Uptime: `{delta[:delta.rfind('.')]}`\n"
message += f"IP \(public\): `{ip}`\n"
message += f"IP \(private\): `{local_ips}`\n"
message += f"Chat ID: `{update.effective_chat.id}`\n"
if update.message:
await update.message.reply_text(message, reply_markup=reply_markup, parse_mode=ParseMode.MARKDOWN_V2)

View File

@ -1,7 +1,6 @@
import os
from pathlib import Path
from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, filters, CallbackQueryHandler
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import MessageHandler, filters
from telegram import Update
import re
import random
@ -18,37 +17,47 @@ TURTLE_VIDEOS = list(TURTLE_VIDEO_LOCATION.glob("*.mp4"))
class TurtleHandler(BaseHandler):
def __init__(self):
self.entry_string = "Variation of hallo"
self.handler = MessageHandler(filters.Regex(r"[hH]([aA]+|[eE]+)[lL]{2,}[oOöÖ]+(le)?|(chen)") | # react to hello strings
filters.Regex(b"\xF0\x9F\x90\xA2".decode("utf8")) | # react to turtle emoji
filters.Regex(r"[sS](childkröte)|[tT](urtle)"), # react to turtle string
self.entry_point)
pass
self.handler = MessageHandler(
filters.Regex(r"[hH]([aA]+|[eE]+)[lL]{2,}[oOöÖ]+(le|chen)?") |
# react to hello strings
filters.Regex(b"\xF0\x9F\x90\xA2".decode("utf8")) |
# react to turtle emoji
filters.Regex(r"[sS](childkröte)|[tT](urtle)"),
# react to turtle string
self.entry_point
)
async def entry_point(self, update: Update, context):
await super().entry_point(update, context)
msgtxt = update.message.text
turtle_emoji = b"\xF0\x9F\x90\xA2".decode("utf8")
if "hallo" in msgtxt: # react to hallo
if "hallo" in msgtxt:
# react to hallo
vid = TURTLE_VIDEOS[0]
answertxt = "Hallo!"
elif re.search("[eE][lL]{2,}[oO]", msgtxt): # react to hello
elif re.search("[eE][lL]{2,}[oO]", msgtxt):
# react to hello
vid = TURTLE_VIDEOS[2]
answertxt = "Hello!"
elif re.search("([aA]{4,}|[lL]{4,}|[oO]{4,}|[öÖ]{4,})", msgtxt): # react to stretched hello
elif re.search("([aA]{4,}|[lL]{4,}|[oO]{4,}|[öÖ]{4,})", msgtxt):
# react to stretched hello
vid = TURTLE_VIDEOS[5]
answertxt = "That's a lot of letters!"
elif re.search(turtle_emoji, msgtxt): # react to turtle emoji
vid=TURTLE_VIDEOS[0] # TODO: choose video for smiley reaction
elif re.search(turtle_emoji, msgtxt):
# react to turtle emoji
vid=TURTLE_VIDEOS[0]
answertxt="Turtle detected! Self-destruction mode activated..."
elif re.search("[sS](childkröte)|[tT](urtle)", msgtxt): # react to turtle string
elif re.search("[sS](childkröte)|[tT](urtle)", msgtxt):
# react to turtle string
vid=None
answertxt=turtle_emoji
else:
vid = random.choice(TURTLE_VIDEOS[1:2]+TURTLE_VIDEOS[3:5]+TURTLE_VIDEOS[6:])
answertxt = ""
if vid!=None:
if vid != None:
if re.search(turtle_emoji, msgtxt):
await update.message.reply_text(text=answertxt)
time.sleep(1)

View File

@ -1,22 +1,45 @@
import os
from pathlib import Path
from telegram.ext import ExtBot
import random
from telegram.error import BadRequest
import logging
from datetime import time, timedelta, timezone, datetime, date
from peewee import fn
import models
MEDIA_DIR = Path(os.getenv("MEDIA_DIR"))
CHAT_ID = os.getenv("CHAT_ID")
async def set_random(bot: ExtBot) -> None:
"""Set a random chat photo."""
if os.getenv("DOCKERIZED", "false") == "false":
# only change image on prod
return
class SetChatPhotoJob():
def __init__(self, bot: ExtBot, job_queue):
self.bot = bot
self.logger = logging.getLogger(self.__class__.__name__)
photos = list(MEDIA_DIR.glob("*.jpg")) + list(MEDIA_DIR.glob("*.png")) + list(MEDIA_DIR.glob("*.jpeg"))
if os.getenv("DOCKERIZED", "false") != "true":
# when running locally, annoy the programmer every 60 seconds <3
job_queue.run_repeating(self.callback_photo, interval=60)
else:
# set the message sending time; include UTC shift +2
sending_time = time(hour=12, minute=0, second=0, tzinfo=timezone(timedelta(hours=2)))
job_queue.run_monthly(self.callback_photo, when=sending_time, day=-1)
if len(photos) == 0:
return
photo = random.choice(photos)
await bot.set_chat_photo(CHAT_ID, photo)
async def callback_photo(self, context):
# last_seen of memory must be older than 10 days in past or None
with models.db:
possible_photos = models.JournalEntry.select().where(
models.JournalEntry.media_path != None
).order_by(fn.Random())
try:
chosen_entry = possible_photos.get()
except:
self.logger.warning("No photos available.")
return
chat_id = os.getenv("CHAT_ID")
try:
await self.bot.set_chat_photo(chat_id, chosen_entry.media_path)
except BadRequest:
self.logger.error("This is a private chat!")
return

View File

@ -0,0 +1,65 @@
from datetime import time, timedelta, timezone, datetime, date
from telegram.constants import ParseMode
import os
from peewee import fn
import logging
import models
class RandomMemoryJob():
def __init__(self, bot, job_queue):
self.bot = bot
self.logger = logging.getLogger(self.__class__.__name__)
if os.getenv("DOCKERIZED", "false") != "true":
# when running locally, annoy the programmer every 60 seconds <3
job_queue.run_repeating(self.callback_memory, interval=3600)
self.min_age = 0 # do not filter messages: show them all
else:
# set the message sending time; include UTC shift +2
sending_time = time(hour=12, minute=0, second=0, tzinfo=timezone(timedelta(hours=2)))
job_queue.run_daily(self.callback_memory, sending_time)
self.min_age = 30 # days
async def callback_memory(self, context):
# last_seen of memory must be older than 10 days in past or None
with models.db:
possible_entries = models.JournalEntry.select().where(
(models.JournalEntry.last_shown <= datetime.today().date() - timedelta(days=self.min_age)) | \
(models.JournalEntry.last_shown == None)
).order_by(fn.Random())
try:
chosen_entry = possible_entries.get()
except:
self.logger.warning("Come back later for another memory.")
return
# update the last_shown of the chosen entry
chosen_entry.last_shown = datetime.today().date()
chosen_entry.save()
chat_id = os.getenv("CHAT_ID")
rating_string = f" ({models.RATING_MAPPING[chosen_entry.rating]})" if chosen_entry.rating else ""
message_text = f"On {chosen_entry.date_pretty}{rating_string}, " \
f"{chosen_entry.author} wrote: \n" \
f"{chosen_entry.spoiler_text}"
if chosen_entry.media_path:
await self.bot.send_photo(
chat_id = chat_id,
photo = chosen_entry.media_path,
caption = message_text,
parse_mode=ParseMode.HTML
)
else:
await self.bot.send_message(
chat_id = chat_id,
text = message_text,
parse_mode=ParseMode.HTML
)

View File

@ -5,14 +5,13 @@ import logging
import models
from commands import journal, status, turtle, memory, advent
from commands.list import list
from cronjob import chat_photo
from cronjob import chat_photo, random_memory
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.INFO
)
import asyncio
logging.getLogger("httpx").setLevel(logging.WARNING)
logger = logging.getLogger(__name__)
@ -24,22 +23,16 @@ def main() -> None:
models.set_db(db_path)
application = Application.builder().token(token).build()
application.add_handler(journal.JournalHandler("journal", models).handler)
application.add_handler(list.ListHandler("list", models).handler)
application.add_handler(status.StatusHandler("status", models).handler)
application.add_handler(journal.JournalHandler("journal").handler)
application.add_handler(list.ListHandler("list").handler)
application.add_handler(status.StatusHandler("status").handler)
application.add_handler(turtle.TurtleHandler().handler)
application.add_handler(memory.MemoryHandler("memory", models).handler)
application.add_handler(memory.MemoryHandler("memory").handler)
application.add_handler(advent.AdventsHandler("advent").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))
random_memory.RandomMemoryJob(application.bot, application.job_queue)
chat_photo.SetChatPhotoJob(application.bot, application.job_queue)
# on every start set a new chat photo
# loop = asyncio.get_event_loop()
asyncio.ensure_future(chat_photo.set_random(application.bot))
# Run the bot until the user presses Ctrl-C
application.run_polling()

View File

@ -1,5 +1,6 @@
from peewee import *
from pathlib import Path
import re
import os
import datetime
@ -9,6 +10,14 @@ ID_MAPPINGS = {
}
ID_MAPPINGS_REV = dict((v, k) for k, v in ID_MAPPINGS.items())
RATING_MAPPING = {
1: "😵",
2: "☹️",
3: "😐",
4: "😃",
5: "🥰"
}
MEDIA_DIR = Path(os.getenv("MEDIA_DIR"))
MEDIA_DIR.mkdir(parents=True, exist_ok=True)
@ -27,7 +36,7 @@ class JournalEntry(BaseModel):
text = TextField(null=True)
media_path = TextField(null=True)
last_shown = DateField(null=True)
rating = IntegerField(null=True) # mapped by RATING_MAPPING
@property
def media(self):
@ -60,6 +69,25 @@ class JournalEntry(BaseModel):
except ValueError: #fck windows
return self.date.strftime('%a, %d. %b %Y')
@property
def spoiler_text(self) -> str:
"""Returns the text with all the frisky details hidden away"""
new_text = self.text.replace("<", "&lt;").replace(">", "&gt;").replace("&", "&amp;")
pattern = re.compile(
"("
"(((?<=(\.|\!|\?)\s)[A-Z])|(^[A-Z]))" # beginning of a sentence
"([^\.\!\?])+" # any character being part of a sentence
"((\:\))|😇|😈|[Ss]ex)" # the smiley
"([^\.\!\?])*" # continuation of sentence
"(\.|\!|\?|\,|$)" # end of the sentence
")"
)
matches = pattern.findall(new_text)
for match in matches:
group_to_replace = match[0]
new_text = new_text.replace(group_to_replace, f"<tg-spoiler>{group_to_replace}</tg-spoiler>")
return new_text
def set_db(db_path):
db.initialize(SqliteDatabase(db_path))

View File

@ -1,12 +1,11 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: journal
name: journal-bot
labels:
app: journal-bot
spec:
# deployment running a single container
# deployment running a single container
selector:
matchLabels:
app: journal-bot
@ -18,8 +17,7 @@ spec:
spec:
containers:
- name: journal
image: mollre/journal-bot:latest
imagePullPolicy: Always
image: mollre/journal-bot:1.0.19
envFrom:
- secretRef:
name: journal-secret-env
@ -39,12 +37,9 @@ spec:
apiVersion: v1
kind: PersistentVolume
metadata:
namespace: journal
name: "journal-data-nfs"
# labels:
# directory: "journal-data"
spec:
storageClassName: fast
storageClassName: ""
capacity:
storage: "5Gi"
accessModes:
@ -52,21 +47,17 @@ spec:
nfs:
path: /export/kluster/journal-bot
server: 192.168.1.157
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
namespace: journal
name: "journal-data-nfs"
spec:
storageClassName: "fast"
storageClassName: ""
accessModes:
- ReadWriteOnce
resources:
requests:
storage: "5Gi"
# selector:
# matchLabels:
# directory: "journal-data"
volumeName: journal-data-nfs

View File

@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./namespace.yaml
- ./deployment.yaml
- ./sealedsecret.yaml
images:
- name: mollre/journal-bot
newTag: 1.0.68

View File

@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: journal
labels:
name: journal

View File

@ -0,0 +1,25 @@
{
"kind": "SealedSecret",
"apiVersion": "bitnami.com/v1alpha1",
"metadata": {
"name": "journal-secret-env",
"namespace": "journal",
"creationTimestamp": null
},
"spec": {
"template": {
"metadata": {
"name": "journal-secret-env",
"namespace": "journal",
"creationTimestamp": null
},
"type": "Opaque"
},
"encryptedData": {
"BOT_TOKEN": "AgBcFTg4wRI37/sXlk7bNO3IB9dC2CaVi/Oh9TQeQ/wN+rRkTTqp/dBpzX3Y1Zcp16d59AqT7y3DafGGZ/V87zcxG1bngdCZUsZfDmZMP0+z+10caMxjbSY4xfBW1/MEL3rW6ONOibhTAI9DDS3p3YCu1V92xRLvOUkwc+mCkV7fneWWGU/wgeci+C75PKTyGIilo5NZXROOyytN7BQwvOiY70j9m/NC9L0Ulbcppho9iuVsYVfkkWHOU6/OcOeL7vjWcvYFTleyI0oclLgtBUSJzBTqe5eJeZPGoVWMGwyMw2BqR8DgeGpDIuSnMEgssh9wUlhVvqkoI7CEUrJy5Rb2YnWcriIbfUfUMwbfc4EpBKt1VVlQcEQmN9jJdoOJ81ywRXl6CJTMMM4apB3iHsBWdzVXCG4I5c6Mv8+xg0V+AYdDt4pGwuRX9s66LShnjFJKnn68chNLnGfNlU68YdwFio0GJkV0/FnXIgTrOwdOovtBz1Gl3ORIWTmSkY7yBRyYBzvzEBlXBAuj51yhdykrmuW6B5CvwqXsm3ia1fvtWwNfvmKySjzbHZQHmbbYR9hLvWm+rPS7TFXw52W6jUyvHh6U2mSHwpwI2byIE+uhXjVQgYbmDgJW2gif3Aam+2VSaGSqWUz7ECSGy4mVC755CyoZl0HDP4PxuHq5kcGm34qmjTRNYM6Y2QvaVb7cBplsZfs+cH+gcfVu2gg3KvAEaFJk85Hz4pirRhcPsLNce6Iw5OegCZ5IQBrzOJXC",
"CHAT_ID": "AgDIgpsygMIcsTDy8a49isS4Hfkmqa0oav+q7Mu7VtcPyrZ4o7hR1u/IlH8Qt4Cg/9QxOw7rJ4DfbK4GDmiOO1oOf0uaR6btLl+/GoKT3mbSHusWfHPrJDGX0SBFw7rOopC+LyFgDHPJEhbKviwnyrBkUuI6gnf1sic4jJ9arb/B97y89dMKFlVCbEzRCrTCK6WDBQ3Lpk+5MI+ugAPSKC8CqsjNc6jmWymdGMk/9n3sAdalfYBCucxHKeVgkrv4sPr9jEUEzIziKansavTs8qVbZgSUMEAAob2KBIAXLcRmo5ISwKvppuA6DMbbXEYEMHVJH9B4gI2eAxClOPVEOBElL+BtsJaSJnJbVEclMzOqwxXQRFPOq4BKxhguA+Uj8Vl8/2diwXEJoUiCZ5emGVvCFQd+Dr2LUPj4AO1AL4zAg+VahuqNV2gI/Dkxgt7Hj+i6jY/jmbk3MIJYjeZh0irmfsWQmUMcmizhxutQdV3kXhHSlomVDHuIdFHFIbjQrI8vSgeysQARSxrJZvt/qeNUNnD1InKa/EQ8I5XDX4o4qIV/pqY8XLVoTcciYDOPZEy3OleHK+26SJDkJOiDOAHbfIBeinaLvYIEW3BwgrakBD16HaNzYBPLPW2ikDCSBTyFRayvfkWHHUGawhdrauxvZzp5UsJViZogypBJuDT3SPvAOlAR4X8Yfr9SmwQYKv8rALH+wW7QtON6R9D7UA==",
"DB_PATH": "AgACucJGoBiO/ymyf6FvEeuQ2MDo+c+VgNk30xY2EZSQZpAbNE6VbaMO0lZj++T82OOBnhfmXID+TWJTIwIHaD2nkPq/ISppBIobVmtUmsR+sm76tao02HJCtPGycyCu1zhEpKtwy3k5nsd0jclq4bQFHccnBaBdZ6xcvmevvJ+YddysHhjSb6ESOoah/5lGiAa3sHe1Hwg57FPZeVuZOCx+MbbmhAXCYbu2bdZzSWA/mFAf1F6qkxSAuVFMJtijPrM13UIVONBPg5E02NO1VEV+LkI5NTUNx9YHVlGNPxogabDq+lhNwulWtLPbKkAXn/CTgcB2vb03geeVN20yz1UzbrdV5CKpIGGZ1At8ehuNypFa595XBVFSmL8RWNmfHCAvypAypjxOMWa89qC0diJW4tY+BUrl2jrIXpARNlD2GTqp7InLtwFsFb3AUbpg+0mnqqiqmtqYKQWJj0WDvfs7ol6k6Qx7P0FdAfRq3ojzArRQ7MruI24CS1hGTQ/hBJaHrcMzEIn/ZkKqZ2fEdNkJt8tTfxVsZ/paE97ERfYeKsuK2uHqUgvSQ+0w7FK7m6PYNpY9gmqZMaqRA7VIRblNauEuLDAGw8Jgyb3YUiV3xLjBuvaCaAEbXOsNsIF35+ZCw2bsYmgSxqNO2b1LvW/uFSUonjVJ9yT9+Qv6V0YJhMztzDLpNKRIEBKgyUN/BE7hV9vtygaan/AkUVmHVA9BwrU=",
"PERSISTENCE_DIR": "AgDF8D5PfJ4DF7wNd8hpEPdph3r/MvK8R/sREX83/b7jFJgSGb/Dku82vwtkDTzsk9A+gGgU//EILYt5Irlo5ObHlcKfimR4fTvdcO9lpBHJnbwXipUcg20Xz/awIGbD3yJmy0LJqgc5MVPtWicF/ZsxQkkcv3+DN4+BgXczncEL+3g55eEbCAwbmFSvdHWIZGbi04VmtmAlSduPVzi7nqH05Nslqtu4p5mZaxPHjGvna0DcIVQNFQC/Wgobox8pezeJ6tANUPFAUpJUp+E5N3q8DofZXiHBQTpNXo3tyM2JYT/IwovSIdPSgJeIhbrfP6hVKOeZjKqaC8/SV67R/1LUpdO7KeKig5d7LJa3vjeeDmrM/3+1vb0C96Xrgv39j4MyPx7HrZxFdOQif4PZlpLEfarEtuSFUAUXx4N2uhLbTyAXyl4dfGkqdbQ5O/UT6xxXw44JsK6DzOz5OkT6cB0uUvJa5TrHk+cVoxlUu3Ex/5o6KXnMFaxfzyizPXeiIs/mTT9Bq6nAtvGad84U6Wvua3ZPofOlH0gFyN8/uMJxwqXbKuO1iScjkxuCNX8YRFzcoWH7VXzbbNPIQLORTu9/PhAIRZXOSxZw2iPZVg3LKuyyW3MgTtnVvgrKYnynw1Yrvc7gu35MhwjvnRrPlVQ+yFrZuB3l2Cf0OWZwonlMr36TsPHIJq+wD4ZEja+ciOsRAWzWuxBEDQ=="
}
}
}

13
renovate.json Normal file
View File

@ -0,0 +1,13 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch"],
"matchCurrentVersion": "!/^0/",
"automerge": true,
"automergeType": "branch",
"ignoreTests": true
}
],
"commitMessagePrefix" : "[CI SKIP]"
}