Initial commit
8
.env.local
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
bot_token=
|
||||||
|
firebase_apiKey=
|
||||||
|
firebase_authDomain=
|
||||||
|
firebase_databaseURL=
|
||||||
|
firebase_projectId=
|
||||||
|
firebase_storageBucket=
|
||||||
|
app_url=
|
||||||
|
PORT=
|
129
.gitignore
vendored
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Miłosz Guglas
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
67
README.md
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# <p align="center"> [everyone-mention-telegram-bot](http://t.me/everyone_mention_bot)
|
||||||
|
<p align="center"> <img src="docs/logo.png" width="150"/>
|
||||||
|
<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
|
||||||
|
|
||||||
|
* [Getting started.](#getting-started)
|
||||||
|
* [Installation](#installation)
|
||||||
|
* [Requirements](#requirements)
|
||||||
|
* [Env file](#env-file)
|
||||||
|
* [Commands](#commands)
|
||||||
|
* [`/in`](#in)
|
||||||
|
* [`/out`](#out)
|
||||||
|
* [`/everyone`](#everyone)
|
||||||
|
|
||||||
|
### Getting started
|
||||||
|
#### Installation
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/miloszowi/everyone-mention-telegram-bot.git
|
||||||
|
pip install -r requirements.txt
|
||||||
|
python entrypoint.py
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Requirements
|
||||||
|
- `python` with version specified in `runtime.txt`
|
||||||
|
- `pip` with version `20.0.2`
|
||||||
|
|
||||||
|
#### Env file
|
||||||
|
```bash
|
||||||
|
cp .env.local .env
|
||||||
|
```
|
||||||
|
and then fulfill copied `.env` file with required values
|
||||||
|
- `bot_token` - your telegram bot token from [BotFather](https://telegram.me/BotFather)
|
||||||
|
- `firebase_*` - all of those values you can find in firebase console
|
||||||
|
- `app_url` - your app url for retrieving webhooks
|
||||||
|
- `PORT` - port for your app
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
#### `/in`
|
||||||
|
Will sign you in for everyone-mentions.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
If you have already opted-in before, alternative reply will be displayed.
|
||||||
|
|
||||||
|

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

|
||||||
|
|
||||||
|
If you haven't opted-in before, alternative reply will be displayed.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### `/everone`
|
||||||
|
Will mention everyone that opted-in for everyone-mentions separated by spaces.
|
||||||
|
|
||||||
|
If user does not contain nickname, his ID will be present instead of nickname.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
If there are no users that opted-in for mentioning, alternative reply will be displayed.
|
||||||
|
|
||||||
|

|
BIN
docs/commands.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
docs/everyone_command.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
docs/everyone_noone_to_mention.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
docs/in_command.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
docs/in_command_already_opted_in.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
docs/logo.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
docs/out_command.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
docs/out_command_did_not_opt_in_before.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
6
entrypoint.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from src.app import App
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = App()
|
||||||
|
|
||||||
|
app.run()
|
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
python-dotenv==0.19.0
|
||||||
|
python-telegram-bot==13.7
|
||||||
|
Pyrebase==3.0.27
|
1
runtime.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
python-3.8.10
|
34
src/app.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from .config.credentials import bot_token, app_url, port
|
||||||
|
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
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.updater = Updater(bot_token)
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
self.registerHandlers()
|
||||||
|
self.registerWebhook()
|
||||||
|
|
||||||
|
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())
|
||||||
|
|
||||||
|
def registerWebhook(self) -> None:
|
||||||
|
self.updater.start_webhook(
|
||||||
|
listen="0.0.0.0",
|
||||||
|
port=int(port),
|
||||||
|
url_path=bot_token,
|
||||||
|
webhook_url=f'{app_url}/{bot_token}'
|
||||||
|
)
|
8
src/config/contents.py
Normal file
@ -0,0 +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_failed = re.escape('You already opted-in for everyone-mentions.')
|
||||||
|
opted_off_successfully = 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.')
|
16
src/config/credentials.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
bot_token = os.environ['bot_token']
|
||||||
|
app_url = os.environ['app_url']
|
||||||
|
port = os.environ['PORT']
|
||||||
|
|
||||||
|
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'],
|
||||||
|
}
|
9
src/config/handlers.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from ..handlers.inHandler import InHandler
|
||||||
|
from ..handlers.outHandler import OutHandler
|
||||||
|
from ..handlers.mentionHandler import MentionHandler
|
||||||
|
|
||||||
|
handlers = [
|
||||||
|
InHandler(),
|
||||||
|
OutHandler(),
|
||||||
|
MentionHandler()
|
||||||
|
]
|
34
src/firebaseProxy.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
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}'
|
18
src/handlers/handlerInterface.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from abc import abstractmethod
|
||||||
|
from telegram.ext.callbackcontext import CallbackContext
|
||||||
|
from telegram.ext.handler import Handler
|
||||||
|
from telegram.update import Update
|
||||||
|
|
||||||
|
|
||||||
|
class HandlerInterface:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def getBotHandler(self) -> Handler: raise Exception('getBotHandler method is not implemented')
|
||||||
|
|
||||||
|
@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')
|
39
src/handlers/inHandler.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
from ..config.contents import opted_in_successfully, opted_in_failed
|
||||||
|
from ..repositories.userRepository import UserRepository
|
||||||
|
from ..firebaseProxy import FirebaseProxy
|
||||||
|
from .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:
|
||||||
|
groupId = update.effective_chat.id
|
||||||
|
userData = {
|
||||||
|
FirebaseProxy.id_index: update.effective_user.id,
|
||||||
|
FirebaseProxy.name_index: update.effective_user.username
|
||||||
|
}
|
||||||
|
userRepository = UserRepository()
|
||||||
|
|
||||||
|
if userRepository.isPresentInGroup(userData.get(FirebaseProxy.id_index), groupId):
|
||||||
|
update.message.reply_markdown_v2(text=opted_in_failed)
|
||||||
|
return
|
||||||
|
|
||||||
|
userRepository.addForGroup(userData, groupId)
|
||||||
|
update.message.reply_markdown_v2(text=opted_in_successfully)
|
||||||
|
|
||||||
|
def getBotHandler(self) -> CommandHandler:
|
||||||
|
return self.botHandler
|
||||||
|
|
||||||
|
def getCommandName(self) -> str:
|
||||||
|
return self.commandName
|
42
src/handlers/mentionHandler.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
from ..config.contents import mention_failed
|
||||||
|
from ..firebaseProxy import FirebaseProxy
|
||||||
|
from ..repositories.groupRepository import GroupRepository
|
||||||
|
from .handlerInterface import HandlerInterface
|
||||||
|
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:
|
||||||
|
groupId = update.effective_chat.id
|
||||||
|
groupRepository = GroupRepository()
|
||||||
|
mentionMessage = self.buildMentionMessage(groupRepository.get(id=groupId))
|
||||||
|
|
||||||
|
update.message.reply_markdown_v2(text=mentionMessage)
|
||||||
|
|
||||||
|
def getBotHandler(self) -> CommandHandler:
|
||||||
|
return self.botHandler
|
||||||
|
|
||||||
|
def getCommandName(self) -> str:
|
||||||
|
return self.commandName
|
||||||
|
|
||||||
|
def buildMentionMessage(self, usersData: dict) -> str:
|
||||||
|
result = ''
|
||||||
|
|
||||||
|
for userData in usersData:
|
||||||
|
userId = str(userData.get(FirebaseProxy.id_index))
|
||||||
|
username = userData.get(FirebaseProxy.name_index) or userId
|
||||||
|
|
||||||
|
result += "*[%s](tg://user?id=%s)* " % (username, userId)
|
||||||
|
|
||||||
|
return result or mention_failed
|
39
src/handlers/outHandler.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
from ..config.contents import opted_off_successfully, opted_off_failed
|
||||||
|
from ..repositories.userRepository import UserRepository
|
||||||
|
from .handlerInterface import HandlerInterface
|
||||||
|
from telegram.ext.callbackcontext import CallbackContext
|
||||||
|
from telegram.ext.commandhandler import CommandHandler
|
||||||
|
from telegram.update import Update
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
||||||
|
groupId = update.effective_chat.id
|
||||||
|
userData = {
|
||||||
|
'id': update.effective_user.id,
|
||||||
|
'name': update.effective_user.username
|
||||||
|
}
|
||||||
|
|
||||||
|
userRepository = UserRepository()
|
||||||
|
if not userRepository.isPresentInGroup(userData.get('id'), groupId):
|
||||||
|
update.message.reply_markdown_v2(text=opted_off_failed)
|
||||||
|
return
|
||||||
|
|
||||||
|
userRepository.removeForGroup(userId=userData.get('id'), groupId=groupId)
|
||||||
|
|
||||||
|
update.message.reply_markdown_v2(text=opted_off_successfully)
|
||||||
|
|
||||||
|
def getBotHandler(self) -> CommandHandler:
|
||||||
|
return self.botHandler
|
||||||
|
|
||||||
|
def getCommandName(self) -> str:
|
||||||
|
return self.commandName
|
18
src/repositories/groupRepository.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from ..firebaseProxy import FirebaseProxy
|
||||||
|
|
||||||
|
|
||||||
|
class GroupRepository():
|
||||||
|
firebase: FirebaseProxy
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.firebase = FirebaseProxy()
|
||||||
|
|
||||||
|
def get(self, id: int) -> dict:
|
||||||
|
result = []
|
||||||
|
groupData = self.firebase.getChilds(FirebaseProxy.group_index, id).get()
|
||||||
|
|
||||||
|
if groupData.each():
|
||||||
|
for user_root in groupData.each():
|
||||||
|
result.append(user_root.val())
|
||||||
|
|
||||||
|
return result
|
30
src/repositories/userRepository.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from ..firebaseProxy import FirebaseProxy
|
||||||
|
|
||||||
|
|
||||||
|
class UserRepository():
|
||||||
|
firebaseProxy: FirebaseProxy
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.firebaseProxy = FirebaseProxy()
|
||||||
|
|
||||||
|
def addForGroup(self, userData: dict, groupId: int) -> None:
|
||||||
|
self.firebaseProxy.getChilds(FirebaseProxy.getGroupPath(groupId)).update({
|
||||||
|
f'{groupId}_{userData.get("id")}': {
|
||||||
|
FirebaseProxy.id_index: userData.get("id"),
|
||||||
|
FirebaseProxy.name_index: userData.get("name")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
def removeForGroup(self, userId: int, groupId: int) -> None:
|
||||||
|
self.firebaseProxy.getChilds(FirebaseProxy.getGroupPath(groupId)).update({
|
||||||
|
FirebaseProxy.getUserPath(userId, groupId): {}
|
||||||
|
})
|
||||||
|
|
||||||
|
def isPresentInGroup(self, userId: int, groupId: int) -> bool:
|
||||||
|
user = self.firebaseProxy.getChilds(
|
||||||
|
FirebaseProxy.getGroupPath(groupId),
|
||||||
|
FirebaseProxy.getUserPath(userId, groupId)
|
||||||
|
).get().val()
|
||||||
|
|
||||||
|
return bool(user)
|
||||||
|
|