Compare commits
4 Commits
12b0bf55f8
...
e4c552af01
Author | SHA1 | Date |
---|---|---|
Ferdinand Thiessen | e4c552af01 | |
Ferdinand Thiessen | 90999bbefb | |
Ferdinand Thiessen | fb50ed05be | |
Ferdinand Thiessen | 54a789b772 |
|
@ -17,5 +17,3 @@ matrix:
|
||||||
PYTHON:
|
PYTHON:
|
||||||
- 3.10
|
- 3.10
|
||||||
- 3.9
|
- 3.9
|
||||||
- 3.8
|
|
||||||
- 3.7
|
|
||||||
|
|
19
README.md
19
README.md
|
@ -7,20 +7,29 @@ This is the backend of the Flaschengeist.
|
||||||
### Requirements
|
### Requirements
|
||||||
- `mysql` or `mariadb`
|
- `mysql` or `mariadb`
|
||||||
- maybe `libmariadb` development files[1]
|
- maybe `libmariadb` development files[1]
|
||||||
- python 3.7+
|
- python 3.9+
|
||||||
|
- pip 21.0+
|
||||||
|
|
||||||
[1] By default Flaschengeist uses mysql as database backend, if you are on Windows Flaschengeist uses `PyMySQL`, but on
|
*[1] By default Flaschengeist uses mysql as database backend, if you are on Windows Flaschengeist uses `PyMySQL`, but on
|
||||||
Linux / Mac the faster `mysqlclient` is used, if it is not already installed installing from pypi requires the
|
Linux / Mac the faster `mysqlclient` is used, if it is not already installed installing from pypi requires the
|
||||||
development files for `libmariadb` to be present on your system.
|
development files for `libmariadb` to be present on your system.*
|
||||||
|
|
||||||
### Install python files
|
### Install python files
|
||||||
pip3 install --user .
|
It is recommended to upgrade pip to the latest version before installing:
|
||||||
|
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
|
||||||
|
Default installation with *mariadb*/*mysql* support:
|
||||||
|
|
||||||
|
pip3 install --user ".[mysql]"
|
||||||
|
|
||||||
or with ldap support
|
or with ldap support
|
||||||
|
|
||||||
pip3 install --user ".[ldap]"
|
pip3 install --user ".[ldap]"
|
||||||
|
|
||||||
or if you want to also run the tests:
|
or if you want to also run the tests:
|
||||||
|
|
||||||
pip3 install --user ".[ldap,test]"
|
pip3 install --user ".[ldap,tests]"
|
||||||
|
|
||||||
You will also need a MySQL driver, recommended drivers are
|
You will also need a MySQL driver, recommended drivers are
|
||||||
- `mysqlclient`
|
- `mysqlclient`
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
"""Controller for Plugin logic
|
||||||
|
|
||||||
|
Used by plugins for setting and notification functionality.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sqlalchemy
|
||||||
|
from ..database import db
|
||||||
|
from ..models.setting import _PluginSetting
|
||||||
|
from ..models.notification import Notification
|
||||||
|
|
||||||
|
|
||||||
|
def get_setting(plugin_id: str, name: str, **kwargs):
|
||||||
|
"""Get plugin setting from database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
plugin_id: ID of the plugin
|
||||||
|
name: string identifying the setting
|
||||||
|
default: Default value
|
||||||
|
Returns:
|
||||||
|
Value stored in database (native python)
|
||||||
|
Raises:
|
||||||
|
`KeyError` if no such setting exists in the database
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
setting = (
|
||||||
|
_PluginSetting.query.filter(_PluginSetting.plugin == plugin_id).filter(_PluginSetting.name == name).one()
|
||||||
|
)
|
||||||
|
return setting.value
|
||||||
|
except sqlalchemy.orm.exc.NoResultFound:
|
||||||
|
if "default" in kwargs:
|
||||||
|
return kwargs["default"]
|
||||||
|
else:
|
||||||
|
raise KeyError
|
||||||
|
|
||||||
|
|
||||||
|
def set_setting(plugin_id: str, name: str, value):
|
||||||
|
"""Save setting in database
|
||||||
|
|
||||||
|
Args:
|
||||||
|
plugin_id: ID of the plugin
|
||||||
|
name: String identifying the setting
|
||||||
|
value: Value to be stored
|
||||||
|
"""
|
||||||
|
setting = (
|
||||||
|
_PluginSetting.query.filter(_PluginSetting.plugin == plugin_id)
|
||||||
|
.filter(_PluginSetting.name == name)
|
||||||
|
.one_or_none()
|
||||||
|
)
|
||||||
|
if setting is not None:
|
||||||
|
if value is None:
|
||||||
|
db.session.delete(setting)
|
||||||
|
else:
|
||||||
|
setting.value = value
|
||||||
|
else:
|
||||||
|
db.session.add(_PluginSetting(plugin=plugin_id, name=name, value=value))
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def notify(plugin_id: str, user, text: str, data=None):
|
||||||
|
"""Create a new notification for an user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
plugin_id: ID of the plugin
|
||||||
|
user: `flaschengeist.models.user.User` to notify
|
||||||
|
text: Visibile notification text
|
||||||
|
data: Optional data passed to the notificaton
|
||||||
|
Returns:
|
||||||
|
ID of the created `flaschengeist.models.notification.Notification`
|
||||||
|
|
||||||
|
Hint: use the data for frontend actions.
|
||||||
|
"""
|
||||||
|
if not user.deleted:
|
||||||
|
n = Notification(text=text, data=data, plugin=plugin_id, user_=user)
|
||||||
|
db.session.add(n)
|
||||||
|
db.session.commit()
|
||||||
|
return n.id
|
|
@ -1,13 +1,9 @@
|
||||||
from dataclasses import asdict, dataclass, field
|
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
|
from dataclasses import asdict, dataclass, field
|
||||||
from werkzeug.datastructures import FileStorage
|
from werkzeug.datastructures import FileStorage
|
||||||
from werkzeug.exceptions import MethodNotAllowed, NotFound
|
from werkzeug.exceptions import MethodNotAllowed, NotFound
|
||||||
|
|
||||||
from flaschengeist.database import db
|
|
||||||
from flaschengeist.controller import imageController
|
|
||||||
from flaschengeist.models.notification import Notification
|
|
||||||
from flaschengeist.models.user import _Avatar, User
|
from flaschengeist.models.user import _Avatar, User
|
||||||
from flaschengeist.models.setting import _PluginSetting
|
|
||||||
from flaschengeist.utils.hook import HookBefore, HookAfter
|
from flaschengeist.utils.hook import HookBefore, HookAfter
|
||||||
|
|
||||||
plugins_installed = HookAfter("plugins.installed")
|
plugins_installed = HookAfter("plugins.installed")
|
||||||
|
@ -133,18 +129,9 @@ class Plugin(PluginMetadata):
|
||||||
Raises:
|
Raises:
|
||||||
`KeyError` if no such setting exists in the database
|
`KeyError` if no such setting exists in the database
|
||||||
"""
|
"""
|
||||||
try:
|
from ..controller import pluginController
|
||||||
setting = (
|
|
||||||
_PluginSetting.query.filter(_PluginSetting.plugin == self.name)
|
return pluginController.get_setting(self.id)
|
||||||
.filter(_PluginSetting.name == name)
|
|
||||||
.one()
|
|
||||||
)
|
|
||||||
return setting.value
|
|
||||||
except sqlalchemy.orm.exc.NoResultFound:
|
|
||||||
if "default" in kwargs:
|
|
||||||
return kwargs["default"]
|
|
||||||
else:
|
|
||||||
raise KeyError
|
|
||||||
|
|
||||||
def set_setting(self, name: str, value):
|
def set_setting(self, name: str, value):
|
||||||
"""Save setting in database
|
"""Save setting in database
|
||||||
|
@ -153,19 +140,9 @@ class Plugin(PluginMetadata):
|
||||||
name: String identifying the setting
|
name: String identifying the setting
|
||||||
value: Value to be stored
|
value: Value to be stored
|
||||||
"""
|
"""
|
||||||
setting = (
|
from ..controller import pluginController
|
||||||
_PluginSetting.query.filter(_PluginSetting.plugin == self.name)
|
|
||||||
.filter(_PluginSetting.name == name)
|
return pluginController.set_setting(self.id, name, value)
|
||||||
.one_or_none()
|
|
||||||
)
|
|
||||||
if setting is not None:
|
|
||||||
if value is None:
|
|
||||||
db.session.delete(setting)
|
|
||||||
else:
|
|
||||||
setting.value = value
|
|
||||||
else:
|
|
||||||
db.session.add(_PluginSetting(plugin=self.name, name=name, value=value))
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
def notify(self, user, text: str, data=None):
|
def notify(self, user, text: str, data=None):
|
||||||
"""Create a new notification for an user
|
"""Create a new notification for an user
|
||||||
|
@ -179,11 +156,9 @@ class Plugin(PluginMetadata):
|
||||||
|
|
||||||
Hint: use the data for frontend actions.
|
Hint: use the data for frontend actions.
|
||||||
"""
|
"""
|
||||||
if not user.deleted:
|
from ..controller import pluginController
|
||||||
n = Notification(text=text, data=data, plugin=self.id, user_=user)
|
|
||||||
db.session.add(n)
|
return pluginController.notify(self.id, user, text, data)
|
||||||
db.session.commit()
|
|
||||||
return n.id
|
|
||||||
|
|
||||||
def serialize(self):
|
def serialize(self):
|
||||||
"""Serialize a plugin into a dict
|
"""Serialize a plugin into a dict
|
||||||
|
@ -283,6 +258,10 @@ class AuthPlugin(Plugin):
|
||||||
MethodNotAllowed: If not supported by Backend
|
MethodNotAllowed: If not supported by Backend
|
||||||
Any valid HTTP exception
|
Any valid HTTP exception
|
||||||
"""
|
"""
|
||||||
|
# By default save the image to the avatar,
|
||||||
|
# deleting would happen by unsetting it
|
||||||
|
from ..controller import imageController
|
||||||
|
|
||||||
user.avatar_ = imageController.upload_image(file)
|
user.avatar_ = imageController.upload_image(file)
|
||||||
|
|
||||||
def delete_avatar(self, user: User):
|
def delete_avatar(self, user: User):
|
||||||
|
|
Loading…
Reference in New Issue