[doc] Add docstrings for core
This commit is contained in:
parent
a00a6b8497
commit
051dd062ac
|
@ -4,6 +4,19 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" Configuration file and command line argument parser.
|
||||||
|
|
||||||
|
Gives a dictionary named `config` with configuration parsed either from
|
||||||
|
`/etc/kibicara.conf` or from a file given by command line argument `-f`.
|
||||||
|
If no configuration was found at all, the defaults are used.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
from kibicara.config import config
|
||||||
|
print(config)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from pytoml import load
|
from pytoml import load
|
||||||
from sys import argv
|
from sys import argv
|
||||||
|
@ -14,6 +27,10 @@ config = {
|
||||||
'frontend_path': None,
|
'frontend_path': None,
|
||||||
'root_url': 'http://localhost:8000/',
|
'root_url': 'http://localhost:8000/',
|
||||||
}
|
}
|
||||||
|
""" Default configuration.
|
||||||
|
|
||||||
|
The default configuration gets overwritten by a configuration file if one exists.
|
||||||
|
"""
|
||||||
|
|
||||||
if argv[0].endswith('kibicara'):
|
if argv[0].endswith('kibicara'):
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" E-Mail handling. """
|
||||||
|
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from email.mime.multipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
@ -14,6 +16,22 @@ logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def send_email(to, subject, sender='kibicara', body=''):
|
def send_email(to, subject, sender='kibicara', body=''):
|
||||||
|
""" E-Mail sender.
|
||||||
|
|
||||||
|
Sends an E-Mail to a specified recipient with a body
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
from kibicara import email
|
||||||
|
email.send_email('abc@de.fg', 'My Email subject', body='Hi this is a mail body.')
|
||||||
|
```
|
||||||
|
|
||||||
|
Args:
|
||||||
|
to (str): Recipients' e-mail address
|
||||||
|
subject (str): The subject of the e-mail
|
||||||
|
sender (str): optional, Sender of the e-mail
|
||||||
|
body (str): The body of the e-mail
|
||||||
|
"""
|
||||||
msg = MIMEMultipart()
|
msg = MIMEMultipart()
|
||||||
msg['From'] = 'Kibicara <%s@%s>' % (sender, getfqdn())
|
msg['From'] = 'Kibicara <%s@%s>' % (sender, getfqdn())
|
||||||
msg['To'] = to
|
msg['To'] = to
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" Entrypoint of Kibicara. """
|
||||||
|
|
||||||
from asyncio import run as asyncio_run
|
from asyncio import run as asyncio_run
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
@ -19,17 +21,23 @@ logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Main:
|
class Main:
|
||||||
def __init__(self):
|
""" Entrypoint for Kibicara.
|
||||||
asyncio_run(self.run())
|
|
||||||
|
|
||||||
async def run(self):
|
Initializes the platform bots and starts the hypercorn webserver serving the
|
||||||
|
Kibicara application and the specified frontend on port 8000.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
asyncio_run(self.__run())
|
||||||
|
|
||||||
|
async def __run(self):
|
||||||
basicConfig(level=DEBUG, format="%(asctime)s %(name)s %(message)s")
|
basicConfig(level=DEBUG, format="%(asctime)s %(name)s %(message)s")
|
||||||
getLogger('aiosqlite').setLevel(WARNING)
|
getLogger('aiosqlite').setLevel(WARNING)
|
||||||
Mapping.create_all()
|
Mapping.create_all()
|
||||||
await Spawner.init_all()
|
await Spawner.init_all()
|
||||||
await self._start_webserver()
|
await self.__start_webserver()
|
||||||
|
|
||||||
async def _start_webserver(self):
|
async def __start_webserver(self):
|
||||||
class SinglePageApplication(StaticFiles):
|
class SinglePageApplication(StaticFiles):
|
||||||
async def get_response(self, path, scope):
|
async def get_response(self, path, scope):
|
||||||
response = await super().get_response(path, scope)
|
response = await super().get_response(path, scope)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" ORM Models for core. """
|
||||||
|
|
||||||
from databases import Database
|
from databases import Database
|
||||||
from kibicara.config import config
|
from kibicara.config import config
|
||||||
from ormantic import Integer, ForeignKey, Model, Text
|
from ormantic import Integer, ForeignKey, Model, Text
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" API classes for implementing bots for platforms. """
|
||||||
|
|
||||||
from asyncio import create_task, Queue
|
from asyncio import create_task, Queue
|
||||||
from kibicara.model import BadWord, Trigger
|
from kibicara.model import BadWord, Trigger
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
@ -13,47 +15,116 @@ logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Message:
|
class Message:
|
||||||
|
"""The Message object that is send through the censor.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```
|
||||||
|
message = Message('Message sent by a user from platform xyz', xyz_message_id=123)
|
||||||
|
```
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): The message text
|
||||||
|
**kwargs (object, optional): Other platform-specific data.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
text (str): The message text
|
||||||
|
**kwargs (object, optional): Other platform-specific data.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, text, **kwargs):
|
def __init__(self, text, **kwargs):
|
||||||
self.text = text
|
self.text = text
|
||||||
self.__dict__.update(kwargs)
|
self.__dict__.update(kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Censor:
|
class Censor:
|
||||||
instances = {}
|
""" The superclass for a platform bot.
|
||||||
|
|
||||||
|
The censor is the superclass for every platform bot. It distributes a message to all
|
||||||
|
other bots from the same hood if it passes the message filter. It provides methods
|
||||||
|
to start and stop the bot and an overwritable stub for a starting routine.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```
|
||||||
|
class XYZPlatform(Censor):
|
||||||
|
def __init__(self, xyz_model):
|
||||||
|
super().__init__(xyz_model.hood)
|
||||||
|
...
|
||||||
|
async def run(self):
|
||||||
|
await gather(self.poll(), self.push())
|
||||||
|
...
|
||||||
|
async def poll(self):
|
||||||
|
while True:
|
||||||
|
# XXX get text message from platform xyz
|
||||||
|
await self.publish(Message(text))
|
||||||
|
...
|
||||||
|
async def push(self):
|
||||||
|
while True:
|
||||||
|
message = await self.receive()
|
||||||
|
# XXX send message.text to platform xyz
|
||||||
|
```
|
||||||
|
|
||||||
|
Args:
|
||||||
|
hood (Hood): A Hood Model object
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
hood (Hood): A Hood Model object
|
||||||
|
"""
|
||||||
|
|
||||||
|
__instances = {}
|
||||||
|
|
||||||
def __init__(self, hood):
|
def __init__(self, hood):
|
||||||
self.hood = hood
|
self.hood = hood
|
||||||
self.inbox = Queue()
|
self._inbox = Queue()
|
||||||
self.task = None
|
self.__task = None
|
||||||
self.hood_censors = self.instances.setdefault(hood.id, [])
|
self.__hood_censors = self.__instances.setdefault(hood.id, [])
|
||||||
self.hood_censors.append(self)
|
self.__hood_censors.append(self)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if self.task is None:
|
""" Start the bot.
|
||||||
self.task = create_task(self.__run())
|
|
||||||
|
Note: This will be called by a spawner, a platform bot should not call this.
|
||||||
|
"""
|
||||||
|
if self.__task is None:
|
||||||
|
self.__task = create_task(self.__run())
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if self.task is not None:
|
""" Stop the bot.
|
||||||
self.task.cancel()
|
|
||||||
self.task = None
|
Note: This will be called by a spawner, a platform bot should not call this.
|
||||||
|
"""
|
||||||
|
if self.__task is not None:
|
||||||
|
self.__task.cancel()
|
||||||
|
self.__task = None
|
||||||
|
|
||||||
async def __run(self):
|
async def __run(self):
|
||||||
await self.hood.load()
|
await self.hood.load()
|
||||||
self.task.set_name('%s %s' % (self.__class__.__name__, self.hood.name))
|
self.__task.set_name('%s %s' % (self.__class__.__name__, self.hood.name))
|
||||||
await self.run()
|
await self.run()
|
||||||
|
|
||||||
# override this in derived class
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
|
""" Entry point for a bot.
|
||||||
|
|
||||||
|
Note: Override this in the derived bot class.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def publish(self, message):
|
async def publish(self, message):
|
||||||
|
""" Distribute a message to the bots in a hood.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message (Message): Message to distribute
|
||||||
|
"""
|
||||||
if not await self.__is_appropriate(message):
|
if not await self.__is_appropriate(message):
|
||||||
return
|
return
|
||||||
for censor in self.hood_censors:
|
for censor in self.__hood_censors:
|
||||||
await censor.inbox.put(message)
|
await censor._inbox.put(message)
|
||||||
|
|
||||||
async def receive(self):
|
async def receive(self):
|
||||||
return await self.inbox.get()
|
""" Receive a message.
|
||||||
|
|
||||||
|
Returns (Message): Received message
|
||||||
|
"""
|
||||||
|
return await self._inbox.get()
|
||||||
|
|
||||||
async def __is_appropriate(self, message):
|
async def __is_appropriate(self, message):
|
||||||
for badword in await BadWord.objects.filter(hood=self.hood).all():
|
for badword in await BadWord.objects.filter(hood=self.hood).all():
|
||||||
|
@ -69,17 +140,40 @@ class Censor:
|
||||||
|
|
||||||
|
|
||||||
class Spawner:
|
class Spawner:
|
||||||
instances = []
|
""" Spawns a bot with a specific bot model.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```
|
||||||
|
class XYZPlatform(Censor):
|
||||||
|
# bot class
|
||||||
|
|
||||||
|
class XYZ(Model):
|
||||||
|
# bot model
|
||||||
|
|
||||||
|
spawner = Spawner(XYZ, XYZPlatform)
|
||||||
|
```
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ORMClass (ORM Model subclass): A Bot Model object
|
||||||
|
BotClass (Censor subclass): A Bot Class object
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
ORMClass (ORM Model subclass): A Hood Model object
|
||||||
|
BotClass (Censor subclass): A Bot Class object
|
||||||
|
"""
|
||||||
|
|
||||||
|
__instances = []
|
||||||
|
|
||||||
def __init__(self, ORMClass, BotClass):
|
def __init__(self, ORMClass, BotClass):
|
||||||
self.ORMClass = ORMClass
|
self.ORMClass = ORMClass
|
||||||
self.BotClass = BotClass
|
self.BotClass = BotClass
|
||||||
self.bots = {}
|
self.__bots = {}
|
||||||
self.instances.append(self)
|
self.__instances.append(self)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def init_all(cls):
|
async def init_all(cls):
|
||||||
for spawner in cls.instances:
|
""" Instantiate and start a bot for every row in the corresponding ORM model. """
|
||||||
|
for spawner in cls.__instances:
|
||||||
await spawner._init()
|
await spawner._init()
|
||||||
|
|
||||||
async def _init(self):
|
async def _init(self):
|
||||||
|
@ -87,13 +181,34 @@ class Spawner:
|
||||||
self.start(item)
|
self.start(item)
|
||||||
|
|
||||||
def start(self, item):
|
def start(self, item):
|
||||||
bot = self.bots.setdefault(item.pk, self.BotClass(item))
|
""" Instantiate and start a bot with the provided ORM object.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
xyz = await XYZ.objects.create(hood=hood, **values.__dict__)
|
||||||
|
spawner.start(xyz)
|
||||||
|
```
|
||||||
|
|
||||||
|
Args:
|
||||||
|
item (ORM Model object): Argument to the bot constructor
|
||||||
|
"""
|
||||||
|
bot = self.__bots.setdefault(item.pk, self.BotClass(item))
|
||||||
bot.start()
|
bot.start()
|
||||||
|
|
||||||
def stop(self, item):
|
def stop(self, item):
|
||||||
bot = self.bots.pop(item.pk, None)
|
""" Stop and delete a bot.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
item (ORM Model object): ORM object corresponding to bot.
|
||||||
|
"""
|
||||||
|
bot = self.__bots.pop(item.pk, None)
|
||||||
if bot is not None:
|
if bot is not None:
|
||||||
bot.stop()
|
bot.stop()
|
||||||
|
|
||||||
def get(self, item):
|
def get(self, item):
|
||||||
return self.bots.get(item.pk)
|
""" Get a running bot.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
item (ORM Model object): ORM object corresponding to bot.
|
||||||
|
"""
|
||||||
|
return self.__bots.get(item.pk)
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" Routing definitions for the REST API.
|
||||||
|
|
||||||
|
A platform bot shall add its API router in this `__init__.py`
|
||||||
|
file to get included into the main application.
|
||||||
|
"""
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from kibicara.platforms.test.webapi import router as test_router
|
from kibicara.platforms.test.webapi import router as test_router
|
||||||
from kibicara.platforms.telegram.webapi import router as telegram_router
|
from kibicara.platforms.telegram.webapi import router as telegram_router
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" REST API endpoints for hood admins. """
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||||
from kibicara import email
|
from kibicara import email
|
||||||
|
@ -71,8 +73,14 @@ router = APIRouter()
|
||||||
|
|
||||||
@router.post('/register/', status_code=status.HTTP_202_ACCEPTED)
|
@router.post('/register/', status_code=status.HTTP_202_ACCEPTED)
|
||||||
async def admin_register(values: BodyAdmin):
|
async def admin_register(values: BodyAdmin):
|
||||||
|
""" Sends an email with a confirmation link.
|
||||||
|
|
||||||
|
- **email**: E-Mail Address of new hood admin
|
||||||
|
- **password**: Password of new hood admin
|
||||||
|
"""
|
||||||
register_token = to_token(**values.__dict__)
|
register_token = to_token(**values.__dict__)
|
||||||
logger.debug(f'register_token={register_token}')
|
logger.debug(f'register_token={register_token}')
|
||||||
|
# TODO implement check to see if email already is in database
|
||||||
try:
|
try:
|
||||||
email.send_email(
|
email.send_email(
|
||||||
to=values.email,
|
to=values.email,
|
||||||
|
@ -88,6 +96,10 @@ async def admin_register(values: BodyAdmin):
|
||||||
|
|
||||||
@router.post('/confirm/{register_token}')
|
@router.post('/confirm/{register_token}')
|
||||||
async def admin_confirm(register_token: str):
|
async def admin_confirm(register_token: str):
|
||||||
|
""" Registration confirmation and account creation.
|
||||||
|
|
||||||
|
- **register_token**: Registration token received in email from /register
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
values = from_token(register_token)
|
values = from_token(register_token)
|
||||||
passhash = argon2.hash(values['password'])
|
passhash = argon2.hash(values['password'])
|
||||||
|
@ -99,6 +111,11 @@ async def admin_confirm(register_token: str):
|
||||||
|
|
||||||
@router.post('/login/')
|
@router.post('/login/')
|
||||||
async def admin_login(form_data: OAuth2PasswordRequestForm = Depends()):
|
async def admin_login(form_data: OAuth2PasswordRequestForm = Depends()):
|
||||||
|
""" Get an access token.
|
||||||
|
|
||||||
|
- **username**: Email of a registered hood admin
|
||||||
|
- **password**: Password of a registered hood admin
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
await get_auth(form_data.username, form_data.password)
|
await get_auth(form_data.username, form_data.password)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -112,6 +129,7 @@ async def admin_login(form_data: OAuth2PasswordRequestForm = Depends()):
|
||||||
|
|
||||||
@router.get('/hoods/')
|
@router.get('/hoods/')
|
||||||
async def admin_hood_read_all(admin=Depends(get_admin)):
|
async def admin_hood_read_all(admin=Depends(get_admin)):
|
||||||
|
""" Get a list of all hoods of a given admin. """
|
||||||
return (
|
return (
|
||||||
await AdminHoodRelation.objects.select_related('hood').filter(admin=admin).all()
|
await AdminHoodRelation.objects.select_related('hood').filter(admin=admin).all()
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" REST API Endpoints for managing hoods. """
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
||||||
from kibicara.model import AdminHoodRelation, Hood
|
from kibicara.model import AdminHoodRelation, Hood
|
||||||
from kibicara.webapi.admin import get_admin
|
from kibicara.webapi.admin import get_admin
|
||||||
|
@ -38,11 +40,17 @@ router = APIRouter()
|
||||||
|
|
||||||
@router.get('/')
|
@router.get('/')
|
||||||
async def hood_read_all():
|
async def hood_read_all():
|
||||||
|
""" Get all existing hoods. """
|
||||||
return await Hood.objects.all()
|
return await Hood.objects.all()
|
||||||
|
|
||||||
|
|
||||||
@router.post('/', status_code=status.HTTP_201_CREATED)
|
@router.post('/', status_code=status.HTTP_201_CREATED)
|
||||||
async def hood_create(values: BodyHood, response: Response, admin=Depends(get_admin)):
|
async def hood_create(values: BodyHood, response: Response, admin=Depends(get_admin)):
|
||||||
|
""" Creates a hood.
|
||||||
|
|
||||||
|
- **name**: Name of the hood
|
||||||
|
- **landingpage**: Markdown formatted description of the hood
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
hood = await Hood.objects.create(**values.__dict__)
|
hood = await Hood.objects.create(**values.__dict__)
|
||||||
await AdminHoodRelation.objects.create(admin=admin.id, hood=hood.id)
|
await AdminHoodRelation.objects.create(admin=admin.id, hood=hood.id)
|
||||||
|
@ -54,16 +62,23 @@ async def hood_create(values: BodyHood, response: Response, admin=Depends(get_ad
|
||||||
|
|
||||||
@router.get('/{hood_id}')
|
@router.get('/{hood_id}')
|
||||||
async def hood_read(hood=Depends(get_hood)):
|
async def hood_read(hood=Depends(get_hood)):
|
||||||
|
""" Get hood with id **hood_id**. """
|
||||||
return hood
|
return hood
|
||||||
|
|
||||||
|
|
||||||
@router.put('/{hood_id}', status_code=status.HTTP_204_NO_CONTENT)
|
@router.put('/{hood_id}', status_code=status.HTTP_204_NO_CONTENT)
|
||||||
async def hood_update(values: BodyHood, hood=Depends(get_hood)):
|
async def hood_update(values: BodyHood, hood=Depends(get_hood)):
|
||||||
|
""" Updates hood with id **hood_id**.
|
||||||
|
|
||||||
|
- **name**: New name of the hood
|
||||||
|
- **landingpage**: New Markdown formatted description of the hood
|
||||||
|
"""
|
||||||
await hood.update(**values.__dict__)
|
await hood.update(**values.__dict__)
|
||||||
|
|
||||||
|
|
||||||
@router.delete('/{hood_id}', status_code=status.HTTP_204_NO_CONTENT)
|
@router.delete('/{hood_id}', status_code=status.HTTP_204_NO_CONTENT)
|
||||||
async def hood_delete(hood=Depends(get_hood)):
|
async def hood_delete(hood=Depends(get_hood)):
|
||||||
|
""" Deletes hood with id **hood_id**. """
|
||||||
for relation in await AdminHoodRelation.objects.filter(hood=hood).all():
|
for relation in await AdminHoodRelation.objects.filter(hood=hood).all():
|
||||||
await relation.delete()
|
await relation.delete()
|
||||||
await hood.delete()
|
await hood.delete()
|
||||||
|
|
|
@ -3,6 +3,13 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" REST API endpoints for managing badwords.
|
||||||
|
|
||||||
|
Provides API endpoints for adding, removing and reading regular expressions that block a
|
||||||
|
received message to be dropped by a censor. This provides a message filter customizable
|
||||||
|
by the hood admins.
|
||||||
|
"""
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
||||||
from kibicara.model import BadWord
|
from kibicara.model import BadWord
|
||||||
from kibicara.webapi.hoods import get_hood
|
from kibicara.webapi.hoods import get_hood
|
||||||
|
@ -28,6 +35,7 @@ router = APIRouter()
|
||||||
|
|
||||||
@router.get('/')
|
@router.get('/')
|
||||||
async def badword_read_all(hood=Depends(get_hood)):
|
async def badword_read_all(hood=Depends(get_hood)):
|
||||||
|
""" Get all badwords of hood with id **hood_id**. """
|
||||||
return await BadWord.objects.filter(hood=hood).all()
|
return await BadWord.objects.filter(hood=hood).all()
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,6 +43,10 @@ async def badword_read_all(hood=Depends(get_hood)):
|
||||||
async def badword_create(
|
async def badword_create(
|
||||||
values: BodyBadWord, response: Response, hood=Depends(get_hood)
|
values: BodyBadWord, response: Response, hood=Depends(get_hood)
|
||||||
):
|
):
|
||||||
|
""" Creates a new badword for hood with id **hood_id**.
|
||||||
|
|
||||||
|
- **pattern**: Regular expression which is used to match a badword.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
regex_compile(values.pattern)
|
regex_compile(values.pattern)
|
||||||
badword = await BadWord.objects.create(hood=hood, **values.__dict__)
|
badword = await BadWord.objects.create(hood=hood, **values.__dict__)
|
||||||
|
@ -48,14 +60,20 @@ async def badword_create(
|
||||||
|
|
||||||
@router.get('/{badword_id}')
|
@router.get('/{badword_id}')
|
||||||
async def badword_read(badword=Depends(get_badword)):
|
async def badword_read(badword=Depends(get_badword)):
|
||||||
|
""" Reads badword with id **badword_id** for hood with id **hood_id**. """
|
||||||
return badword
|
return badword
|
||||||
|
|
||||||
|
|
||||||
@router.put('/{badword_id}', status_code=status.HTTP_204_NO_CONTENT)
|
@router.put('/{badword_id}', status_code=status.HTTP_204_NO_CONTENT)
|
||||||
async def badword_update(values: BodyBadWord, badword=Depends(get_badword)):
|
async def badword_update(values: BodyBadWord, badword=Depends(get_badword)):
|
||||||
|
""" Updates badword with id **badword_id** for hood with id **hood_id**.
|
||||||
|
|
||||||
|
- **pattern**: Regular expression which is used to match a badword
|
||||||
|
"""
|
||||||
await badword.update(**values.__dict__)
|
await badword.update(**values.__dict__)
|
||||||
|
|
||||||
|
|
||||||
@router.delete('/{badword_id}', status_code=status.HTTP_204_NO_CONTENT)
|
@router.delete('/{badword_id}', status_code=status.HTTP_204_NO_CONTENT)
|
||||||
async def badword_delete(badword=Depends(get_badword)):
|
async def badword_delete(badword=Depends(get_badword)):
|
||||||
|
""" Deletes badword with id **badword_id** for hood with id **hood_id**. """
|
||||||
await badword.delete()
|
await badword.delete()
|
||||||
|
|
|
@ -3,6 +3,14 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: 0BSD
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
""" REST API endpoints for managing triggers.
|
||||||
|
|
||||||
|
Provides API endpoints for adding, removing and reading regular expressions that allow a
|
||||||
|
message to be passed through by a censor. A published message must match one of these
|
||||||
|
regular expressions otherwise it gets dropped by the censor. This provides a message
|
||||||
|
filter customizable by the hood admins.
|
||||||
|
"""
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
||||||
from kibicara.model import Trigger
|
from kibicara.model import Trigger
|
||||||
from kibicara.webapi.hoods import get_hood
|
from kibicara.webapi.hoods import get_hood
|
||||||
|
@ -28,6 +36,7 @@ router = APIRouter()
|
||||||
|
|
||||||
@router.get('/')
|
@router.get('/')
|
||||||
async def trigger_read_all(hood=Depends(get_hood)):
|
async def trigger_read_all(hood=Depends(get_hood)):
|
||||||
|
""" Get all triggers of hood with id **hood_id**. """
|
||||||
return await Trigger.objects.filter(hood=hood).all()
|
return await Trigger.objects.filter(hood=hood).all()
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,6 +44,10 @@ async def trigger_read_all(hood=Depends(get_hood)):
|
||||||
async def trigger_create(
|
async def trigger_create(
|
||||||
values: BodyTrigger, response: Response, hood=Depends(get_hood)
|
values: BodyTrigger, response: Response, hood=Depends(get_hood)
|
||||||
):
|
):
|
||||||
|
""" Creates a new trigger for hood with id **hood_id**.
|
||||||
|
|
||||||
|
- **pattern**: Regular expression which is used to match a trigger.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
regex_compile(values.pattern)
|
regex_compile(values.pattern)
|
||||||
trigger = await Trigger.objects.create(hood=hood, **values.__dict__)
|
trigger = await Trigger.objects.create(hood=hood, **values.__dict__)
|
||||||
|
@ -48,14 +61,20 @@ async def trigger_create(
|
||||||
|
|
||||||
@router.get('/{trigger_id}')
|
@router.get('/{trigger_id}')
|
||||||
async def trigger_read(trigger=Depends(get_trigger)):
|
async def trigger_read(trigger=Depends(get_trigger)):
|
||||||
|
""" Reads trigger with id **trigger_id** for hood with id **hood_id**. """
|
||||||
return trigger
|
return trigger
|
||||||
|
|
||||||
|
|
||||||
@router.put('/{trigger_id}', status_code=status.HTTP_204_NO_CONTENT)
|
@router.put('/{trigger_id}', status_code=status.HTTP_204_NO_CONTENT)
|
||||||
async def trigger_update(values: BodyTrigger, trigger=Depends(get_trigger)):
|
async def trigger_update(values: BodyTrigger, trigger=Depends(get_trigger)):
|
||||||
|
""" Updates trigger with id **trigger_id** for hood with id **hood_id**.
|
||||||
|
|
||||||
|
- **pattern**: Regular expression which is used to match a trigger
|
||||||
|
"""
|
||||||
await trigger.update(**values.__dict__)
|
await trigger.update(**values.__dict__)
|
||||||
|
|
||||||
|
|
||||||
@router.delete('/{trigger_id}', status_code=status.HTTP_204_NO_CONTENT)
|
@router.delete('/{trigger_id}', status_code=status.HTTP_204_NO_CONTENT)
|
||||||
async def trigger_delete(trigger=Depends(get_trigger)):
|
async def trigger_delete(trigger=Depends(get_trigger)):
|
||||||
|
""" Deletes trigger with id **trigger_id** for hood with id **hood_id**. """
|
||||||
await trigger.delete()
|
await trigger.delete()
|
||||||
|
|
Loading…
Reference in a new issue