Fixed Hooks, use own implementation. Fixed routes.

This commit is contained in:
Ferdinand Thiessen 2020-10-16 00:37:57 +02:00
parent 287cc91947
commit ec05cde746
10 changed files with 405 additions and 330 deletions

View File

@ -1,6 +1,6 @@
from pyhooks import precall_register
from flaschengeist.system.hook import HookCall
send_message_hook = precall_register("send_message")
send_message_hook = HookCall("send_message")
class Plugin:

View File

@ -11,7 +11,7 @@ from werkzeug.local import LocalProxy
from flaschengeist import logger
from flaschengeist.modules import Plugin
from flaschengeist.system.decorator import login_required
from flaschengeist.system.controller import accessTokenController, userController
from flaschengeist.system.controller import accessTokenController, userController, messageController
access_controller = LocalProxy(lambda: accessTokenController.AccessTokenController())
auth_bp = Blueprint("auth", __name__)
@ -21,18 +21,19 @@ class AuthRoutePlugin(Plugin):
def __init__(self, conf):
super().__init__(blueprint=auth_bp)
#################################################
# Routes #
# #
# /auth POST: login (new token) #
# GET: get all tokens for user #
# /auth/<token> GET: get lifetime of token #
# PUT: set new lifetime #
# DELETE: logout / delete token #
#################################################
#################################################
# Routes #
# #
# /auth POST: login (new token) #
# GET: get all tokens for user #
# /auth/<token> GET: get lifetime of token #
# PUT: set new lifetime #
# DELETE: logout / delete token #
#################################################
@auth_bp.route("/auth", methods=["POST"])
def _create_token():
@auth_bp.route("/auth", methods=["POST"])
def _create_token():
"""Login User
Login in User and create an AccessToken for the User.
@ -61,15 +62,19 @@ class AuthRoutePlugin(Plugin):
access_controller.clear_expired()
return jsonify({"user": user, "token": token, "permissions": user.get_permissions()})
@auth_bp.route("/auth", methods=["GET"])
@login_required()
def _get_tokens(access_token, **kwargs):
@auth_bp.route("/auth", methods=["GET"])
@login_required()
def _get_tokens(access_token, **kwargs):
tokens = access_controller.get_users_tokens(access_token.user)
a = messageController.Message(access_token.user, "Go", "Bar")
messageController.send_message(a)
return jsonify(tokens)
@auth_bp.route("/auth/<token>", methods=["DELETE"])
@login_required()
def _delete_token(token, access_token, **kwargs):
@login_required()
@auth_bp.route("/auth/<token>", methods=["DELETE"])
def _delete_token(token, access_token, **kwargs):
logger.debug("Try to delete access token {{ {} }}".format(token))
token = access_controller.get_token(token, access_token.user)
if not token:
@ -81,9 +86,10 @@ class AuthRoutePlugin(Plugin):
access_controller.clear_expired()
return jsonify({"ok": "ok"})
@auth_bp.route("/auth/<token>", methods=["GET"])
@login_required()
def _get_token(token, access_token, **kwargs):
@login_required()
@auth_bp.route("/auth/<token>", methods=["GET"])
def _get_token(token, access_token, **kwargs):
logger.debug("get token {{ {} }}".format(token))
token = access_controller.get_token(token, access_token.user)
if not token:
@ -92,9 +98,10 @@ class AuthRoutePlugin(Plugin):
raise Forbidden
return jsonify(token)
@auth_bp.route("/auth/<token>", methods=["PUT"])
@login_required()
def _set_lifetime(token, access_token, **kwargs):
@login_required()
@auth_bp.route("/auth/<token>", methods=["PUT"])
def _set_lifetime(token, access_token, **kwargs):
token = access_controller.get_token(token, access_token.user)
if not token:
# Return 403 error, so that users can not bruteforce tokens

View File

@ -1,6 +1,8 @@
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from flaschengeist import logger
from flaschengeist.system.models.user import User
from flaschengeist.system.controller import userController
from flaschengeist.system.controller.messageController import Message
@ -19,8 +21,14 @@ class MailMessagePlugin(Plugin):
self.mail = config["MAIL"]
@send_message_hook
def dummy_send(msg):
self.send_mail(msg)
def send_mail(self, msg: Message):
if isinstance(msg.receiver, User):
if not msg.receiver.mail:
logger.warn("Could not send Mail, mail missing: {}".format(msg.receiver))
return
recipients = [msg.receiver.mail]
else:
recipients = userController.get_user_by_role(msg.receiver)
@ -29,15 +37,17 @@ class MailMessagePlugin(Plugin):
mail["From"] = self.mail
mail["To"] = ", ".join(recipients)
mail["Subject"] = msg.subject
msg.attach(msg.message)
if not self.smtp:
mail.attach(MIMEText(msg.message))
if not hasattr(self, "smtp"):
self.__connect()
self.smtp.sendmail(self.mail, recipients, msg.as_string())
self.smtp.sendmail(self.mail, recipients, mail.as_string())
def __connect(self):
if self.crypt == "SSL":
self.smtp = smtplib.SMTP_SSL(self.server, self.port)
if self.crypt == "STARTTLS":
self.smtp = smtplib.SMTP(self.smtpServer, self.port)
elif self.crypt == "STARTTLS":
self.smtp = smtplib.SMTP(self.server, self.port)
self.smtp.starttls()
else:
raise ValueError("Invalid CRYPT given")
self.smtp.login(self.user, self.password)

View File

@ -12,20 +12,21 @@ class RolesPlugin(Plugin):
def __init__(self, config):
super().__init__(config, roles_bp)
######################################################
# Routes #
# #
# /roles POST: register new #
# GET: get all roles #
# /roles/permissions GET: get all permissions #
# /roles/<rid> GET: get role with rid #
# PUT: modify role / permission #
# DELETE: remove role #
######################################################
######################################################
# Routes #
# #
# /roles POST: register new #
# GET: get all roles #
# /roles/permissions GET: get all permissions #
# /roles/<rid> GET: get role with rid #
# PUT: modify role / permission #
# DELETE: remove role #
######################################################
@roles_bp.route("/roles", methods=["POST"])
@login_required()
def add_role(self):
@roles_bp.route("/roles", methods=["POST"])
@login_required()
def add_role(self):
data = request.get_json()
if not data or "name" not in data:
raise BadRequest
@ -34,29 +35,33 @@ class RolesPlugin(Plugin):
role = roleController.create_role(data["name"], permissions)
return jsonify({"ok": "ok", "id": role.id})
@roles_bp.route("/roles", methods=["GET"])
@login_required()
def list_roles(self, **kwargs):
@roles_bp.route("/roles", methods=["GET"])
@login_required()
def list_roles(**kwargs):
roles = roleController.get_roles()
return jsonify(roles)
@roles_bp.route("/roles/permissions", methods=["GET"])
@login_required()
def list_permissions(self, **kwargs):
@roles_bp.route("/roles/permissions", methods=["GET"])
@login_required()
def list_permissions(**kwargs):
permissions = roleController.get_permissions()
return jsonify(permissions)
@roles_bp.route("/roles/<rid>", methods=["GET"])
@login_required()
def __get_role(self, rid, **kwargs):
@roles_bp.route("/roles/<rid>", methods=["GET"])
@login_required()
def __get_role(rid, **kwargs):
role = roleController.get_role(rid)
if role:
return jsonify({"id": role.id, "name": role, "permissions": role.permissions})
raise NotFound
@roles_bp.route("/roles/<rid>", methods=["PUT"])
@login_required()
def __edit_role(self, rid, **kwargs):
@roles_bp.route("/roles/<rid>", methods=["PUT"])
@login_required()
def __edit_role(rid, **kwargs):
role = roleController.get_role(rid)
if not role:
raise NotFound
@ -69,9 +74,10 @@ class RolesPlugin(Plugin):
roleController.update_role(role)
return jsonify({"ok": "ok"})
@roles_bp.route("/roles/<rid>", methods=["DELETE"])
@login_required()
def __delete_role(self, rid, **kwargs):
@roles_bp.route("/roles/<rid>", methods=["DELETE"])
@login_required()
def __delete_role(rid, **kwargs):
if not roleController.delete_role(rid):
raise NotFound

View File

@ -16,40 +16,42 @@ class SchedulePlugin(Plugin):
def __init__(self, config):
super().__init__(blueprint=schedule_bp)
####################################################################################
# Routes #
# #
# /schedule/events POST: create new #
# GET: get all events this month #
# /schedule/events/<year>/<month> GET: get events by month / date #
# /<year>/<month>/<day> #
# /schedule/events/<id> GET: get event by ID #
# DELETE: delete specified event #
# PUT: modify specified event #
# /schedule/events/<id>/slots GET: get EventSlots of Event #
# POST: add new EventSlot to Event #
# /schedule/events/<id>/slots/<sid> PUT: modify EventSlot #
# GET: get specified EventSlot #
# /schedule/events/<id>/slots/<sid>/jobs POST: add User #
# /schedule/eventKinds
# /schedule/eventKinds/<id>
# PUT: modify user #
# DELETE: remove user #
####################################################################################
####################################################################################
# Routes #
# #
# /schedule/events POST: create new #
# GET: get all events this month #
# /schedule/events/<year>/<month> GET: get events by month / date #
# /<year>/<month>/<day> #
# /schedule/events/<id> GET: get event by ID #
# DELETE: delete specified event #
# PUT: modify specified event #
# /schedule/events/<id>/slots GET: get EventSlots of Event #
# POST: add new EventSlot to Event #
# /schedule/events/<id>/slots/<sid> PUT: modify EventSlot #
# GET: get specified EventSlot #
# /schedule/events/<id>/slots/<sid>/jobs POST: add User #
# /schedule/eventKinds
# /schedule/eventKinds/<id>
# PUT: modify user #
# DELETE: remove user #
####################################################################################
@schedule_bp.route("/events/<int:id>", methods=["GET"])
@login_required() # roles=['schedule_read'])
def __get_event(self, id, **kwargs):
@schedule_bp.route("/events/<int:id>", methods=["GET"])
@login_required() # roles=['schedule_read'])
def __get_event(self, id, **kwargs):
event = eventController.get_event(id)
if not event:
raise NotFound
return jsonify(event)
@schedule_bp.route("/events", methods=["GET"])
@schedule_bp.route("/events/<int:year>/<int:month>", methods=["GET"])
@schedule_bp.route("/events/<int:year>/<int:month>/<int:day>", methods=["GET"])
@login_required() # roles=['schedule_read'])
def __get_events(self, year=datetime.now().year, month=datetime.now().month, day=None, **kwrags):
@schedule_bp.route("/events", methods=["GET"])
@schedule_bp.route("/events/<int:year>/<int:month>", methods=["GET"])
@schedule_bp.route("/events/<int:year>/<int:month>/<int:day>", methods=["GET"])
@login_required() # roles=['schedule_read'])
def __get_events(year=datetime.now().year, month=datetime.now().month, day=None, **kwargs):
"""Get Event objects for specified date (or month or year),
if nothing set then events for current month are returned
@ -57,7 +59,7 @@ class SchedulePlugin(Plugin):
year (int, optional): year to query, defaults to current year
month (int, optional): month to query (if set), defaults to current month
day (int, optional): day to query events for (if set)
**kwrags: contains at least access_token (see flaschengeist.decorator)
**kwargs: contains at least access_token (see flaschengeist.decorator)
Returns:
JSON list containing events found
Raises:
@ -79,27 +81,30 @@ class SchedulePlugin(Plugin):
except ValueError:
raise BadRequest("Invalid date given")
@schedule_bp.route("/eventKinds", methods=["POST"])
@login_required()
def __new_event_kind(self, **kwargs):
@schedule_bp.route("/eventKinds", methods=["POST"])
@login_required()
def __new_event_kind(**kwargs):
data = request.get_json()
if "name" not in data:
raise BadRequest
kind = eventController.create_event_kind(data["name"])
return jsonify({"ok": "ok", "id": kind.id})
@schedule_bp.route("/slotKinds", methods=["POST"])
@login_required()
def __new_slot_kind(self, **kwargs):
@schedule_bp.route("/slotKinds", methods=["POST"])
@login_required()
def __new_slot_kind(**kwargs):
data = request.get_json()
if not data or "name" not in data:
raise BadRequest
kind = eventController.create_job_kind(data["name"])
return jsonify({"ok": "ok", "id": kind.id})
@schedule_bp.route("/events", methods=["POST"])
@login_required()
def __new_event(self, **kwargs):
@schedule_bp.route("/events", methods=["POST"])
@login_required()
def __new_event(**kwargs):
data = request.get_json()
event = eventController.create_event(
begin=parser.isoparse(data["begin"]),
@ -109,49 +114,55 @@ class SchedulePlugin(Plugin):
)
return jsonify({"ok": "ok", "id": event.id})
@schedule_bp.route("/events/<int:id>", methods=["DELETE"])
@login_required()
def __delete_event(self, id, **kwargs):
if not eventController.delete_event(id):
@schedule_bp.route("/events/<int:event_id>", methods=["DELETE"])
@login_required()
def __delete_event(event_id, **kwargs):
if not eventController.delete_event(event_id):
raise NotFound
db.session.commit()
return jsonify({"ok": "ok"})
@schedule_bp.route("/eventKinds/<int:id>", methods=["PUT"])
@login_required()
def __edit_event_kind(self, id, **kwargs):
@schedule_bp.route("/eventKinds/<int:event_id>", methods=["PUT"])
@login_required()
def __edit_event_kind(event_id, **kwargs):
data = request.get_json()
if not data or "name" not in data:
raise BadRequest
eventController.rename_event_kind(id, data["name"])
eventController.rename_event_kind(event_id, data["name"])
return jsonify({"ok": "ok"})
@schedule_bp.route("/events/<int:event_id>/slots", methods=["GET"])
@login_required()
def __get_slots(self, event_id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots", methods=["GET"])
@login_required()
def __get_slots(event_id, **kwargs):
event = eventController.get_event(event_id)
if not event:
raise NotFound
return jsonify({event.slots})
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["GET"])
@login_required()
def __get_slot(self, event_id, slot_id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["GET"])
@login_required()
def __get_slot(event_id, slot_id, **kwargs):
slot = eventController.get_event_slot(slot_id, event_id)
if slot:
return jsonify(slot)
raise NotFound
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["DELETE"])
@login_required()
def __delete_slot(self, event_id, slot_id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["DELETE"])
@login_required()
def __delete_slot(event_id, slot_id, **kwargs):
if eventController.delete_event_slot(slot_id, event_id):
return jsonify({"ok": "ok"})
raise NotFound
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["PUT"])
@login_required()
def __update_slot(self, event_id, slot_id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["PUT"])
@login_required()
def __update_slot(event_id, slot_id, **kwargs):
data = request.get_json()
if not data:
raise BadRequest
@ -162,9 +173,10 @@ class SchedulePlugin(Plugin):
return jsonify({"ok": "ok"})
raise NotFound
@schedule_bp.route("/events/<int:event_id>/slots", methods=["POST"])
@login_required()
def __add_slot(self, event_id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots", methods=["POST"])
@login_required()
def __add_slot(event_id, **kwargs):
event = eventController.get_event(event_id)
if not event:
raise NotFound
@ -182,5 +194,6 @@ class SchedulePlugin(Plugin):
eventController.add_slot(event, **attr)
return jsonify({"ok": "ok"})
def __edit_event(self):
def __edit_event():
...

View File

@ -24,30 +24,34 @@ class UsersPlugin(Plugin):
# DELETE: remove user #
#################################################
@users_bp.route("/users", methods=["POST"])
def __registration(self):
@users_bp.route("/users", methods=["POST"])
def __registration(self):
logger.debug("Register new User...")
return jsonify({"ok": "ok... well not implemented"})
@users_bp.route("/users", methods=["GET"])
@login_required()
def __list_users(self, **kwargs):
@users_bp.route("/users", methods=["GET"])
@login_required()
def __list_users(**kwargs):
logger.debug("Retrieve list of all users")
users = userController.get_users()
return jsonify(users)
@users_bp.route("/users/<uid>", methods=["GET"])
@login_required()
def __get_user(self, uid, **kwargs):
@users_bp.route("/users/<uid>", methods=["GET"])
@login_required()
def __get_user(uid, **kwargs):
logger.debug("Get information of user {{ {} }}".format(uid))
user = userController.get_user(uid)
if user:
return jsonify(user)
raise NotFound
@users_bp.route("/users/<uid>", methods=["PUT"])
@login_required()
def __edit_user(self, uid, **kwargs):
@users_bp.route("/users/<uid>", methods=["PUT"])
@login_required()
def __edit_user(uid, **kwargs):
logger.debug("Modify information of user {{ {} }}".format(uid))
user = userController.get_user(uid)
if not user:

View File

@ -28,7 +28,22 @@ or with debug messages:
run_flaschengeist --debug
## Development
### Code Style
We enforce you to use PEP 8 code style with a line length of 120 as used by Black.
See also [Black Code Style](https://github.com/psf/black/blob/master/docs/the_black_code_style.md).
#### Code formatting
We use [Black](https://github.com/psf/black) as the code formatter.
Installation:
pip install black
Usage:
black -l 120 DIRECTORY_OR_FILE
### Misc
#### Git blame
When using `git blame` use this to ignore the code formatting commits:
$ git blame FILE.py --ignore-revs-file .git-blame-ignore-revs

View File

@ -1,5 +1,6 @@
from flaschengeist import logger
from flaschengeist.system.hook import Hook
from flaschengeist.system.models.user import User, Role
from pyhooks import Hook
class Message:

View File

@ -0,0 +1,20 @@
_hook_dict = {}
class Hook(object):
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
if self.function.__name__ in _hook_dict:
_hook_dict[self.function.__name__](*args, **kwargs)
self.function(*args, **kwargs)
class HookCall(object):
def __init__(self, name):
self.name = name
def __call__(self, function):
_hook_dict[self.name] = function
return function

View File

@ -19,7 +19,6 @@ setup(
"werkzeug",
"bjoern",
"python-dateutil",
"pyhooks",
],
extras_require={"ldap": ["flask_ldapconn", "ldap3"]},
entry_points={