Package: telegram-spotted-dmi-bot
Telegram-SpottedDMI-BotTelegram-SpottedDMI-Botis the platform that powers@Spotted_DMI_Bot, a Telegram bot that let students send an anonymous message to the channel community.🔴 Using the live versionThe bot is live on Telegram with the username@Spotted_DMI_Bot.
To see the posts, once published, checkSpotted DMISend'/start'to start it,'/help'to see a list of commands.Please note that the commands and their answers are in Italian.🤖 Telegram bot setupIf you want to deploy your own version of this bot, you will need to have a telegram bot available. You should readthis guidefor more details, but in short:Send a message to@BotfatherFollow the guided procedureYou will receive a token. Whoever knows that token has complete control over your bot, so handle it with careYou will need that token later, for it is a needed value in the settings📂 Project structure.
├──.devcontainer# DevContainer configuration for VsCode├──.github/workflows# CI/CD workflows├──docs# Documentation├──scripts# Utility script for setting up the project├──src
│├──spotted# Main package││├──__init__.py# Init file for the package││├──__main__.py# Entry point for the package││├──config# Configuration files││├──data# Data related function││├──debug# Debug related functions││├──handlers# Collection of handlers for the bot││└──utils# Utility functions├──tests# Tests│├──e2e# End to end tests│├──integration# Integration tests│└──unit# Unit tests├──Dockerfile# Dockerfile used to build the image├──pyproject.toml# Package configuration file└──README.md# This file💻 Setting up a local instance for contributing (from git)System requirementsPython 3 (3.10)pip3DependenciesAll the requirements are listed in thepyproject.tomlfile.
The most important ones are:python-telegram-botrequestsPyYAMLInstall withpip3# [Optional] Create a virtual environmentpython3-mvenv.venv# [Optional] Activate the virtual environmentsource.venv/bin/activate# Linux.venv\Scripts\activate.bat# Windows# Using the -e flag will install the package in editable mode# If you change the code, you won't need to reinstall the package# If you want to install it in a non-editable mode, just remove the -e flagpip3install-e.StepsClone this repositoryCreate a"settings.yaml"file and edit the desired parameters.It must contain at least a valid'token'and'post.admin_group_id'values.You could also skip the files and useenvironment variablesinstead.Make sure the bot is in present both in the admin group and in the spot channel. It may need to have admin privileges. If comments are enabled, the bot has to be in the comment group too as an admin.Runpython3 -m spottedtostart the bot💻 Setting up a local instance for running (from pip)System requirementsPython 3 (3.10)pip3Install withpip3Install the package:pip3installtelegram-spotted-dmi-botStepsCreate a"settings.yaml"file and edit the desired parameters.It must contain at least a valid'token'and'post.admin_group_id'values.You could also skip the files and useenvironment variablesinstead.Runpython3 -m spottedtostart the bot🐳 Setting up a Docker containerSystem requirementsDockerStepsClone this repositoryMake sure the bot is in present both in the admin group and in the spot channel. It may need to have admin privileges. If comments are enabled, the bot has to be in the comment group too as an admin.Rundocker build --tag spotted-image .When starting the container, useenvironment variablesto configure the bot.Rundocker run -d --name spotted -e TOKEN=<token_arg> [other env vars] spotted-image[!Tip]When it is built, the container will copy the"settings.yaml"and the"autoreplies.yaml"files, in the root directory, if present.
While it is possible to provide the configuration this way, it is recommended to use the environment variables instead, as they will override the values from the files.[!Warning]The database file created inside the container will be lost when the container is removed.
If you want to keep the database, you should mount a volume to the container.
You can do so by adding the-v <host_path>:<container_path>flag to thedocker runcommand.
See theexamplesfor more details.ExamplesFirst rundockerbuild--tagspotted-image.Then something likedockerrun-d--namespotted-container-eTOKEN=<token_arg>-ePOST_CHANNEL_ID=-4-ePOST_GROUP_ID=-5-ePOST_CHANNEL_GROUP_ID=-6spotted-imageIf you want to check the logs in real time, you can run# -f flag to follow the logs, otherwise it will just print the last onesdockerlogs-fspotted-containerIf you want to access the container's shell, you can rundockerexec-itspotted-container/bin/bashMounting a volumeIf you want to keep the database file, you can mount a volume to the container.
This will assume the default database path, which is"./spotted.sqlite3".# The file will survive the container removal, stored in the volume "spotted-db"dockerrun-d--namespotted-container-vspotted-db:/app-eTOKEN=<token_arg>-ePOST_CHANNEL_ID=-4-ePOST_GROUP_ID=-5-ePOST_CHANNEL_GROUP_ID=-6spotted-imageIf you want to be able to access the database file from the host, you can use a bind mount instead.# The file will be available in the host under the path "./spotted.sqlite3"dockerrun-d--namespotted-container-v.:/app-eTOKEN=<token_arg>-ePOST_CHANNEL_ID=-4-ePOST_GROUP_ID=-5-ePOST_CHANNEL_GROUP_ID=-6spotted-imagePackage versionIf you want to change the version displayed by the package inside the container, you can do when building the image:dockerbuild--tagspotted-image--build-argVERSION=<version>.# Exampledockerbuild--tagspotted-image--build-argVERSION=3.0.0.Keep in mind that this will only change the version displayed bypython3 -m spotted --version, not the version of the package itself.To stop/remove the container:Rundocker stop spotted-containerto stop the containerRundocker rm -f spotted-containerto remove the container📦 DevContainerThe VsCodeRemote - Containersextension lets you use a Docker container as a full-featured development environment. It allows you to open any folder inside (or mounted into) a container and take advantage of VsCode's full feature set.System requirementsVsCodeDockerStepsStart VsCode, run theRemote-Containers: Reopen in containercommand from the Command Palette (F1)Running the botAfter installation, the bot can be started with the command:python3-mspottedThere are a few command-line arguments you can use to customize the bot behaviour:--settingsor-s: path to the"settings.yaml"file. Default:"./settings.yaml"(relative to the pwd)--auto-repliesor-a: path to the"auto_replies.yaml"file. Default:"./auto_replies.yaml"(relative to the pwd)Also, keep in mind that the bot will generate an sqlite database file in the path indicated by thesettings.yamlfile named"spotted.sqlite3"by default. The file will be created if missing, but thepath must be valid.
Lastly, if logs are enabled, the bot will log under the path specified insettings.yaml.
By default, it would be"logs/spotted.log"and"logs/spotted_error.log".
The pathwill be createdif it does not exist.SettingsWhen it is initialized, the bot reads both the"config/yaml/autoreplies.yaml"and the"config/settings.yaml"files inside the package, which contain the default values for the settings.
Then the configuration gets overwritten using the"settings.yaml"and the"auto_replies.yaml"files you provide.
The bot expects to find both files in thepwddirectory, meaning the directory from which you run the bot.
You can change this behaviour by specifying the path to the files with the--configand--auto-repliesflags.python3-mspotted-c/path/to/settings.yaml-a/path/to/autoreplies.yamlFeel free to customize the settings file,but make sure to add a validtokenandpost.admin_group_idvalues, since they are mandatory.# config/settings.yamldebug:local_log:false# save each and every message in a log file. Make sure the path "logs/messages.log" is valid when enabledreset_on_load:false# whether or not the database should reset every time the bot launches. USE CAREFULLYlog_file:"logs/spotted.log"# path to the log file, if local_log is enabled. Relative to the pwdlog_error_file:"logs/spotted_error.log"# path to the error log file. Relative to the pwddb_file:"spotted.sqlite3"# path to the database file. Relative to the pwd# key used to encrypt the database backup sent to the admin periodically.# Must be 32 bytes long and base64 encoded.# If not specified (default), the backup will be sent in clear textcrypto_key:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"post:# id of the group associated with the channel. Telegram will send automatically forward the posts there. Required if comments are enabledcommunity_group_id:-100channel_id:-200# id of the channel to which the bot will send the approved postschannel_tag:"@channel"# tag of the channel to which the bot will send the approved postscomments:true# whether or not the channel the bot will send the posts to has comments enabledadmin_group_id:-300# id of the admin group the bot will usen_votes:2# votes needed to approve/reject a pending postremove_after_h:12# pending posts older than this number of hours will be removed by /clean_pendingreport_wait_mins:30# number of minutes the user has to wait before being able to report another user againreport:true# whether to add a report button as an inline keyboard after each post# whether the bot should delete any anonym comment coming from a channel.# The bots must have delete permission in the group and comments must be enableddelete_anonymous_comments:true# whether the bot should replace any anonymous comment with a message by itself.# WARNING:delete_anonymous_comments must be true for this option to make sense.# Otherwise the comment would be doubled.# The bots must have delete permission in the group and comments must be enabledreplace_anonymous_comments:falsetoken:xxxxxxxxxxxx# token of the telegram botbot_tag:"@bot"# tag of the telegram botSettings overrideThe settings may also be set through environment variables.All the env vars with the same name (case insensitive) will override the ones in the settings file.
To update thepostsettings, prefix the env var name withPOST_. The same is true for thedebugsettings, to be prefixed withDEBUG_.# Environment values
TOKEN=xxxxxx        # will override the *token* value found in settings.yaml
POST_N_VOTES=4      # will override the *post.n_votes* value found in settings.yaml
DEBUG_LOCAL_LOG=4   # will override the *debug.local_log* value found in settings.yamlThe complete order of precedence for the application of configuration settings isenv var > (user provided) settings.yaml > (package provided) settings.yaml[!Note]
The bot provides a/reloadcommand that will reload the settings without restarting the bot.
Keep in mind that the order of precedence will be the same, meaning that the env vars will always override thesettings.yamlfiles.Since every setting has a default value specified in the defaultsettings.yamlexcept fortokenand thechat_ids of the groups and the channel, those are the only necessary setting to add when setting up the bot for the first time.
All other values will be assigned a valid default value if not specified.Settings typingTypings are provided by default for eny value specified through the.yamlfiles.
On the other hand, if you use the environment variables, everything will be treated as a string.To prevent this, you can use thesettings.yaml.typesspecifying a type for each setting.
This way it will be casted in the specified type.Supported types:boolintfloatlist (of str)Any unknown type won't be casted.
This means that env var will remain strings.# settings.yaml.typesdebug:local_log:boolreset_on_load:boollog_file:strlog_error_file:strdb_file:strcrypto_key:strpost:community_group_id:intchannel_id:intchannel_tag:strcomments:booladmin_group_id:intn_votes:intremove_after_h:intreport:boolreport_wait_mins:intreplace_anonymous_comments:booldelete_anonymous_comments:booltoken:strbot_tag:str🧪[Optional]Setting up testing and lintingIf you plan to contribute to this project, you may want to run the tests and the linters locally.[!Note]When creating a pull request, all the tests and linters will be run automatically using thegithub actions.
If the tests fail, the pull request won't be merged until all the errors are fixed.
Hence, it is recommended to run the tests and the linters locally before pushing your changes.DependenciesAll the dev requirements are listed in thepyproject.tomlfile under[project.optional-dependencies].pytestpytest-covpytest-mockpytest-asynciopylintblackisortInstall withpip3After having cloned the repository and having installed the main package withpip3 install -e ., you can install the dev dependencies with:pip3install-e.[test]pip3install-e.[lint]Testing:Runpytest tests/unitto run the unit testsRunpytest tests/integrationto run the integration testsLinting:Runpylint src teststo lint the codeRunblack --check src teststo make sure the code is formatted correctly. If it is not, you can runblack srcto format it automaticallyRunisort --check-only src teststo make sure the imports are sorted correctly. If they are not, you can runisort srcto sort them automaticallyScriptsThescriptfolder contains some utility scripts such asscript/local-ci.shthat can be used to simulate the whole CI pipeline locally.
Make sure to have the dev dependencies installed before running them.Furthermore, the package provides some utility scripts:run_sqlscript that can be used to run an arbitrary sql script on the indicated sqlite3 database.f_cryptoscript that can be used to encrypt/decrypt files with a key or generate a new key.run_sql<path_to_sql_script><path_to_db_file># Examplerun_sql./script/create_db.sql./spotted.sqlite3f_crypto<encrypt|decrypt><input_file><output_file>--key<key># Examplef_cryptoencrypt./spotted.sqlite3./spotted.sqlite3.enc--keyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx# Generate a new keyf_cryptogenerate_key[!Important]
Make sure to backup your database before running any scripts on it, since all alteration will happen in place, and there is no way to undo them.📚 DocumentationLink to the documentation