From 9c15227cbf26894baae98fe1e1f6078be83c91f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mi=C5=82osz=20Guglas?=
<32432158+miloszowi@users.noreply.github.com>
Date: Sat, 18 Sep 2021 15:30:56 +0200
Subject: [PATCH] Initial commit
---
.env.local | 8 ++
.gitignore | 129 +++++++++++++++++++++
LICENSE | 21 ++++
Procfile | 1 +
README.md | 67 +++++++++++
docs/commands.png | Bin 0 -> 28149 bytes
docs/everyone_command.png | Bin 0 -> 9379 bytes
docs/everyone_noone_to_mention.png | Bin 0 -> 8903 bytes
docs/in_command.png | Bin 0 -> 9444 bytes
docs/in_command_already_opted_in.png | Bin 0 -> 9554 bytes
docs/logo.png | Bin 0 -> 26458 bytes
docs/out_command.png | Bin 0 -> 9557 bytes
docs/out_command_did_not_opt_in_before.png | Bin 0 -> 9956 bytes
entrypoint.py | 6 +
requirements.txt | 3 +
runtime.txt | 1 +
src/app.py | 34 ++++++
src/config/contents.py | 8 ++
src/config/credentials.py | 16 +++
src/config/handlers.py | 9 ++
src/firebaseProxy.py | 34 ++++++
src/handlers/handlerInterface.py | 18 +++
src/handlers/inHandler.py | 39 +++++++
src/handlers/mentionHandler.py | 42 +++++++
src/handlers/outHandler.py | 39 +++++++
src/repositories/groupRepository.py | 18 +++
src/repositories/userRepository.py | 30 +++++
27 files changed, 523 insertions(+)
create mode 100644 .env.local
create mode 100644 .gitignore
create mode 100644 LICENSE
create mode 100644 Procfile
create mode 100644 README.md
create mode 100644 docs/commands.png
create mode 100644 docs/everyone_command.png
create mode 100644 docs/everyone_noone_to_mention.png
create mode 100644 docs/in_command.png
create mode 100644 docs/in_command_already_opted_in.png
create mode 100644 docs/logo.png
create mode 100644 docs/out_command.png
create mode 100644 docs/out_command_did_not_opt_in_before.png
create mode 100644 entrypoint.py
create mode 100644 requirements.txt
create mode 100644 runtime.txt
create mode 100644 src/app.py
create mode 100644 src/config/contents.py
create mode 100644 src/config/credentials.py
create mode 100644 src/config/handlers.py
create mode 100644 src/firebaseProxy.py
create mode 100644 src/handlers/handlerInterface.py
create mode 100644 src/handlers/inHandler.py
create mode 100644 src/handlers/mentionHandler.py
create mode 100644 src/handlers/outHandler.py
create mode 100644 src/repositories/groupRepository.py
create mode 100644 src/repositories/userRepository.py
diff --git a/.env.local b/.env.local
new file mode 100644
index 0000000..a0bec50
--- /dev/null
+++ b/.env.local
@@ -0,0 +1,8 @@
+bot_token=
+firebase_apiKey=
+firebase_authDomain=
+firebase_databaseURL=
+firebase_projectId=
+firebase_storageBucket=
+app_url=
+PORT=
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b6e4761
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,129 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..beeb482
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 MiĆosz Guglas
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Procfile b/Procfile
new file mode 100644
index 0000000..fe54d30
--- /dev/null
+++ b/Procfile
@@ -0,0 +1 @@
+web: python entrypoint.py
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2d254aa
--- /dev/null
+++ b/README.md
@@ -0,0 +1,67 @@
+#
[everyone-mention-telegram-bot](http://t.me/everyone_mention_bot)
+
+
simple, but useful telegram bot to gather all of group members attention!
+
+
+## Contents
+
+* [Getting started.](#getting-started)
+ * [Installation](#installation)
+ * [Requirements](#requirements)
+ * [Env file](#env-file)
+* [Commands](#commands)
+ * [`/in`](#in)
+ * [`/out`](#out)
+ * [`/everyone`](#everyone)
+
+### Getting started
+#### Installation
+```bash
+git clone https://github.com/miloszowi/everyone-mention-telegram-bot.git
+pip install -r requirements.txt
+python entrypoint.py
+```
+
+#### Requirements
+- `python` with version specified in `runtime.txt`
+- `pip` with version `20.0.2`
+
+#### Env file
+```bash
+cp .env.local .env
+```
+and then fulfill copied `.env` file with required values
+- `bot_token` - your telegram bot token from [BotFather](https://telegram.me/BotFather)
+- `firebase_*` - all of those values you can find in firebase console
+- `app_url` - your app url for retrieving webhooks
+- `PORT` - port for your app
+
+### Commands
+#### `/in`
+Will sign you in for everyone-mentions.
+
+
+
+If you have already opted-in before, alternative reply will be displayed.
+
+
+
+#### `/out`
+Will sign you off for everyone-mentions.
+
+
+
+If you haven't opted-in before, alternative reply will be displayed.
+
+
+
+#### `/everone`
+Will mention everyone that opted-in for everyone-mentions separated by spaces.
+
+If user does not contain nickname, his ID will be present instead of nickname.
+
+
+
+If there are no users that opted-in for mentioning, alternative reply will be displayed.
+
+
diff --git a/docs/commands.png b/docs/commands.png
new file mode 100644
index 0000000000000000000000000000000000000000..24caf9d54023405748428ebb8558dd3e091f9349
GIT binary patch
literal 28149
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