diff --git a/.env.local b/.env.local deleted file mode 100644 index eb624cf..0000000 --- a/.env.local +++ /dev/null @@ -1,6 +0,0 @@ -bot_token= -firebase_apiKey= -firebase_authDomain= -firebase_databaseURL= -firebase_projectId= -firebase_storageBucket= diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index b6e4761..08d0bd2 --- a/.gitignore +++ b/.gitignore @@ -102,6 +102,8 @@ celerybeat.pid *.sage.py # Environments +app.env +database.env .env .venv env/ diff --git a/Dockerfile b/Dockerfile new file mode 100755 index 0000000..86cff90 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.8-buster + +WORKDIR /src + +COPY ./src/requirements.txt /src +RUN pip install -r ./requirements.txt + diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/Procfile b/Procfile deleted file mode 100644 index fe54d30..0000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: python entrypoint.py diff --git a/README.md b/README.md old mode 100644 new mode 100755 index a4ecb9b..f578ee3 --- a/README.md +++ b/README.md @@ -26,14 +26,28 @@ python entrypoint.py - `python` with version specified in `runtime.txt` - `pip` with version `20.0.2` -#### Env file +#### Env files +First, copy env files for database and app containers ```bash -cp .env.local .env +cp docker/config/app/app.dist.env docker/config/app/app.env +cp docker/config/database/database.dist.env docker/config/app/app.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 +and then fulfill copied `.env` files with required values +app.env +- `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) + +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` Will sign you in for everyone-mentions. @@ -56,7 +70,7 @@ 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 user does not have nickname, it will assign random name from `names` python library to his ID ![everybody command example](docs/everyone_command.png) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100755 index 0000000..21047b1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,37 @@ +version: "3.6" + +services: + + database: + image: mongo:4.0.8 + restart: unless-stopped + env_file: + - ./docker/config/database/database.env + volumes: + - db-data:/data/db + ports: + - 27017:27017 + networks: + - web + + app: + build: . + command: python app.py + env_file: + - ./docker/config/app/app.env + volumes: + - ./src:/src + ports: + - 9000:9000 + depends_on: + - database + networks: + - web + restart: on-failure + +networks: + web: + driver: bridge + +volumes: + db-data: \ No newline at end of file diff --git a/docker/config/app/app.dist.env b/docker/config/app/app.dist.env new file mode 100755 index 0000000..ad05a23 --- /dev/null +++ b/docker/config/app/app.dist.env @@ -0,0 +1,7 @@ +BOT_TOKEN= + +MONGODB_DATABASE= +MONGODB_USERNAME= +MONGODB_PASSWORD= +MONGODB_HOSTNAME=localhost +MONGODB_PORT=27017 \ No newline at end of file diff --git a/docker/config/database/database.dist.env b/docker/config/database/database.dist.env new file mode 100755 index 0000000..3594ee3 --- /dev/null +++ b/docker/config/database/database.dist.env @@ -0,0 +1,5 @@ +MONGO_INITDB_ROOT_USERNAME= +MONGO_INITDB_ROOT_PASSWORD= +MONGO_INITDB_DATABASE= +MONGODB_DATA_DIR=/mongo/database +MONDODB_LOG_DIR= \ No newline at end of file diff --git a/docker/logs b/docker/logs new file mode 100755 index 0000000..76ec3ec --- /dev/null +++ b/docker/logs @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +[ -z "$1" ] && printf "\nPlease specify service name (ex. app)\n\n" && exit + +docker-compose logs -f "$@" \ No newline at end of file diff --git a/docs/commands.png b/docs/commands.png old mode 100644 new mode 100755 diff --git a/docs/everyone_command.png b/docs/everyone_command.png old mode 100644 new mode 100755 diff --git a/docs/everyone_noone_to_mention.png b/docs/everyone_noone_to_mention.png old mode 100644 new mode 100755 diff --git a/docs/in_command.png b/docs/in_command.png old mode 100644 new mode 100755 diff --git a/docs/in_command_already_opted_in.png b/docs/in_command_already_opted_in.png old mode 100644 new mode 100755 diff --git a/docs/logo.png b/docs/logo.png old mode 100644 new mode 100755 diff --git a/docs/out_command.png b/docs/out_command.png old mode 100644 new mode 100755 diff --git a/docs/out_command_did_not_opt_in_before.png b/docs/out_command_did_not_opt_in_before.png old mode 100644 new mode 100755 diff --git a/entrypoint.py b/entrypoint.py deleted file mode 100644 index 2e270f8..0000000 --- a/entrypoint.py +++ /dev/null @@ -1,6 +0,0 @@ -from src.app import App - -if __name__ == "__main__": - app = App() - - app.run() diff --git a/runtime.txt b/runtime.txt deleted file mode 100644 index a48890e..0000000 --- a/runtime.txt +++ /dev/null @@ -1 +0,0 @@ -python-3.8.10 diff --git a/src/app.py b/src/app.py old mode 100644 new mode 100755 index a27caca..70eea6c --- a/src/app.py +++ b/src/app.py @@ -1,10 +1,9 @@ -from .config.credentials import bot_token -from .config.handlers import handlers -from .handlers.handlerInterface import HandlerInterface +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 - class App: updater: Updater dispatcher: Dispatcher @@ -14,6 +13,7 @@ class App: def run(self) -> None: self.registerHandlers() + self.updater.start_polling() self.updater.idle() @@ -23,3 +23,9 @@ class App: raise Exception('Invalid list of handlers provided. Handler must implement HandlerInterface') self.updater.dispatcher.add_handler(handler.getBotHandler()) + + +if __name__ == "__main__": + app = App() + + app.run() \ No newline at end of file diff --git a/src/config/contents.py b/src/config/contents.py old mode 100644 new mode 100755 diff --git a/src/config/credentials.py b/src/config/credentials.py old mode 100644 new mode 100755 index 072318f..3bcc710 --- a/src/config/credentials.py +++ b/src/config/credentials.py @@ -5,10 +5,8 @@ load_dotenv() bot_token = os.environ['bot_token'] -firebaseConfig = { - "apiKey": os.environ['firebase_apiKey'], - "authDomain": os.environ['firebase_authDomain'], - "databaseURL": os.environ['firebase_databaseURL'], - "projectId": os.environ['firebase_projectId'], - "storageBucket": os.environ['firebase_storageBucket'], -} +MONGODB_DATABASE=os.environ['MONGODB_DATABASE'] +MONGODB_USERNAME=os.environ['MONGODB_USERNAME'] +MONGODB_PASSWORD=os.environ['MONGODB_PASSWORD'] +MONGODB_HOSTNAME=os.environ['MONGODB_HOSTNAME'] +MONGODB_PORT=os.environ['MONGODB_PORT'] diff --git a/src/config/handlers.py b/src/config/handlers.py old mode 100644 new mode 100755 index a7d81d6..0ea3e9c --- a/src/config/handlers.py +++ b/src/config/handlers.py @@ -1,6 +1,6 @@ -from ..handlers.inHandler import InHandler -from ..handlers.outHandler import OutHandler -from ..handlers.mentionHandler import MentionHandler +from handlers.inHandler import InHandler +from handlers.outHandler import OutHandler +from handlers.mentionHandler import MentionHandler handlers = [ InHandler(), diff --git a/src/database/databaseClient.py b/src/database/databaseClient.py new file mode 100755 index 0000000..97ac57e --- /dev/null +++ b/src/database/databaseClient.py @@ -0,0 +1,30 @@ +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(): + mongoClient: MongoClient + database: Database + + def __init__(self) -> None: + uri = "mongodb://%s:%s@%s:%s/%s?authSource=admin" % ( + MONGODB_USERNAME, quote_plus(MONGODB_PASSWORD), + MONGODB_HOSTNAME, MONGODB_PORT, MONGODB_DATABASE + ) + + self.mongoClient = MongoClient(uri) + self.database = self.mongoClient[MONGODB_DATABASE] + + def insert(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 diff --git a/src/entities/chat.py b/src/entities/chat.py new file mode 100755 index 0000000..ea6217e --- /dev/null +++ b/src/entities/chat.py @@ -0,0 +1,28 @@ +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 new file mode 100755 index 0000000..3a38791 --- /dev/null +++ b/src/entities/chatPerson.py @@ -0,0 +1,34 @@ +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/group.py b/src/entities/group.py deleted file mode 100644 index 931491c..0000000 --- a/src/entities/group.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Iterable -from .user import User - -class Group(): - __id: int - __users: Iterable[User] = [] - - def __init__(self, id: int) -> None: - self.__id = id - - def getId(self) -> int: - return self.__id - - def setUsers(self, users: Iterable[User]) -> None: - self.__users = users - - def addUser(self, user: User) -> None: - self.__users.append(user) - - def removeUser(self, user: User) -> None: - for index, groupUser in enumerate(self.__users): - if groupUser.getId() == user.getId(): - del self.__users[index] - - def getUsers(self) -> Iterable[User]: - return self.__users - - def hasUser(self, user: User) -> bool: - userIds = [int(groupUser.getId()) for groupUser in self.getUsers()] - - if user.getId() in userIds: - return True - - return False \ No newline at end of file diff --git a/src/entities/person.py b/src/entities/person.py new file mode 100755 index 0000000..2c1cfdf --- /dev/null +++ b/src/entities/person.py @@ -0,0 +1,44 @@ +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/entities/user.py b/src/entities/user.py deleted file mode 100644 index 13808d2..0000000 --- a/src/entities/user.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Optional - -class User(): - __id: int - __username: Optional[str] - __groupId: int - - def __init__(self, id: int, username: Optional[str]) -> None: - self.__id = id - self.__username = username - - def getId(self) -> int: - return self.__id - - def getUsername(self) -> Optional[str]: - return self.__username - - def getGroupId(self) -> int: - return self.__groupId \ No newline at end of file diff --git a/src/firebaseProxy.py b/src/firebaseProxy.py deleted file mode 100644 index aa8db8c..0000000 --- a/src/firebaseProxy.py +++ /dev/null @@ -1,34 +0,0 @@ -import pyrebase -from pyrebase.pyrebase import Database as FirebaseDB -from .config.credentials import firebaseConfig - - -class FirebaseProxy(): - db: FirebaseDB - - # Group specific values - group_index: str = 'groups' - - # User specific values - id_index: str = 'id' - name_index: str = 'name' - - def __init__(self) -> None: - firebase = pyrebase.pyrebase.initialize_app(firebaseConfig) - self.db = firebase.database() - - def getChilds(self, *childs: str) -> FirebaseDB: - current = self.db - - for child_index in childs: - current = current.child(child_index) - - return current - - @staticmethod - def getGroupPath(groupId: int) -> str: - return f'{FirebaseProxy.group_index}/{groupId}' - - @staticmethod - def getUserPath(userId: int, groupId: int) -> str: - return f'{groupId}_{userId}' diff --git a/src/handlers/handlerInterface.py b/src/handlers/handlerInterface.py old mode 100644 new mode 100755 index 3cad7ce..5a4607c --- a/src/handlers/handlerInterface.py +++ b/src/handlers/handlerInterface.py @@ -16,3 +16,6 @@ class HandlerInterface: @abstractmethod def getCommandName(self) -> str: raise Exception('getCommandName method is not implemented') + + def reply(self, update: Update, message: str) -> None: + update.effective_message.reply_markdown_v2(text=message) diff --git a/src/handlers/inHandler.py b/src/handlers/inHandler.py old mode 100644 new mode 100755 index 7bbfdca..49f5840 --- a/src/handlers/inHandler.py +++ b/src/handlers/inHandler.py @@ -1,12 +1,11 @@ -from ..config.contents import opted_in_successfully, opted_in_failed -from ..entities.user import User -from ..repositories.groupRepository import GroupRepository -from .handlerInterface import HandlerInterface +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' @@ -18,18 +17,19 @@ class InHandler(HandlerInterface): ) def handle(self, update: Update, context: CallbackContext) -> None: - groupRepository = GroupRepository() - group = groupRepository.get(update.effective_chat.id) - user = User(update.effective_user.id, update.effective_user.username) + personId = update.effective_user.id + chatId = update.effective_chat.id + username = update.effective_user.username - if group.hasUser(user): - update.message.reply_markdown_v2(text=opted_in_failed) + relationRepository = RelationRepository() + relation = relationRepository.get(chatId, personId) + + if relation: + self.reply(update, opted_in_failed) return - - group.addUser(user) - groupRepository.save(group) - - update.message.reply_markdown_v2(text=opted_in_successfully) + + relationRepository.save(chatId, personId, username) + self.reply(update, opted_in_successfully) def getBotHandler(self) -> CommandHandler: return self.botHandler diff --git a/src/handlers/mentionHandler.py b/src/handlers/mentionHandler.py old mode 100644 new mode 100755 index bcccc72..4cad530 --- a/src/handlers/mentionHandler.py +++ b/src/handlers/mentionHandler.py @@ -1,9 +1,9 @@ -from ..config.contents import mention_failed -from ..entities.group import Group -from ..entities.user import User -from ..firebaseProxy import FirebaseProxy -from ..repositories.groupRepository import GroupRepository -from .handlerInterface import HandlerInterface +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 @@ -20,11 +20,15 @@ class MentionHandler(HandlerInterface): ) def handle(self, update: Update, context: CallbackContext) -> None: - groupId = update.effective_chat.id - groupRepository = GroupRepository() - mentionMessage = self.buildMentionMessage(groupRepository.get(id=groupId)) + relationRepository = RelationRepository() + persons = relationRepository.getPersonsForChat(update.effective_chat.id) + + if not persons: + self.reply(update, mention_failed) + return + + self.reply(update, self.buildMentionMessage(persons)) - update.message.reply_markdown_v2(text=mentionMessage) def getBotHandler(self) -> CommandHandler: return self.botHandler @@ -32,11 +36,10 @@ class MentionHandler(HandlerInterface): def getCommandName(self) -> str: return self.commandName - def buildMentionMessage(self, group: Group) -> str: + def buildMentionMessage(self, persons: Iterable[Person]) -> str: result = '' - for user in group.getUsers(): - username = user.getUsername() or user.getId() - result += f'*[{username}](tg://user?id={user.getId()})* ' + for person in persons: + result += f'*[{person.getUsername()}](tg://user?id={person.getId()})* ' - return result or mention_failed + return result diff --git a/src/handlers/outHandler.py b/src/handlers/outHandler.py old mode 100644 new mode 100755 index 8d3b5b1..f0597a5 --- a/src/handlers/outHandler.py +++ b/src/handlers/outHandler.py @@ -1,11 +1,11 @@ -from ..config.contents import opted_off_successfully, opted_off_failed -from ..entities.user import User -from ..repositories.groupRepository import GroupRepository -from .handlerInterface import HandlerInterface +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 @@ -18,18 +18,18 @@ class OutHandler(HandlerInterface): ) def handle(self, update: Update, context: CallbackContext) -> None: - groupRepository = GroupRepository() - group = groupRepository.get(update.effective_chat.id) - user = User(update.effective_user.id, update.effective_user.username) + personId = update.effective_user.id + chatId = update.effective_chat.id - if group.hasUser(user): - group.removeUser(user) - groupRepository.save(group) - - update.message.reply_markdown_v2(text=opted_off_successfully) + relationRepository = RelationRepository() + relation = relationRepository.get(chatId, personId) + + if not relation: + self.reply(update, opted_off_failed) return - - update.message.reply_markdown_v2(text=opted_off_failed) + + relationRepository.remove(relation) + self.reply(update, opted_off_successfully) def getBotHandler(self) -> CommandHandler: return self.botHandler diff --git a/src/repositories/chatRepository.py b/src/repositories/chatRepository.py new file mode 100755 index 0000000..ec57f0a --- /dev/null +++ b/src/repositories/chatRepository.py @@ -0,0 +1,18 @@ +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/groupRepository.py b/src/repositories/groupRepository.py deleted file mode 100644 index 20d13dd..0000000 --- a/src/repositories/groupRepository.py +++ /dev/null @@ -1,48 +0,0 @@ -from ..entities.group import Group -from ..entities.user import User -from ..firebaseProxy import FirebaseProxy - - -class GroupRepository(): - firebase: FirebaseProxy - - def __init__(self) -> None: - self.firebase = FirebaseProxy() - - def get(self, id: int) -> Group: - group = Group(id) - fbData = self.firebase.getChilds(FirebaseProxy.group_index, id).get() - users = [] - - for userData in fbData.each() or []: - userData = userData.val() - users.append( - User( - userData.get(FirebaseProxy.id_index), - userData.get(FirebaseProxy.name_index) - ) - ) - - group.setUsers(users) - - return group - - def save(self, group: Group) -> None: - users = {} - - if not group.getUsers(): - self.remove(group) - - for user in group.getUsers(): - users[user.getId()] = { - FirebaseProxy.id_index: user.getId(), - FirebaseProxy.name_index: user.getUsername() - } - - self.firebase.getChilds( - FirebaseProxy.group_index, - group.getId() - ).update(users) - - def remove(self, group: Group) -> None: - self.firebase.getChilds(FirebaseProxy.group_index, group.getId()).remove() \ No newline at end of file diff --git a/src/repositories/personRepository.py b/src/repositories/personRepository.py new file mode 100755 index 0000000..b3ee6bb --- /dev/null +++ b/src/repositories/personRepository.py @@ -0,0 +1,27 @@ +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 new file mode 100755 index 0000000..3482544 --- /dev/null +++ b/src/repositories/relationRepository.py @@ -0,0 +1,56 @@ +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/repositories/userRepository.py b/src/repositories/userRepository.py deleted file mode 100644 index 7155b4e..0000000 --- a/src/repositories/userRepository.py +++ /dev/null @@ -1,12 +0,0 @@ -from ..firebaseProxy import FirebaseProxy - - -class UserRepository(): - firebaseProxy: FirebaseProxy - - def __init__(self) -> None: - self.firebaseProxy = FirebaseProxy() - - # TODO : this repository needs to handle user save/deletion/update - # right now, all of those above is handled by GroupRepository - \ No newline at end of file diff --git a/requirements.txt b/src/requirements.txt old mode 100644 new mode 100755 similarity index 63% rename from requirements.txt rename to src/requirements.txt index af1197a..81d707c --- a/requirements.txt +++ b/src/requirements.txt @@ -1,3 +1,4 @@ python-dotenv==0.19.0 python-telegram-bot==13.7 -Pyrebase==3.0.27 +pymongo==3.12.0 +names==0.3.0 \ No newline at end of file