diff --git a/README.md b/README.md
index f578ee3..5b2ff7d 100755
--- a/README.md
+++ b/README.md
@@ -3,53 +3,61 @@
simple, but useful telegram bot to gather all of group members attention!
-## 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
+```
+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

diff --git a/docker-compose.yml b/docker-compose.yml
index 21047b1..3d7b5b8 100755
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -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:
diff --git a/docker/config/app/app.dist.env b/docker/config/app.dist.env
similarity index 100%
rename from docker/config/app/app.dist.env
rename to docker/config/app.dist.env
diff --git a/docker/config/database/database.dist.env b/docker/config/database.dist.env
similarity index 100%
rename from docker/config/database/database.dist.env
rename to docker/config/database.dist.env
diff --git a/src/app.py b/src/app.py
index 70eea6c..ffefb32 100755
--- a/src/app.py
+++ b/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()
\ No newline at end of file
+ app.run()
diff --git a/src/config/contents.py b/src/config/contents.py
index d36c2fc..a3345c1 100755
--- a/src/config/contents.py
+++ b/src/config/contents.py
@@ -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.')
diff --git a/src/config/credentials.py b/src/config/credentials.py
index 3bcc710..7a1ffaa 100755
--- a/src/config/credentials.py
+++ b/src/config/credentials.py
@@ -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']
diff --git a/src/config/handlers.py b/src/config/handlers.py
deleted file mode 100755
index 0ea3e9c..0000000
--- a/src/config/handlers.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from handlers.inHandler import InHandler
-from handlers.outHandler import OutHandler
-from handlers.mentionHandler import MentionHandler
-
-handlers = [
- InHandler(),
- OutHandler(),
- MentionHandler()
-]
diff --git a/src/database/databaseClient.py b/src/database/client.py
similarity index 53%
rename from src/database/databaseClient.py
rename to src/database/client.py
index 97ac57e..2295067 100755
--- a/src/database/databaseClient.py
+++ b/src/database/client.py
@@ -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)
\ No newline at end of file
+ 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 }
+ )
diff --git a/src/entities/chat.py b/src/entities/chat.py
deleted file mode 100755
index ea6217e..0000000
--- a/src/entities/chat.py
+++ /dev/null
@@ -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'])
\ No newline at end of file
diff --git a/src/entities/chatPerson.py b/src/entities/chatPerson.py
deleted file mode 100755
index 3a38791..0000000
--- a/src/entities/chatPerson.py
+++ /dev/null
@@ -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'])
\ No newline at end of file
diff --git a/src/entities/person.py b/src/entities/person.py
deleted file mode 100755
index 2c1cfdf..0000000
--- a/src/entities/person.py
+++ /dev/null
@@ -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'])
\ No newline at end of file
diff --git a/src/entity/user.py b/src/entity/user.py
new file mode 100644
index 0000000..58fd2b3
--- /dev/null
+++ b/src/entity/user.py
@@ -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]
+ )
diff --git a/src/exception/alreadyExistsException.py b/src/exception/alreadyExistsException.py
new file mode 100644
index 0000000..d3498b1
--- /dev/null
+++ b/src/exception/alreadyExistsException.py
@@ -0,0 +1,2 @@
+class AlreadyExistsException(Exception):
+ pass
\ No newline at end of file
diff --git a/src/exception/notFoundException.py b/src/exception/notFoundException.py
new file mode 100644
index 0000000..11e1ffd
--- /dev/null
+++ b/src/exception/notFoundException.py
@@ -0,0 +1,2 @@
+class NotFoundException(Exception):
+ pass
\ No newline at end of file
diff --git a/src/handlers/handlerInterface.py b/src/handler/abstractHandler.py
similarity index 76%
rename from src/handlers/handlerInterface.py
rename to src/handler/abstractHandler.py
index 5a4607c..e5ba4c7 100755
--- a/src/handlers/handlerInterface.py
+++ b/src/handler/abstractHandler.py
@@ -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)
diff --git a/src/handler/inHandler.py b/src/handler/inHandler.py
new file mode 100755
index 0000000..045e306
--- /dev/null
+++ b/src/handler/inHandler.py
@@ -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
diff --git a/src/handler/mentionHandler.py b/src/handler/mentionHandler.py
new file mode 100755
index 0000000..72079d7
--- /dev/null
+++ b/src/handler/mentionHandler.py
@@ -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
diff --git a/src/handler/outHandler.py b/src/handler/outHandler.py
new file mode 100755
index 0000000..2648e11
--- /dev/null
+++ b/src/handler/outHandler.py
@@ -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
diff --git a/src/handler/vo/updateData.py b/src/handler/vo/updateData.py
new file mode 100644
index 0000000..7c6737e
--- /dev/null
+++ b/src/handler/vo/updateData.py
@@ -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)
diff --git a/src/handlers/inHandler.py b/src/handlers/inHandler.py
deleted file mode 100755
index 49f5840..0000000
--- a/src/handlers/inHandler.py
+++ /dev/null
@@ -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
diff --git a/src/handlers/mentionHandler.py b/src/handlers/mentionHandler.py
deleted file mode 100755
index 4cad530..0000000
--- a/src/handlers/mentionHandler.py
+++ /dev/null
@@ -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
diff --git a/src/handlers/outHandler.py b/src/handlers/outHandler.py
deleted file mode 100755
index f0597a5..0000000
--- a/src/handlers/outHandler.py
+++ /dev/null
@@ -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
diff --git a/src/repositories/chatRepository.py b/src/repositories/chatRepository.py
deleted file mode 100755
index ec57f0a..0000000
--- a/src/repositories/chatRepository.py
+++ /dev/null
@@ -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())
\ No newline at end of file
diff --git a/src/repositories/personRepository.py b/src/repositories/personRepository.py
deleted file mode 100755
index b3ee6bb..0000000
--- a/src/repositories/personRepository.py
+++ /dev/null
@@ -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())
\ No newline at end of file
diff --git a/src/repositories/relationRepository.py b/src/repositories/relationRepository.py
deleted file mode 100755
index 3482544..0000000
--- a/src/repositories/relationRepository.py
+++ /dev/null
@@ -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())
-
diff --git a/src/repository/userRepository.py b/src/repository/userRepository.py
new file mode 100644
index 0000000..2f16f81
--- /dev/null
+++ b/src/repository/userRepository.py
@@ -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
+
+
+