mirror of
https://github.com/miloszowi/everyone-mention-telegram-bot.git
synced 2025-05-20 09:14:07 +00:00
changed mongoDb collection structure, removed group entity & repository, updated README.md, changed folder names to singular forms
This commit is contained in:
parent
baa8a78cad
commit
cd8e3507ca
60
README.md
60
README.md
@ -3,53 +3,61 @@
|
||||
<p align="center"> simple, but useful telegram bot to gather all of group members attention!
|
||||
<!-- Icon made by https://www.freepik.com from https://www.flaticon.com/ -->
|
||||
|
||||
## Contents
|
||||
# Contents
|
||||
|
||||
* [Getting started.](#getting-started)
|
||||
* [Installation](#installation)
|
||||
* [Requirements](#requirements)
|
||||
* [Env file](#env-file)
|
||||
* [Installation](#installation)
|
||||
* [Logs](#logs)
|
||||
* [Env files](#env-files)
|
||||
* [Commands](#commands)
|
||||
* [`/in`](#in)
|
||||
* [`/out`](#out)
|
||||
* [`/everyone`](#everyone)
|
||||
|
||||
### Getting started
|
||||
#### Installation
|
||||
## Getting started
|
||||
|
||||
### Requirements
|
||||
- `docker-compose` in version `1.25.0`
|
||||
- `docker` in version `20.10.7`
|
||||
|
||||
### 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 files
|
||||
First, copy env files for database and app containers
|
||||
after that, you need to copy env files and fulfill it with correct values
|
||||
```bash
|
||||
cp docker/config/app/app.dist.env docker/config/app/app.env
|
||||
cp docker/config/database/database.dist.env docker/config/app/app.env
|
||||
cp docker/config/app.dist.env docker/config/app.env
|
||||
cp docker/config/database.dist.env docker/config/app.env
|
||||
```
|
||||
and then fulfill copied `.env` files with required values
|
||||
|
||||
and finally, you can run the bot by launching docker containers
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
(`-d` flag will run containers in detached mode)
|
||||
### Logs
|
||||
You can use
|
||||
```bash
|
||||
docker/logs <container>
|
||||
```
|
||||
to check container logs
|
||||
### Env files
|
||||
app.env
|
||||
- `bot_token` - your telegram bot token from [BotFather](https://telegram.me/BotFather)
|
||||
- `BOT_TOKEN` - your telegram bot token from [BotFather](https://telegram.me/BotFather)
|
||||
- `MONGODB_DATABASE` - MongoDB database name
|
||||
- `MONGODB_USERNAME` - MongoDB username
|
||||
- `MONGODB_PASSWORD` - MongoDB password
|
||||
- `MONGODB_HOSTNAME` - MongoDB host (default `database` - container name)
|
||||
- `MONGODB_PORT` - MongoDB port (default `port` - given in docker-compose configuration)
|
||||
- `MONGODB_PORT` - MongoDB port (default `27017` - given in docker-compose configuration)
|
||||
|
||||
database.env
|
||||
- `MONGO_INITDB_ROOT_USERNAME` - conf from `app.env`
|
||||
- `MONGO_INITDB_ROOT_PASSWORD` - conf from `app.env`
|
||||
- `MONGO_INITDB_DATABASE` - conf from `app.env`
|
||||
- `MONGODB_DATA_DIR` - directory to store MongoDB documents (inside a container)
|
||||
- `MONDODB_LOG_DIR` - log file
|
||||
### Commands
|
||||
#### `/in`
|
||||
- `MONDODB_LOG_DIR` - path to logs storage
|
||||
## Commands
|
||||
### `/in`
|
||||
Will sign you in for everyone-mentions.
|
||||
|
||||

|
||||
@ -58,7 +66,7 @@ If you have already opted-in before, alternative reply will be displayed.
|
||||
|
||||

|
||||
|
||||
#### `/out`
|
||||
### `/out`
|
||||
Will sign you off for everyone-mentions.
|
||||
|
||||

|
||||
@ -67,10 +75,10 @@ If you haven't opted-in before, alternative reply will be displayed.
|
||||
|
||||

|
||||
|
||||
#### `/everone`
|
||||
### `/everyone`
|
||||
Will mention everyone that opted-in for everyone-mentions separated by spaces.
|
||||
|
||||
If user does not have nickname, it will assign random name from `names` python library to his ID
|
||||
If user does not have nickname, it will first try to assign his firstname, then random firstname from `names` python library
|
||||
|
||||

|
||||
|
||||
|
@ -6,7 +6,7 @@ services:
|
||||
image: mongo:4.0.8
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ./docker/config/database/database.env
|
||||
- ./docker/config/database.env
|
||||
volumes:
|
||||
- db-data:/data/db
|
||||
ports:
|
||||
@ -18,7 +18,7 @@ services:
|
||||
build: .
|
||||
command: python app.py
|
||||
env_file:
|
||||
- ./docker/config/app/app.env
|
||||
- ./docker/config/app.env
|
||||
volumes:
|
||||
- ./src:/src
|
||||
ports:
|
||||
|
23
src/app.py
23
src/app.py
@ -1,15 +1,17 @@
|
||||
from config.credentials import bot_token
|
||||
from config.handlers import handlers
|
||||
from handlers.handlerInterface import HandlerInterface
|
||||
from telegram.ext.dispatcher import Dispatcher
|
||||
from telegram.ext import Updater
|
||||
from telegram.ext.dispatcher import Dispatcher
|
||||
|
||||
from config.credentials import BOT_TOKEN
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
from handler import (inHandler, mentionHandler, outHandler)
|
||||
|
||||
|
||||
class App:
|
||||
updater: Updater
|
||||
dispatcher: Dispatcher
|
||||
|
||||
def __init__(self):
|
||||
self.updater = Updater(bot_token)
|
||||
self.updater = Updater(BOT_TOKEN)
|
||||
|
||||
def run(self) -> None:
|
||||
self.registerHandlers()
|
||||
@ -18,14 +20,13 @@ class App:
|
||||
self.updater.idle()
|
||||
|
||||
def registerHandlers(self) -> None:
|
||||
for handler in handlers:
|
||||
if not isinstance(handler, HandlerInterface):
|
||||
raise Exception('Invalid list of handlers provided. Handler must implement HandlerInterface')
|
||||
|
||||
self.updater.dispatcher.add_handler(handler.getBotHandler())
|
||||
for handler in AbstractHandler.__subclasses__():
|
||||
self.updater.dispatcher.add_handler(
|
||||
handler().getBotHandler()
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = App()
|
||||
|
||||
app.run()
|
||||
app.run()
|
||||
|
@ -1,8 +1,8 @@
|
||||
import re
|
||||
|
||||
# These are MarkdownV2 python-telegram-bot specific
|
||||
opted_in_successfully = re.escape('You have opted-in for everyone-mentions.')
|
||||
opted_in = re.escape('You have opted-in for everyone-mentions.')
|
||||
opted_in_failed = re.escape('You already opted-in for everyone-mentions.')
|
||||
opted_off_successfully = re.escape('You have opted-off for everyone-mentions.')
|
||||
opted_off = re.escape('You have opted-off for everyone-mentions.')
|
||||
opted_off_failed = re.escape('You need to opt-in first before processing this command.')
|
||||
mention_failed = re.escape('There are no users to mention.')
|
||||
|
@ -1,9 +1,10 @@
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
bot_token = os.environ['bot_token']
|
||||
BOT_TOKEN = os.environ['BOT_TOKEN']
|
||||
|
||||
MONGODB_DATABASE=os.environ['MONGODB_DATABASE']
|
||||
MONGODB_USERNAME=os.environ['MONGODB_USERNAME']
|
||||
|
@ -1,9 +0,0 @@
|
||||
from handlers.inHandler import InHandler
|
||||
from handlers.outHandler import OutHandler
|
||||
from handlers.mentionHandler import MentionHandler
|
||||
|
||||
handlers = [
|
||||
InHandler(),
|
||||
OutHandler(),
|
||||
MentionHandler()
|
||||
]
|
@ -1,10 +1,13 @@
|
||||
from pymongo.errors import ServerSelectionTimeoutError
|
||||
from config.credentials import MONGODB_USERNAME, MONGODB_PASSWORD, MONGODB_DATABASE, MONGODB_HOSTNAME, MONGODB_PORT
|
||||
from pymongo import MongoClient
|
||||
from pymongo.database import Database
|
||||
from urllib.parse import quote_plus
|
||||
|
||||
class DatabaseClient():
|
||||
from config.credentials import (MONGODB_DATABASE, MONGODB_HOSTNAME,
|
||||
MONGODB_PASSWORD, MONGODB_PORT,
|
||||
MONGODB_USERNAME)
|
||||
from pymongo import MongoClient
|
||||
from pymongo.database import Database
|
||||
|
||||
|
||||
class Client():
|
||||
mongoClient: MongoClient
|
||||
database: Database
|
||||
|
||||
@ -17,14 +20,17 @@ class DatabaseClient():
|
||||
self.mongoClient = MongoClient(uri)
|
||||
self.database = self.mongoClient[MONGODB_DATABASE]
|
||||
|
||||
def insert(self, collection: str, data: dict) -> None:
|
||||
def insertOne(self, collection: str, data: dict) -> None:
|
||||
self.database.get_collection(collection).insert_one(data)
|
||||
|
||||
def find(self, collection: str, query: dict) -> dict:
|
||||
return self.database.get_collection(collection).find(query)
|
||||
|
||||
def findOne(self, collection: str, query: dict) -> dict:
|
||||
return self.database.get_collection(collection).find_one(query)
|
||||
|
||||
def remove(self, collection: str, data: dict) -> None:
|
||||
self.database.get_collection(collection).remove(data)
|
||||
def findMany(self, collection: str, filter: dict) -> dict:
|
||||
return self.database.get_collection(collection).find(filter)
|
||||
|
||||
def updateOne(self, collection: str, filter: dict, data: dict) -> None:
|
||||
self.database.get_collection(collection).update_one(
|
||||
filter,
|
||||
{ "$set" : data }
|
||||
)
|
@ -1,28 +0,0 @@
|
||||
from __future__ import annotations
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Chat():
|
||||
id: str
|
||||
|
||||
def __init__(self, id: str) -> None:
|
||||
self.id = id
|
||||
|
||||
def getId(self) -> str:
|
||||
return self.id
|
||||
|
||||
def toDict(self) -> dict:
|
||||
return {
|
||||
'_id': self.id
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def getMongoRoot() -> str:
|
||||
return 'chat'
|
||||
|
||||
@staticmethod
|
||||
def fromDocument(document: Optional[dict]) -> Optional[Chat]:
|
||||
if not document:
|
||||
return None
|
||||
|
||||
return Chat(document['_id'])
|
@ -1,34 +0,0 @@
|
||||
from __future__ import annotations
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class ChatPerson():
|
||||
chat_id: str
|
||||
person_id: str
|
||||
|
||||
def __init__(self, chatId: str, personId: str) -> None:
|
||||
self.chat_id = chatId
|
||||
self.person_id = personId
|
||||
|
||||
def getChatId(self) -> str:
|
||||
return self.chat_id
|
||||
|
||||
def getPersonId(self) -> str:
|
||||
return self.person_id
|
||||
|
||||
def toDict(self) -> dict:
|
||||
return {
|
||||
'_id': f'{self.chat_id}-{self.person_id}',
|
||||
'chat_id': self.chat_id,
|
||||
'person_id': self.person_id
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def getMongoRoot() -> str:
|
||||
return 'chat_person'
|
||||
|
||||
@staticmethod
|
||||
def fromDocument(document: Optional[dict]) -> Optional[ChatPerson]:
|
||||
if not document:
|
||||
return None
|
||||
return ChatPerson(document['chat_id'], document['person_id'])
|
@ -1,44 +0,0 @@
|
||||
from __future__ import annotations
|
||||
from abc import abstractmethod
|
||||
from typing import Optional
|
||||
import names
|
||||
|
||||
|
||||
class Person():
|
||||
id: str
|
||||
username: str
|
||||
|
||||
def __init__(self, id: str, username: Optional[str] = None) -> None:
|
||||
self.id = id
|
||||
|
||||
if not username:
|
||||
self.username = names.get_first_name()
|
||||
else:
|
||||
self.username = username
|
||||
|
||||
def getId(self) -> str:
|
||||
return self.id
|
||||
|
||||
def getUsername(self) -> str:
|
||||
return self.username
|
||||
|
||||
def toDict(self, withUsername: bool = True) -> dict:
|
||||
result = {
|
||||
'_id': self.id
|
||||
}
|
||||
|
||||
if withUsername:
|
||||
result['username'] = self.username
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def getMongoRoot() -> str:
|
||||
return 'person'
|
||||
|
||||
@staticmethod
|
||||
def fromDocument(document: Optional[dict]) -> Optional[Person]:
|
||||
if not document:
|
||||
return None
|
||||
|
||||
return Person(document['_id'], document['username'])
|
52
src/entity/user.py
Normal file
52
src/entity/user.py
Normal file
@ -0,0 +1,52 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable
|
||||
|
||||
|
||||
class User():
|
||||
collection: str = 'users'
|
||||
idIndex: str = '_id'
|
||||
chatsIndex: str = 'chats'
|
||||
usernameIndex: str = 'username'
|
||||
|
||||
userId: str
|
||||
username: str
|
||||
chats: Iterable[str]
|
||||
|
||||
def __init__(self, userId, username, chats) -> None:
|
||||
self.userId = userId
|
||||
self.username = username
|
||||
self.chats = chats
|
||||
|
||||
def getUserId(self) -> str:
|
||||
return self.userId
|
||||
|
||||
def getUsername(self) -> str:
|
||||
return self.username
|
||||
|
||||
def getChats(self) -> Iterable[str]:
|
||||
return self.chats
|
||||
|
||||
def isInChat(self, chatId: str) -> bool:
|
||||
return chatId in self.getChats()
|
||||
|
||||
def addToChat(self, chatId: str) -> None:
|
||||
self.chats.append(chatId)
|
||||
|
||||
def removeFromChat(self, chatId: str) -> None:
|
||||
if chatId in self.getChats():
|
||||
self.chats.remove(chatId)
|
||||
|
||||
def toMongoDocument(self) -> dict:
|
||||
return {
|
||||
self.usernameIndex: self.getUsername(),
|
||||
self.chatsIndex: self.getChats()
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def fromMongoDocument(mongoDocument: dict) -> User:
|
||||
return User(
|
||||
mongoDocument[User.idIndex],
|
||||
mongoDocument[User.usernameIndex],
|
||||
mongoDocument[User.chatsIndex]
|
||||
)
|
2
src/exception/alreadyExistsException.py
Normal file
2
src/exception/alreadyExistsException.py
Normal file
@ -0,0 +1,2 @@
|
||||
class AlreadyExistsException(Exception):
|
||||
pass
|
2
src/exception/notFoundException.py
Normal file
2
src/exception/notFoundException.py
Normal file
@ -0,0 +1,2 @@
|
||||
class NotFoundException(Exception):
|
||||
pass
|
@ -1,10 +1,13 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.handler import Handler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.vo.updateData import UpdateData
|
||||
|
||||
class HandlerInterface:
|
||||
|
||||
class AbstractHandler:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
@ -14,8 +17,8 @@ class HandlerInterface:
|
||||
@abstractmethod
|
||||
def handle(self, update: Update, context: CallbackContext) -> None: raise Exception('handle method is not implemented')
|
||||
|
||||
@abstractmethod
|
||||
def getCommandName(self) -> str: raise Exception('getCommandName method is not implemented')
|
||||
def getUpdateData(self, update: Update) -> UpdateData:
|
||||
return UpdateData.createFromUpdate(update)
|
||||
|
||||
def reply(self, update: Update, message: str) -> None:
|
||||
update.effective_message.reply_markdown_v2(text=message)
|
38
src/handler/inHandler.py
Executable file
38
src/handler/inHandler.py
Executable file
@ -0,0 +1,38 @@
|
||||
from config.contents import opted_in, opted_in_failed
|
||||
from exception.notFoundException import NotFoundException
|
||||
from repository.userRepository import UserRepository
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
|
||||
|
||||
class InHandler(AbstractHandler):
|
||||
botHandler: CommandHandler
|
||||
userRepository: UserRepository
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.botHandler = CommandHandler('in', self.handle)
|
||||
self.userRepository = UserRepository()
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
updateData = self.getUpdateData(update)
|
||||
|
||||
try:
|
||||
user = self.userRepository.getById(updateData.getUserId())
|
||||
|
||||
if user.isInChat(updateData.getChatId()):
|
||||
self.reply(update, opted_in_failed)
|
||||
return
|
||||
|
||||
user.addToChat(updateData.getChatId())
|
||||
self.userRepository.save(user)
|
||||
|
||||
except NotFoundException:
|
||||
self.userRepository.saveByUpdateData(updateData)
|
||||
|
||||
self.reply(update, opted_in)
|
||||
|
||||
def getBotHandler(self) -> CommandHandler:
|
||||
return self.botHandler
|
40
src/handler/mentionHandler.py
Executable file
40
src/handler/mentionHandler.py
Executable file
@ -0,0 +1,40 @@
|
||||
from typing import Iterable
|
||||
|
||||
from config.contents import mention_failed
|
||||
from entity.user import User
|
||||
from repository.userRepository import UserRepository
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
|
||||
|
||||
class MentionHandler(AbstractHandler):
|
||||
botHandler: CommandHandler
|
||||
userRepository: UserRepository
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.botHandler = CommandHandler('everyone', self.handle)
|
||||
self.userRepository = UserRepository()
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
updateData = self.getUpdateData(update)
|
||||
users = self.userRepository.getAllForChat(updateData.getChatId())
|
||||
|
||||
if users:
|
||||
self.reply(update, self.buildMentionMessage(users))
|
||||
return
|
||||
|
||||
self.reply(update, mention_failed)
|
||||
|
||||
def getBotHandler(self) -> CommandHandler:
|
||||
return self.botHandler
|
||||
|
||||
def buildMentionMessage(self, users: Iterable[User]) -> str:
|
||||
result = ''
|
||||
|
||||
for user in users:
|
||||
result += f'*[{user.getUsername()}](tg://user?id={user.getUserId()})* '
|
||||
|
||||
return result
|
36
src/handler/outHandler.py
Executable file
36
src/handler/outHandler.py
Executable file
@ -0,0 +1,36 @@
|
||||
from config.contents import opted_off, opted_off_failed
|
||||
from exception.notFoundException import NotFoundException
|
||||
from repository.userRepository import UserRepository
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
from handler.abstractHandler import AbstractHandler
|
||||
|
||||
|
||||
class OutHandler(AbstractHandler):
|
||||
botHandler: CommandHandler
|
||||
userRepository: UserRepository
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.botHandler = CommandHandler('out', self.handle)
|
||||
self.userRepository = UserRepository()
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
updateData = self.getUpdateData(update)
|
||||
|
||||
try:
|
||||
user = self.userRepository.getById(updateData.getUserId())
|
||||
if not user.isInChat(updateData.getChatId()):
|
||||
raise NotFoundException()
|
||||
except NotFoundException:
|
||||
self.reply(update, opted_off_failed)
|
||||
return
|
||||
|
||||
user.removeFromChat(updateData.getChatId())
|
||||
self.userRepository.save(user)
|
||||
|
||||
self.reply(update, opted_off)
|
||||
|
||||
def getBotHandler(self) -> CommandHandler:
|
||||
return self.botHandler
|
36
src/handler/vo/updateData.py
Normal file
36
src/handler/vo/updateData.py
Normal file
@ -0,0 +1,36 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import names
|
||||
from telegram.update import Update
|
||||
|
||||
|
||||
class UpdateData():
|
||||
userId: str
|
||||
chatId: str
|
||||
username: str
|
||||
|
||||
def __init__(self, userId: str, chatId: str, username: str) -> None:
|
||||
self.userId = userId
|
||||
self.chatId = chatId
|
||||
self.username = username
|
||||
|
||||
def getUserId(self) -> str:
|
||||
return self.userId
|
||||
|
||||
def getChatId(self) -> str:
|
||||
return self.chatId
|
||||
|
||||
def getUsername(self) -> str:
|
||||
return self.username
|
||||
|
||||
@staticmethod
|
||||
def createFromUpdate(update: Update) -> UpdateData:
|
||||
userId = str(update.effective_user.id)
|
||||
chatId = str(update.effective_chat.id)
|
||||
chatId = "-284685928"
|
||||
username = update.effective_user.username or update.effective_user.first_name
|
||||
|
||||
if not username:
|
||||
username = names.get_first_name()
|
||||
|
||||
return UpdateData(userId, chatId, username)
|
@ -1,38 +0,0 @@
|
||||
from config.contents import opted_in_successfully, opted_in_failed
|
||||
from repositories.relationRepository import RelationRepository
|
||||
from database.databaseClient import DatabaseClient
|
||||
from handlers.handlerInterface import HandlerInterface
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
class InHandler(HandlerInterface):
|
||||
botHandler: CommandHandler
|
||||
commandName: str = 'in'
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.botHandler = CommandHandler(
|
||||
self.getCommandName(),
|
||||
self.handle
|
||||
)
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
personId = update.effective_user.id
|
||||
chatId = update.effective_chat.id
|
||||
username = update.effective_user.username
|
||||
|
||||
relationRepository = RelationRepository()
|
||||
relation = relationRepository.get(chatId, personId)
|
||||
|
||||
if relation:
|
||||
self.reply(update, opted_in_failed)
|
||||
return
|
||||
|
||||
relationRepository.save(chatId, personId, username)
|
||||
self.reply(update, opted_in_successfully)
|
||||
|
||||
def getBotHandler(self) -> CommandHandler:
|
||||
return self.botHandler
|
||||
|
||||
def getCommandName(self) -> str:
|
||||
return self.commandName
|
@ -1,45 +0,0 @@
|
||||
from typing import Iterable
|
||||
from config.contents import mention_failed
|
||||
from entities.person import Person
|
||||
from handlers.handlerInterface import HandlerInterface
|
||||
from repositories.relationRepository import RelationRepository
|
||||
from repositories.personRepository import PersonRepository
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
|
||||
class MentionHandler(HandlerInterface):
|
||||
botHandler: CommandHandler
|
||||
commandName: str = 'everyone'
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.botHandler = CommandHandler(
|
||||
self.getCommandName(),
|
||||
self.handle
|
||||
)
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
relationRepository = RelationRepository()
|
||||
persons = relationRepository.getPersonsForChat(update.effective_chat.id)
|
||||
|
||||
if not persons:
|
||||
self.reply(update, mention_failed)
|
||||
return
|
||||
|
||||
self.reply(update, self.buildMentionMessage(persons))
|
||||
|
||||
|
||||
def getBotHandler(self) -> CommandHandler:
|
||||
return self.botHandler
|
||||
|
||||
def getCommandName(self) -> str:
|
||||
return self.commandName
|
||||
|
||||
def buildMentionMessage(self, persons: Iterable[Person]) -> str:
|
||||
result = ''
|
||||
|
||||
for person in persons:
|
||||
result += f'*[{person.getUsername()}](tg://user?id={person.getId()})* '
|
||||
|
||||
return result
|
@ -1,38 +0,0 @@
|
||||
from config.contents import opted_off_successfully, opted_off_failed
|
||||
from handlers.handlerInterface import HandlerInterface
|
||||
from telegram.ext.callbackcontext import CallbackContext
|
||||
from telegram.ext.commandhandler import CommandHandler
|
||||
from telegram.update import Update
|
||||
|
||||
from repositories.relationRepository import RelationRepository
|
||||
|
||||
|
||||
class OutHandler(HandlerInterface):
|
||||
botHandler: CommandHandler
|
||||
commandName: str = 'out'
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.botHandler = CommandHandler(
|
||||
self.getCommandName(),
|
||||
self.handle
|
||||
)
|
||||
|
||||
def handle(self, update: Update, context: CallbackContext) -> None:
|
||||
personId = update.effective_user.id
|
||||
chatId = update.effective_chat.id
|
||||
|
||||
relationRepository = RelationRepository()
|
||||
relation = relationRepository.get(chatId, personId)
|
||||
|
||||
if not relation:
|
||||
self.reply(update, opted_off_failed)
|
||||
return
|
||||
|
||||
relationRepository.remove(relation)
|
||||
self.reply(update, opted_off_successfully)
|
||||
|
||||
def getBotHandler(self) -> CommandHandler:
|
||||
return self.botHandler
|
||||
|
||||
def getCommandName(self) -> str:
|
||||
return self.commandName
|
@ -1,18 +0,0 @@
|
||||
from database.databaseClient import DatabaseClient
|
||||
from entities.chat import Chat
|
||||
from typing import Optional
|
||||
|
||||
class ChatRepository:
|
||||
database: DatabaseClient
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.database = DatabaseClient()
|
||||
|
||||
def get(self, id: str) -> Optional[Chat]:
|
||||
chat = Chat(id)
|
||||
search = self.database.findOne(Chat.getMongoRoot(), chat.toDict())
|
||||
|
||||
return Chat.fromDocument(search)
|
||||
|
||||
def save(self, chat: Chat) -> None:
|
||||
self.database.insert(Chat.getMongoRoot(), chat.toDict())
|
@ -1,27 +0,0 @@
|
||||
from database.databaseClient import DatabaseClient
|
||||
from entities.person import Person
|
||||
from typing import Iterable, Optional
|
||||
|
||||
class PersonRepository:
|
||||
database: DatabaseClient
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.database = DatabaseClient()
|
||||
|
||||
def get(self, id: str) -> Optional[Person]:
|
||||
person = Person(id)
|
||||
search = self.database.findOne(Person.getMongoRoot(), person.toDict(False))
|
||||
|
||||
return Person.fromDocument(search)
|
||||
|
||||
def find(self, query: dict) -> Iterable[Person]:
|
||||
result = []
|
||||
search = self.database.find(Person.getMongoRoot(), query)
|
||||
|
||||
for document in search:
|
||||
result.append(Person.fromDocument(document))
|
||||
|
||||
return result
|
||||
|
||||
def save(self, person: Person) -> None:
|
||||
self.database.insert(Person.getMongoRoot(), person.toDict())
|
@ -1,56 +0,0 @@
|
||||
from typing import Iterable, Optional
|
||||
from database.databaseClient import DatabaseClient
|
||||
from entities.chat import Chat
|
||||
from entities.chatPerson import ChatPerson
|
||||
from entities.person import Person
|
||||
from repositories.personRepository import PersonRepository
|
||||
from repositories.chatRepository import ChatRepository
|
||||
|
||||
|
||||
class RelationRepository():
|
||||
client: DatabaseClient
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.client = DatabaseClient()
|
||||
|
||||
def get(self, chatId: str, personId: str) -> Optional[ChatPerson]:
|
||||
relation = ChatPerson(chatId, personId)
|
||||
search = self.client.findOne(ChatPerson.getMongoRoot(), relation.toDict())
|
||||
|
||||
return ChatPerson.fromDocument(search)
|
||||
|
||||
def save(self, chatId: str, personId: str, username: Optional[str] = None) -> None:
|
||||
relation = ChatPerson(chatId, personId)
|
||||
|
||||
self.client.insert(ChatPerson.getMongoRoot(), relation.toDict())
|
||||
personRepository = PersonRepository()
|
||||
person = personRepository.get(personId)
|
||||
|
||||
if not person:
|
||||
person = Person(personId, username)
|
||||
personRepository.save(person)
|
||||
|
||||
chatRepository = ChatRepository()
|
||||
chat = chatRepository.get(chatId)
|
||||
|
||||
if not chat:
|
||||
chat = Chat(chatId)
|
||||
chatRepository.save(chat)
|
||||
|
||||
def getPersonsForChat(self, chatId: str) -> Iterable[ChatPerson]:
|
||||
result = []
|
||||
relations = self.client.find(ChatPerson.getMongoRoot(), {'chat_id': chatId})
|
||||
|
||||
search = {}
|
||||
for relation in relations:
|
||||
search['_id'] = relation['person_id']
|
||||
|
||||
if not search:
|
||||
return result
|
||||
|
||||
personRepository = PersonRepository()
|
||||
return personRepository.find(search)
|
||||
|
||||
def remove(self, relation: ChatPerson) -> None:
|
||||
self.client.remove(ChatPerson.getMongoRoot() ,relation.toDict())
|
||||
|
66
src/repository/userRepository.py
Normal file
66
src/repository/userRepository.py
Normal file
@ -0,0 +1,66 @@
|
||||
from typing import Iterable, Optional
|
||||
|
||||
from database.client import Client
|
||||
from entity.user import User
|
||||
from exception.notFoundException import NotFoundException
|
||||
from handler.vo.updateData import UpdateData
|
||||
|
||||
|
||||
class UserRepository():
|
||||
client: Client
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.client = Client()
|
||||
|
||||
def getById(self, id: str) -> User:
|
||||
user = self.client.findOne(
|
||||
User.collection,
|
||||
{
|
||||
User.idIndex: id
|
||||
}
|
||||
)
|
||||
|
||||
if not user:
|
||||
raise NotFoundException(f'Could not find user with "{id}" id')
|
||||
|
||||
return User(
|
||||
user[User.idIndex],
|
||||
user[User.usernameIndex],
|
||||
user[User.chatsIndex]
|
||||
)
|
||||
|
||||
def save(self, user: User) -> None:
|
||||
self.client.updateOne(
|
||||
User.collection,
|
||||
{ User.idIndex: user.getUserId() },
|
||||
user.toMongoDocument()
|
||||
)
|
||||
|
||||
def saveByUpdateData(self, data: UpdateData) -> None:
|
||||
self.client.insertOne(
|
||||
User.collection,
|
||||
{
|
||||
User.idIndex: data.getUserId(),
|
||||
User.usernameIndex: data.getUsername(),
|
||||
User.chatsIndex: [data.getChatId()]
|
||||
}
|
||||
)
|
||||
|
||||
def getAllForChat(self, chatId: str) -> Iterable[User]:
|
||||
result = []
|
||||
users = self.client.findMany(
|
||||
User.collection,
|
||||
{
|
||||
User.chatsIndex: {
|
||||
"$in" : [chatId]
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
for record in users:
|
||||
result.append(User.fromMongoDocument(record))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user