Only use one plugin system, load auth and "normal" plugins at once.
* Added Plugin class, where to inheritate from
This commit is contained in:
parent
60c2637784
commit
2c55edf6a8
|
@ -6,6 +6,7 @@ from flask.json import JSONEncoder, jsonify
|
||||||
from werkzeug.exceptions import HTTPException
|
from werkzeug.exceptions import HTTPException
|
||||||
|
|
||||||
from . import logger
|
from . import logger
|
||||||
|
from .modules import AuthPlugin
|
||||||
from .system.config import config, configure_app
|
from .system.config import config, configure_app
|
||||||
from .system.controller import roleController
|
from .system.controller import roleController
|
||||||
|
|
||||||
|
@ -30,19 +31,6 @@ class CustomJSONEncoder(JSONEncoder):
|
||||||
return JSONEncoder.default(self, o)
|
return JSONEncoder.default(self, o)
|
||||||
|
|
||||||
|
|
||||||
def __load_auth(app):
|
|
||||||
for entry_point in pkg_resources.iter_entry_points('flaschengeist.auth'):
|
|
||||||
logger.debug('Found authentication plugin: %s', entry_point.name)
|
|
||||||
if entry_point.name == config['FLASCHENGEIST']['AUTH']:
|
|
||||||
app.config['FG_AUTH_BACKEND'] = entry_point.load()()
|
|
||||||
app.config['FG_AUTH_BACKEND'].configure(
|
|
||||||
config[entry_point.name] if config.has_section(entry_point.name) else {})
|
|
||||||
logger.info('Loaded authentication plugin > %s <', entry_point.name)
|
|
||||||
break
|
|
||||||
if not app.config['FG_AUTH_BACKEND']:
|
|
||||||
logger.error('No authentication plugin configured or authentication plugin not found')
|
|
||||||
|
|
||||||
|
|
||||||
def __load_plugins(app):
|
def __load_plugins(app):
|
||||||
logger.info('Search for plugins')
|
logger.info('Search for plugins')
|
||||||
app.config['FG_PLUGINS'] = {}
|
app.config['FG_PLUGINS'] = {}
|
||||||
|
@ -50,10 +38,20 @@ def __load_plugins(app):
|
||||||
logger.debug("Found plugin: >{}<".format(entry_point.name))
|
logger.debug("Found plugin: >{}<".format(entry_point.name))
|
||||||
plugin = None
|
plugin = None
|
||||||
if config.get(entry_point.name, 'enabled', fallback=False):
|
if config.get(entry_point.name, 'enabled', fallback=False):
|
||||||
plugin = entry_point.load()()
|
plugin = entry_point.load()(config[entry_point.name] if config.has_section(entry_point.name) else {})
|
||||||
app.register_blueprint(plugin.blueprint)
|
if plugin.blueprint:
|
||||||
logger.info("Loaded plugin >{}<".format(entry_point.name))
|
app.register_blueprint(plugin.blueprint)
|
||||||
app.config["FG_PLUGINS"][entry_point.name] = plugin
|
logger.info("Load plugin >{}<".format(entry_point.name))
|
||||||
|
if isinstance(plugin, AuthPlugin):
|
||||||
|
logger.debug('Found authentication plugin: %s', entry_point.name)
|
||||||
|
if entry_point.name == config['FLASCHENGEIST']['AUTH']:
|
||||||
|
app.config['FG_AUTH_BACKEND'] = plugin
|
||||||
|
else:
|
||||||
|
del plugin
|
||||||
|
else:
|
||||||
|
app.config["FG_PLUGINS"][entry_point.name] = plugin
|
||||||
|
if 'FG_AUTH_BACKEND' not in app.config:
|
||||||
|
logger.error('No authentication plugin configured or authentication plugin not found')
|
||||||
|
|
||||||
|
|
||||||
def install_all():
|
def install_all():
|
||||||
|
@ -77,7 +75,6 @@ def create_app():
|
||||||
from .system.database import db
|
from .system.database import db
|
||||||
configure_app(app)
|
configure_app(app)
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
__load_auth(app)
|
|
||||||
__load_plugins(app)
|
__load_plugins(app)
|
||||||
|
|
||||||
@app.route("/", methods=["GET"])
|
@app.route("/", methods=["GET"])
|
||||||
|
|
|
@ -12,15 +12,21 @@ HOST =
|
||||||
PASSWORD =
|
PASSWORD =
|
||||||
DATABASE =
|
DATABASE =
|
||||||
|
|
||||||
[MAIL]
|
[auth_plain]
|
||||||
URL =
|
enabled = true
|
||||||
PORT =
|
|
||||||
USER =
|
#[mail]
|
||||||
PASSWD =
|
# enabled = true
|
||||||
MAIL =
|
# SERVER =
|
||||||
CRYPT = SSL/STARTLS
|
# PORT =
|
||||||
|
# USER =
|
||||||
|
# PASSWORD =
|
||||||
|
# MAIL =
|
||||||
|
# SSL or STARTLS
|
||||||
|
# CRYPT = SSL
|
||||||
|
|
||||||
#[auth_ldap]
|
#[auth_ldap]
|
||||||
|
# enabled = true
|
||||||
# URL =
|
# URL =
|
||||||
# PORT =
|
# PORT =
|
||||||
# BINDDN =
|
# BINDDN =
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
|
from pyhooks import precall_register
|
||||||
|
|
||||||
|
send_message_hook = precall_register("send_message")
|
||||||
|
|
||||||
|
|
||||||
class Plugin:
|
class Plugin:
|
||||||
def __init__(self, blueprint, permissions = {}):
|
def __init__(self, config=None, blueprint=None, permissions={}):
|
||||||
self.blueprint = blueprint
|
self.blueprint = blueprint
|
||||||
self.permissions = permissions
|
self.permissions = permissions
|
||||||
|
|
||||||
|
@ -10,10 +15,7 @@ class Plugin:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Auth:
|
class AuthPlugin(Plugin):
|
||||||
def configure(self, config):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def login(self, user, pw):
|
def login(self, user, pw):
|
||||||
""" Login routine, MUST BE IMPLEMENTED!
|
""" Login routine, MUST BE IMPLEMENTED!
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,12 @@ from flaschengeist.system.decorator import login_required
|
||||||
from flaschengeist.system.controller import accessTokenController, userController
|
from flaschengeist.system.controller import accessTokenController, userController
|
||||||
|
|
||||||
access_controller = LocalProxy(lambda: accessTokenController.AccessTokenController())
|
access_controller = LocalProxy(lambda: accessTokenController.AccessTokenController())
|
||||||
|
|
||||||
auth_bp = Blueprint('auth', __name__)
|
auth_bp = Blueprint('auth', __name__)
|
||||||
|
|
||||||
|
|
||||||
def register():
|
class AuthRoutePlugin(Plugin):
|
||||||
return Plugin(auth_bp)
|
def __init__(self, conf):
|
||||||
|
super().__init__(blueprint=auth_bp)
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# Routes #
|
# Routes #
|
||||||
|
@ -31,84 +31,83 @@ def register():
|
||||||
# DELETE: logout / delete token #
|
# DELETE: logout / delete token #
|
||||||
#################################################
|
#################################################
|
||||||
|
|
||||||
|
@auth_bp.route("/auth", methods=['POST'])
|
||||||
|
def _create_token():
|
||||||
|
""" Login User
|
||||||
|
|
||||||
@auth_bp.route("/auth", methods=['POST'])
|
Login in User and create an AccessToken for the User.
|
||||||
def _create_token():
|
Requires POST data {'userid': string, 'password': string}
|
||||||
""" Login User
|
Returns:
|
||||||
|
A JSON-File with user information and created token or errors
|
||||||
|
"""
|
||||||
|
logger.debug("Start log in.")
|
||||||
|
data = request.get_json()
|
||||||
|
try:
|
||||||
|
userid = data['userid']
|
||||||
|
password = data['password']
|
||||||
|
except KeyError:
|
||||||
|
raise BadRequest("Missing parameter(s)")
|
||||||
|
|
||||||
Login in User and create an AccessToken for the User.
|
logger.debug("search user {{ {} }} in database".format(userid))
|
||||||
Requires POST data {'userid': string, 'password': string}
|
user = userController.login_user(userid, password)
|
||||||
Returns:
|
if not user:
|
||||||
A JSON-File with user information and created token or errors
|
raise Unauthorized
|
||||||
"""
|
logger.debug("user is {{ {} }}".format(user))
|
||||||
logger.debug("Start log in.")
|
token = access_controller.create(user, user_agent=request.user_agent)
|
||||||
data = request.get_json()
|
logger.debug("access token is {{ {} }}".format(token))
|
||||||
try:
|
logger.info("User {{ {} }} success login.".format(userid))
|
||||||
userid = data['userid']
|
|
||||||
password = data['password']
|
|
||||||
except KeyError:
|
|
||||||
raise BadRequest("Missing parameter(s)")
|
|
||||||
|
|
||||||
logger.debug("search user {{ {} }} in database".format(userid))
|
# Lets cleanup the DB
|
||||||
user = userController.login_user(userid, password)
|
access_controller.clear_expired()
|
||||||
if not user:
|
return jsonify({"user": user, "token": token, "permissions": user.get_permissions()})
|
||||||
raise Unauthorized
|
|
||||||
logger.debug("user is {{ {} }}".format(user))
|
|
||||||
token = access_controller.create(user, user_agent=request.user_agent)
|
|
||||||
logger.debug("access token is {{ {} }}".format(token))
|
|
||||||
logger.info("User {{ {} }} success login.".format(userid))
|
|
||||||
|
|
||||||
# Lets cleanup the DB
|
|
||||||
access_controller.clear_expired()
|
|
||||||
return jsonify({"user": user, "token": token, "permissions": user.get_permissions()})
|
|
||||||
|
|
||||||
|
|
||||||
@auth_bp.route("/auth", methods=['GET'])
|
@auth_bp.route("/auth", methods=['GET'])
|
||||||
@login_required()
|
@login_required()
|
||||||
def _get_tokens(access_token, **kwargs):
|
def _get_tokens(access_token, **kwargs):
|
||||||
tokens = access_controller.get_users_tokens(access_token.user)
|
tokens = access_controller.get_users_tokens(access_token.user)
|
||||||
return jsonify(tokens)
|
return jsonify(tokens)
|
||||||
|
|
||||||
|
|
||||||
@auth_bp.route("/auth/<token>", methods=['DELETE'])
|
@auth_bp.route("/auth/<token>", methods=['DELETE'])
|
||||||
@login_required()
|
@login_required()
|
||||||
def _delete_token(token, access_token, **kwargs):
|
def _delete_token(token, access_token, **kwargs):
|
||||||
logger.debug("Try to delete access token {{ {} }}".format(token))
|
logger.debug("Try to delete access token {{ {} }}".format(token))
|
||||||
token = access_controller.get_token(token, access_token.user)
|
token = access_controller.get_token(token, access_token.user)
|
||||||
if not token:
|
if not token:
|
||||||
logger.debug("Token not found in database!")
|
logger.debug("Token not found in database!")
|
||||||
# Return 403 error, so that users can not bruteforce tokens
|
# Return 403 error, so that users can not bruteforce tokens
|
||||||
# Valid tokens from other users and invalid tokens now are looking the same
|
# Valid tokens from other users and invalid tokens now are looking the same
|
||||||
raise Forbidden
|
raise Forbidden
|
||||||
access_controller.delete_token(token)
|
access_controller.delete_token(token)
|
||||||
access_controller.clear_expired()
|
access_controller.clear_expired()
|
||||||
return jsonify({"ok": "ok"})
|
|
||||||
|
|
||||||
|
|
||||||
@auth_bp.route("/auth/<token>", methods=['GET'])
|
|
||||||
@login_required()
|
|
||||||
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:
|
|
||||||
# Return 403 error, so that users can not bruteforce tokens
|
|
||||||
# Valid tokens from other users and invalid tokens now are looking the same
|
|
||||||
raise Forbidden
|
|
||||||
return jsonify(token)
|
|
||||||
|
|
||||||
|
|
||||||
@auth_bp.route("/auth/<token>", methods=['PUT'])
|
|
||||||
@login_required()
|
|
||||||
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
|
|
||||||
# Valid tokens from other users and invalid tokens now are looking the same
|
|
||||||
raise Forbidden
|
|
||||||
try:
|
|
||||||
lifetime = request.get_json()['value']
|
|
||||||
logger.debug("set lifetime {{ {} }} to access token {{ {} }}".format(lifetime, token))
|
|
||||||
access_controller.set_lifetime(token, lifetime)
|
|
||||||
return jsonify({"ok": "ok"})
|
return jsonify({"ok": "ok"})
|
||||||
except (KeyError, TypeError):
|
|
||||||
raise BadRequest
|
|
||||||
|
@auth_bp.route("/auth/<token>", methods=['GET'])
|
||||||
|
@login_required()
|
||||||
|
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:
|
||||||
|
# Return 403 error, so that users can not bruteforce tokens
|
||||||
|
# Valid tokens from other users and invalid tokens now are looking the same
|
||||||
|
raise Forbidden
|
||||||
|
return jsonify(token)
|
||||||
|
|
||||||
|
|
||||||
|
@auth_bp.route("/auth/<token>", methods=['PUT'])
|
||||||
|
@login_required()
|
||||||
|
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
|
||||||
|
# Valid tokens from other users and invalid tokens now are looking the same
|
||||||
|
raise Forbidden
|
||||||
|
try:
|
||||||
|
lifetime = request.get_json()['value']
|
||||||
|
logger.debug("set lifetime {{ {} }} to access token {{ {} }}".format(lifetime, token))
|
||||||
|
access_controller.set_lifetime(token, lifetime)
|
||||||
|
return jsonify({"ok": "ok"})
|
||||||
|
except (KeyError, TypeError):
|
||||||
|
raise BadRequest
|
||||||
|
|
|
@ -1,29 +1,26 @@
|
||||||
from ldap3.core.exceptions import LDAPPasswordIsMandatoryError, LDAPBindError
|
import ssl
|
||||||
from ldap3.utils.hashed import hashed
|
from ldap3.utils.hashed import hashed
|
||||||
from werkzeug.exceptions import BadRequest
|
from ldap3 import SUBTREE, MODIFY_REPLACE, HASHED_SALTED_SHA512
|
||||||
|
from ldap3.core.exceptions import LDAPPasswordIsMandatoryError, LDAPBindError
|
||||||
import flaschengeist.modules as modules
|
|
||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
from flask_ldapconn import LDAPConn
|
from flask_ldapconn import LDAPConn
|
||||||
from ldap3 import SUBTREE, MODIFY_REPLACE, HASHED_SALTED_SHA512
|
from werkzeug.exceptions import BadRequest
|
||||||
import ssl
|
|
||||||
|
|
||||||
|
from flaschengeist.modules import AuthPlugin
|
||||||
from flaschengeist.system.models.user import User
|
from flaschengeist.system.models.user import User
|
||||||
from flaschengeist import logger
|
|
||||||
|
|
||||||
|
|
||||||
class AuthLDAP(modules.Auth):
|
class AuthLDAP(AuthPlugin):
|
||||||
_default = {
|
def __init__(self, config):
|
||||||
'PORT': '389',
|
super().__init__()
|
||||||
'USE_SSL': 'False'
|
|
||||||
}
|
|
||||||
ldap = None
|
|
||||||
dn = None
|
|
||||||
|
|
||||||
def configure(self, config):
|
defaults = {
|
||||||
for name in self._default:
|
'PORT': '389',
|
||||||
|
'USE_SSL': 'False'
|
||||||
|
}
|
||||||
|
for name in defaults:
|
||||||
if name not in config:
|
if name not in config:
|
||||||
config[name] = self._default[name]
|
config[name] = defaults[name]
|
||||||
|
|
||||||
app.config.update(
|
app.config.update(
|
||||||
LDAP_SERVER=config['URL'],
|
LDAP_SERVER=config['URL'],
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import smtplib
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
|
||||||
|
from flaschengeist.system.models.user import User
|
||||||
|
from flaschengeist.system.controller import userController
|
||||||
|
from flaschengeist.system.controller.messageController import Message
|
||||||
|
|
||||||
|
from . import Plugin, send_message_hook
|
||||||
|
|
||||||
|
|
||||||
|
class MailMessagePlugin(Plugin):
|
||||||
|
def __init__(self, config):
|
||||||
|
super().__init__()
|
||||||
|
self.server = config['SERVER']
|
||||||
|
self.port = config['PORT']
|
||||||
|
self.user = config['USER']
|
||||||
|
self.password = config['PASSWORD']
|
||||||
|
self.crypt = config['CRYPT']
|
||||||
|
self.mail = config['MAIL']
|
||||||
|
|
||||||
|
@send_message_hook
|
||||||
|
def send_mail(self, msg: Message):
|
||||||
|
if isinstance(msg.receiver, User):
|
||||||
|
recipients = [msg.receiver.mail]
|
||||||
|
else:
|
||||||
|
recipients = userController.get_user_by_role(msg.receiver)
|
||||||
|
|
||||||
|
mail = MIMEMultipart()
|
||||||
|
mail['From'] = self.mail
|
||||||
|
mail['To'] = ", ".join(recipients)
|
||||||
|
mail['Subject'] = msg.subject
|
||||||
|
msg.attach(msg.message)
|
||||||
|
if not self.smtp:
|
||||||
|
self.__connect()
|
||||||
|
self.smtp.sendmail(self.mail, recipients, msg.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)
|
||||||
|
self.smtp.starttls()
|
||||||
|
self.smtp.login(self.user, self.password)
|
|
@ -1,16 +1,16 @@
|
||||||
from flask import Blueprint, request, jsonify
|
from flask import Blueprint, request, jsonify
|
||||||
from werkzeug.exceptions import NotFound, BadRequest, Forbidden
|
from werkzeug.exceptions import NotFound, BadRequest
|
||||||
|
|
||||||
from flaschengeist.modules import Plugin
|
from flaschengeist.modules import Plugin
|
||||||
from flaschengeist.system.decorator import login_required
|
from flaschengeist.system.decorator import login_required
|
||||||
from flaschengeist.system.controller import roleController
|
from flaschengeist.system.controller import roleController
|
||||||
|
|
||||||
roles_bp = Blueprint("roles", __name__)
|
roles_bp = Blueprint("roles", __name__)
|
||||||
permissions = {}
|
|
||||||
|
|
||||||
|
|
||||||
def register():
|
class RolesPlugin(Plugin):
|
||||||
return Plugin(roles_bp, permissions)
|
def __init__(self, config):
|
||||||
|
super().__init__(config, roles_bp)
|
||||||
|
|
||||||
######################################################
|
######################################################
|
||||||
# Routes #
|
# Routes #
|
||||||
|
@ -23,66 +23,60 @@ def register():
|
||||||
# DELETE: remove role #
|
# DELETE: remove role #
|
||||||
######################################################
|
######################################################
|
||||||
|
|
||||||
|
@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
|
||||||
|
if "permissions" in data:
|
||||||
|
permissions = data["permissions"]
|
||||||
|
role = roleController.create_role(data["name"], permissions)
|
||||||
|
return jsonify({"ok": "ok", "id": role.id})
|
||||||
|
|
||||||
@roles_bp.route("/roles", methods=['POST'])
|
@roles_bp.route("/roles", methods=['GET'])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __add_role():
|
def list_roles(self, **kwargs):
|
||||||
data = request.get_json()
|
roles = roleController.get_roles()
|
||||||
if not data or "name" not in data:
|
return jsonify(roles)
|
||||||
raise BadRequest
|
|
||||||
if "permissions" in data:
|
|
||||||
permissions = data["permissions"]
|
|
||||||
role = roleController.create_role(data["name"], permissions)
|
|
||||||
return jsonify({"ok": "ok", "id": role.id})
|
|
||||||
|
|
||||||
|
@roles_bp.route("/roles/permissions", methods=['GET'])
|
||||||
|
@login_required()
|
||||||
|
def list_permissions(self, **kwargs):
|
||||||
|
permissions = roleController.get_permissions()
|
||||||
|
return jsonify(permissions)
|
||||||
|
|
||||||
@roles_bp.route("/roles", methods=['GET'])
|
@roles_bp.route("/roles/<rid>", methods=['GET'])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __list_roles(**kwargs):
|
def __get_role(self, rid, **kwargs):
|
||||||
roles = roleController.get_roles()
|
role = roleController.get_role(rid)
|
||||||
return jsonify(roles)
|
if role:
|
||||||
|
return jsonify({
|
||||||
|
"id": role.id,
|
||||||
@roles_bp.route("/roles/permissions", methods=['GET'])
|
"name": role,
|
||||||
@login_required()
|
"permissions": role.permissions
|
||||||
def __list_permissions(**kwargs):
|
})
|
||||||
permissions = roleController.get_permissions()
|
|
||||||
return jsonify(permissions)
|
|
||||||
|
|
||||||
|
|
||||||
@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(rid, **kwargs):
|
|
||||||
role = roleController.get_role(rid)
|
|
||||||
if not role:
|
|
||||||
raise NotFound
|
raise NotFound
|
||||||
|
|
||||||
data = request.get_json()
|
@roles_bp.route("/roles/<rid>", methods=['PUT'])
|
||||||
if 'name' in data:
|
@login_required()
|
||||||
role.name = data["name"]
|
def __edit_role(self, rid, **kwargs):
|
||||||
if "permissions" in data:
|
role = roleController.get_role(rid)
|
||||||
roleController.set_permissions(role, data["permissions"])
|
if not role:
|
||||||
roleController.update_role(role)
|
raise NotFound
|
||||||
return jsonify({"ok": "ok"})
|
|
||||||
|
|
||||||
|
data = request.get_json()
|
||||||
|
if 'name' in data:
|
||||||
|
role.name = data["name"]
|
||||||
|
if "permissions" in data:
|
||||||
|
roleController.set_permissions(role, data["permissions"])
|
||||||
|
roleController.update_role(role)
|
||||||
|
return jsonify({"ok": "ok"})
|
||||||
|
|
||||||
@roles_bp.route("/roles/<rid>", methods=['DELETE'])
|
@roles_bp.route("/roles/<rid>", methods=['DELETE'])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __delete_role(rid, **kwargs):
|
def __delete_role(self, rid, **kwargs):
|
||||||
if not roleController.delete_role(rid):
|
if not roleController.delete_role(rid):
|
||||||
raise NotFound
|
raise NotFound
|
||||||
|
|
||||||
return jsonify({"ok": "ok"})
|
return jsonify({"ok": "ok"})
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
|
from datetime import datetime, timedelta
|
||||||
from flask import Blueprint, request, jsonify
|
from flask import Blueprint, request, jsonify
|
||||||
from werkzeug.exceptions import BadRequest, NotFound
|
from werkzeug.exceptions import BadRequest, NotFound
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
from flaschengeist.modules import Plugin
|
from flaschengeist.modules import Plugin
|
||||||
from flaschengeist.system.controller import eventController
|
|
||||||
from flaschengeist.system.database import db
|
from flaschengeist.system.database import db
|
||||||
from flaschengeist.system.decorator import login_required
|
|
||||||
from flaschengeist.system.models.event import EventKind
|
from flaschengeist.system.models.event import EventKind
|
||||||
|
from flaschengeist.system.decorator import login_required
|
||||||
|
from flaschengeist.system.controller import eventController
|
||||||
|
|
||||||
schedule_bp = Blueprint("schedule", __name__, url_prefix="/schedule")
|
schedule_bp = Blueprint("schedule", __name__, url_prefix="/schedule")
|
||||||
permissions = {}
|
|
||||||
|
|
||||||
|
|
||||||
def register():
|
class SchedulePlugin(Plugin):
|
||||||
return Plugin(schedule_bp, permissions)
|
def __init__(self, config):
|
||||||
|
super().__init__(blueprint=schedule_bp)
|
||||||
|
|
||||||
####################################################################################
|
####################################################################################
|
||||||
# Routes #
|
# Routes #
|
||||||
|
@ -38,161 +37,159 @@ def register():
|
||||||
# DELETE: remove user #
|
# DELETE: remove user #
|
||||||
####################################################################################
|
####################################################################################
|
||||||
|
|
||||||
|
@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/<int:id>", methods=['GET'])
|
@schedule_bp.route("/events", methods=['GET'])
|
||||||
@login_required() # roles=['schedule_read'])
|
@schedule_bp.route("/events/<int:year>/<int:month>", methods=['GET'])
|
||||||
def __get_event(id, **kwargs):
|
@schedule_bp.route("/events/<int:year>/<int:month>/<int:day>", methods=['GET'])
|
||||||
event = eventController.get_event(id)
|
@login_required() # roles=['schedule_read'])
|
||||||
if not event:
|
def __get_events(self, year=datetime.now().year, month=datetime.now().month, day=None, **kwrags):
|
||||||
raise NotFound
|
"""Get Event objects for specified date (or month or year),
|
||||||
return jsonify(event)
|
if nothing set then events for current month are returned
|
||||||
|
|
||||||
|
Args:
|
||||||
@schedule_bp.route("/events", methods=['GET'])
|
year (int, optional): year to query, defaults to current year
|
||||||
@schedule_bp.route("/events/<int:year>/<int:month>", methods=['GET'])
|
month (int, optional): month to query (if set), defaults to current month
|
||||||
@schedule_bp.route("/events/<int:year>/<int:month>/<int:day>", methods=['GET'])
|
day (int, optional): day to query events for (if set)
|
||||||
@login_required() # roles=['schedule_read'])
|
**kwrags: contains at least access_token (see flaschengeist.decorator)
|
||||||
def __get_events(year=datetime.now().year, month=datetime.now().month, day=None, **kwrags):
|
Returns:
|
||||||
"""Get Event objects for specified date (or month or year),
|
JSON list containing events found
|
||||||
if nothing set then events for current month are returned
|
Raises:
|
||||||
|
BadRequest: If date is invalid
|
||||||
Args:
|
"""
|
||||||
year (int, optional): year to query, defaults to current year
|
try:
|
||||||
month (int, optional): month to query (if set), defaults to current month
|
begin = datetime(year=year, month=month, day=1)
|
||||||
day (int, optional): day to query events for (if set)
|
if day:
|
||||||
**kwrags: contains at least access_token (see flaschengeist.decorator)
|
begin += timedelta(days=day - 1)
|
||||||
Returns:
|
end = begin + timedelta(days=1)
|
||||||
JSON list containing events found
|
|
||||||
Raises:
|
|
||||||
BadRequest: If date is invalid
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
begin = datetime(year=year, month=month, day=1)
|
|
||||||
if day:
|
|
||||||
begin += timedelta(days=day - 1)
|
|
||||||
end = begin + timedelta(days=1)
|
|
||||||
else:
|
|
||||||
if month == 12:
|
|
||||||
end = datetime(year=year + 1, month=1, day=1)
|
|
||||||
else:
|
else:
|
||||||
end = datetime(year=year, month=month+1, day=1)
|
if month == 12:
|
||||||
|
end = datetime(year=year + 1, month=1, day=1)
|
||||||
|
else:
|
||||||
|
end = datetime(year=year, month=month+1, day=1)
|
||||||
|
|
||||||
events = eventController.get_events(begin, end)
|
events = eventController.get_events(begin, end)
|
||||||
return jsonify(events)
|
return jsonify(events)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise BadRequest("Invalid date given")
|
raise BadRequest("Invalid date given")
|
||||||
|
|
||||||
|
|
||||||
@schedule_bp.route("/eventKinds", methods=['POST'])
|
@schedule_bp.route("/eventKinds", methods=['POST'])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __new_event_kind(**kwargs):
|
def __new_event_kind(self, **kwargs):
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
if "name" not in data:
|
if "name" not in data:
|
||||||
raise BadRequest
|
raise BadRequest
|
||||||
kind = eventController.create_event_kind(data["name"])
|
kind = eventController.create_event_kind(data["name"])
|
||||||
return jsonify({"ok": "ok", "id": kind.id})
|
return jsonify({"ok": "ok", "id": kind.id})
|
||||||
|
|
||||||
|
|
||||||
@schedule_bp.route("/slotKinds", methods=["POST"])
|
@schedule_bp.route("/slotKinds", methods=["POST"])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __new_slot_kind(**kwargs):
|
def __new_slot_kind(self, **kwargs):
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
if not data or "name" not in data:
|
if not data or "name" not in data:
|
||||||
raise BadRequest
|
raise BadRequest
|
||||||
kind = eventController.create_job_kind(data["name"])
|
kind = eventController.create_job_kind(data["name"])
|
||||||
return jsonify({"ok": "ok", "id": kind.id})
|
return jsonify({"ok": "ok", "id": kind.id})
|
||||||
|
|
||||||
|
|
||||||
@schedule_bp.route("/events", methods=['POST'])
|
@schedule_bp.route("/events", methods=['POST'])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __new_event(**kwargs):
|
def __new_event(self, **kwargs):
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
event = eventController.create_event(begin=parser.isoparse(data["begin"]),
|
event = eventController.create_event(begin=parser.isoparse(data["begin"]),
|
||||||
end=parser.isoparse(data["end"]),
|
end=parser.isoparse(data["end"]),
|
||||||
description=data["description"],
|
description=data["description"],
|
||||||
kind=EventKind.query.get(data["kind"]))
|
kind=EventKind.query.get(data["kind"]))
|
||||||
return jsonify({"ok": "ok", "id": event.id})
|
return jsonify({"ok": "ok", "id": event.id})
|
||||||
|
|
||||||
|
|
||||||
@schedule_bp.route("/events/<int:id>", methods=["DELETE"])
|
@schedule_bp.route("/events/<int:id>", methods=["DELETE"])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __delete_event(id, **kwargs):
|
def __delete_event(self, id, **kwargs):
|
||||||
if not eventController.delete_event(id):
|
if not eventController.delete_event(id):
|
||||||
raise NotFound
|
raise NotFound
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return jsonify({'ok': 'ok'})
|
return jsonify({'ok': 'ok'})
|
||||||
|
|
||||||
|
|
||||||
@schedule_bp.route("/eventKinds/<int:id>", methods=["PUT"])
|
@schedule_bp.route("/eventKinds/<int:id>", methods=["PUT"])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __edit_event_kind(id, **kwargs):
|
def __edit_event_kind(self, id, **kwargs):
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
if not data or "name" not in data:
|
if not data or "name" not in data:
|
||||||
raise BadRequest
|
raise BadRequest
|
||||||
eventController.rename_event_kind(id, data["name"])
|
eventController.rename_event_kind(id, data["name"])
|
||||||
return jsonify({"ok": "ok"})
|
|
||||||
|
|
||||||
|
|
||||||
@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(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(event_id, slot_id, **kwargs):
|
|
||||||
if eventController.delete_event_slot(slot_id, event_id):
|
|
||||||
return jsonify({"ok": "ok"})
|
return jsonify({"ok": "ok"})
|
||||||
raise NotFound
|
|
||||||
|
|
||||||
|
|
||||||
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["PUT"])
|
@schedule_bp.route("/events/<int:event_id>/slots", methods=["GET"])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __update_slot(event_id, slot_id, **kwargs):
|
def __get_slots(self, event_id, **kwargs):
|
||||||
data = request.get_json()
|
event = eventController.get_event(event_id)
|
||||||
if not data:
|
if not event:
|
||||||
raise BadRequest
|
raise NotFound
|
||||||
|
return jsonify({event.slots})
|
||||||
for job in data['jobs']:
|
|
||||||
eventController.add_job(job.kind, job.user)
|
|
||||||
if eventController.delete_event_slot(slot_id, event_id):
|
|
||||||
return jsonify({"ok": "ok"})
|
|
||||||
raise NotFound
|
|
||||||
|
|
||||||
|
|
||||||
@schedule_bp.route("/events/<int:event_id>/slots", methods=["POST"])
|
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["GET"])
|
||||||
@login_required()
|
@login_required()
|
||||||
def __add_slot(event_id, **kwargs):
|
def __get_slot(self, event_id, slot_id, **kwargs):
|
||||||
event = eventController.get_event(event_id)
|
slot = eventController.get_event_slot(slot_id, event_id)
|
||||||
if not event:
|
if slot:
|
||||||
|
return jsonify(slot)
|
||||||
raise NotFound
|
raise NotFound
|
||||||
data = request.get_json()
|
|
||||||
attr = {"job_slots": []}
|
|
||||||
try:
|
|
||||||
if "start" in data:
|
|
||||||
attr["start"] = parser.isoparse(data["start"])
|
|
||||||
if "end" in data:
|
|
||||||
attr["end"] = parser.isoparse(data["end"])
|
|
||||||
for job in data["jobs"]:
|
|
||||||
attr["job_slots"].append({"needed_persons": job["needed_persons"], "kind": job["kind"]})
|
|
||||||
except KeyError:
|
|
||||||
raise BadRequest("Missing data in request")
|
|
||||||
eventController.add_slot(event, **attr)
|
|
||||||
return jsonify({"ok": "ok"})
|
|
||||||
|
|
||||||
|
|
||||||
def __edit_event():
|
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["DELETE"])
|
||||||
...
|
@login_required()
|
||||||
|
def __delete_slot(self, 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):
|
||||||
|
data = request.get_json()
|
||||||
|
if not data:
|
||||||
|
raise BadRequest
|
||||||
|
|
||||||
|
for job in data['jobs']:
|
||||||
|
eventController.add_job(job.kind, job.user)
|
||||||
|
if eventController.delete_event_slot(slot_id, event_id):
|
||||||
|
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):
|
||||||
|
event = eventController.get_event(event_id)
|
||||||
|
if not event:
|
||||||
|
raise NotFound
|
||||||
|
data = request.get_json()
|
||||||
|
attr = {"job_slots": []}
|
||||||
|
try:
|
||||||
|
if "start" in data:
|
||||||
|
attr["start"] = parser.isoparse(data["start"])
|
||||||
|
if "end" in data:
|
||||||
|
attr["end"] = parser.isoparse(data["end"])
|
||||||
|
for job in data["jobs"]:
|
||||||
|
attr["job_slots"].append({"needed_persons": job["needed_persons"], "kind": job["kind"]})
|
||||||
|
except KeyError:
|
||||||
|
raise BadRequest("Missing data in request")
|
||||||
|
eventController.add_slot(event, **attr)
|
||||||
|
return jsonify({"ok": "ok"})
|
||||||
|
|
||||||
|
|
||||||
|
def __edit_event(self):
|
||||||
|
...
|
||||||
|
|
|
@ -10,8 +10,9 @@ users_bp = Blueprint("users", __name__)
|
||||||
permissions = {'EDIT_USER': 'edit_user'}
|
permissions = {'EDIT_USER': 'edit_user'}
|
||||||
|
|
||||||
|
|
||||||
def register():
|
class UsersPlugin(Plugin):
|
||||||
return Plugin(users_bp, permissions)
|
def __init__(self, config):
|
||||||
|
super().__init__(blueprint=users_bp, permissions=permissions)
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# Routes #
|
# Routes #
|
||||||
|
@ -23,49 +24,45 @@ def register():
|
||||||
# DELETE: remove user #
|
# DELETE: remove user #
|
||||||
#################################################
|
#################################################
|
||||||
|
|
||||||
|
@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=['POST'])
|
@users_bp.route("/users", methods=['GET'])
|
||||||
def __registration():
|
@login_required()
|
||||||
logger.debug("Register new User...")
|
def __list_users(self, **kwargs):
|
||||||
return jsonify({"ok": "ok... well not implemented"})
|
logger.debug("Retrieve list of all users")
|
||||||
|
users = userController.get_users()
|
||||||
|
return jsonify(users)
|
||||||
|
|
||||||
|
@users_bp.route("/users/<uid>", methods=['GET'])
|
||||||
@users_bp.route("/users", methods=['GET'])
|
@login_required()
|
||||||
@login_required()
|
def __get_user(self, uid, **kwargs):
|
||||||
def __list_users(**kwargs):
|
logger.debug("Get information of user {{ {} }}".format(uid))
|
||||||
logger.debug("Retrieve list of all users")
|
user = userController.get_user(uid)
|
||||||
users = userController.get_users()
|
if user:
|
||||||
return jsonify(users)
|
return jsonify(user)
|
||||||
|
|
||||||
|
|
||||||
@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(uid, **kwargs):
|
|
||||||
logger.debug("Modify information of user {{ {} }}".format(uid))
|
|
||||||
user = userController.get_user(uid)
|
|
||||||
if not user:
|
|
||||||
raise NotFound
|
raise NotFound
|
||||||
|
|
||||||
if uid != kwargs['access_token'].user.uid and user.has_permissions(permissions['EDIT_USER']):
|
@users_bp.route("/users/<uid>", methods=['PUT'])
|
||||||
return Forbidden
|
@login_required()
|
||||||
|
def __edit_user(self, uid, **kwargs):
|
||||||
|
logger.debug("Modify information of user {{ {} }}".format(uid))
|
||||||
|
user = userController.get_user(uid)
|
||||||
|
if not user:
|
||||||
|
raise NotFound
|
||||||
|
|
||||||
data = request.get_json()
|
if uid != kwargs['access_token'].user.uid and user.has_permissions(permissions['EDIT_USER']):
|
||||||
if 'password' not in data:
|
return Forbidden
|
||||||
raise BadRequest("Password is missing")
|
|
||||||
for key in ["firstname", "lastname", "display_name", "mail"]:
|
data = request.get_json()
|
||||||
if key in data:
|
if 'password' not in data:
|
||||||
setattr(user, key, data[key])
|
raise BadRequest("Password is missing")
|
||||||
new_password = data['new_password'] if 'new_password' in data else None
|
for key in ["firstname", "lastname", "display_name", "mail"]:
|
||||||
userController.modify_user(user, data['password'], new_password)
|
if key in data:
|
||||||
userController.update_user(user)
|
setattr(user, key, data[key])
|
||||||
return jsonify({"ok": "ok"})
|
new_password = data['new_password'] if 'new_password' in data else None
|
||||||
|
userController.modify_user(user, data['password'], new_password)
|
||||||
|
userController.update_user(user)
|
||||||
|
return jsonify({"ok": "ok"})
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
import smtplib
|
|
||||||
from datetime import datetime
|
|
||||||
from email.mime.multipart import MIMEMultipart
|
|
||||||
from email.mime.text import MIMEText
|
|
||||||
from email.header import Header
|
|
||||||
from geruecht.logger import getDebugLogger
|
|
||||||
from . import mailConfig
|
|
||||||
|
|
||||||
debug = getDebugLogger()
|
|
||||||
|
|
||||||
class EmailController():
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
debug.info("init email controller")
|
|
||||||
self.smtpServer = mailConfig['URL']
|
|
||||||
self.port = mailConfig['port']
|
|
||||||
self.user = mailConfig['user']
|
|
||||||
self.passwd = mailConfig['passwd']
|
|
||||||
self.crypt = mailConfig['crypt']
|
|
||||||
self.email = mailConfig['email']
|
|
||||||
|
|
||||||
debug.debug("smtpServer is {{ {} }}, port is {{ {} }}, user is {{ {} }}, crypt is {{ {} }}, email is {{ {} }}".format(self.smtpServer, self.port, self.user, self.crypt, self.email))
|
|
||||||
|
|
||||||
def __connect__(self):
|
|
||||||
debug.info('connect to email server')
|
|
||||||
if self.crypt == 'SSL':
|
|
||||||
self.smtp = smtplib.SMTP_SSL(self.smtpServer, self.port)
|
|
||||||
log = self.smtp.ehlo()
|
|
||||||
debug.debug("ehlo is {{ {} }}".format(log))
|
|
||||||
if self.crypt == 'STARTTLS':
|
|
||||||
self.smtp = smtplib.SMTP(self.smtpServer, self.port)
|
|
||||||
log = self.smtp.ehlo()
|
|
||||||
debug.debug("ehlo is {{ {} }}".format(log))
|
|
||||||
log = self.smtp.starttls()
|
|
||||||
debug.debug("starttles is {{ {} }}".format(log))
|
|
||||||
log = self.smtp.login(self.user, self.passwd)
|
|
||||||
debug.debug("login is {{ {} }}".format(log))
|
|
||||||
|
|
||||||
def jobTransact(self, user, jobtransact):
|
|
||||||
debug.info("create email jobtransact {{ {} }}for user {{ {} }}".format(jobtransact, user))
|
|
||||||
date = '{}.{}.{}'.format(jobtransact['on_date']['day'], jobtransact['on_date']['month'], jobtransact['on_date']['year'])
|
|
||||||
from_user = '{} {}'.format(jobtransact['from_user']['firstname'], jobtransact['from_user']['lastname'])
|
|
||||||
job_kind = jobtransact['job_kind']
|
|
||||||
subject = 'Dienstanfrage am {}'.format(date)
|
|
||||||
text = MIMEText(
|
|
||||||
"Hallo {} {},\n"
|
|
||||||
"{} fragt, ob du am {} den Dienst {} übernehmen willst.\nBeantworte die Anfrage im Userportal von Flaschengeist.".format(user.firstname, user.lastname, from_user, date, job_kind['name']), 'plain')
|
|
||||||
debug.debug("subject is {{ {} }}, text is {{ {} }}".format(subject, text.as_string()))
|
|
||||||
return (subject, text)
|
|
||||||
|
|
||||||
def jobInvite(self, user, jobtransact):
|
|
||||||
debug.info("create email jobtransact {{ {} }}for user {{ {} }}".format(jobtransact, user))
|
|
||||||
date = '{}.{}.{}'.format(jobtransact['on_date']['day'], jobtransact['on_date']['month'], jobtransact['on_date']['year'])
|
|
||||||
from_user = '{} {}'.format(jobtransact['from_user']['firstname'], jobtransact['from_user']['lastname'])
|
|
||||||
subject = 'Diensteinladung am {}'.format(date)
|
|
||||||
text = MIMEText(
|
|
||||||
"Hallo {} {},\n"
|
|
||||||
"{} fragt, ob du am {} mit Dienst haben willst.\nBeantworte die Anfrage im Userportal von Flaschengeist.".format(user.firstname, user.lastname, from_user, date), 'plain')
|
|
||||||
debug.debug("subject is {{ {} }}, text is {{ {} }}".format(subject, text.as_string()))
|
|
||||||
return (subject, text)
|
|
||||||
|
|
||||||
def credit(self, user):
|
|
||||||
debug.info("create email credit for user {{ {} }}".format(user))
|
|
||||||
subject = Header('Gerücht, bezahle deine Schulden!', 'utf-8')
|
|
||||||
sum = user.getGeruecht(datetime.now().year).getSchulden()
|
|
||||||
if sum < 0:
|
|
||||||
type = 'Schulden'
|
|
||||||
add = 'Bezahle diese umgehend an den Finanzer.'
|
|
||||||
else:
|
|
||||||
type = 'Guthaben'
|
|
||||||
add = ''
|
|
||||||
text = MIMEText(
|
|
||||||
"Hallo {} {},\nDu hast {} im Wert von {:.2f} €. {}\n\nDiese Nachricht wurde automatisch erstellt.".format(
|
|
||||||
user.firstname, user.lastname, type, abs(sum) / 100, add), 'plain')
|
|
||||||
debug.debug("subject is {{ {} }}, text is {{ {} }}".format(subject, text.as_string()))
|
|
||||||
return (subject, text)
|
|
||||||
|
|
||||||
def passwordReset(self, user, data):
|
|
||||||
debug.info("create email passwort reset for user {{ {} }}".format(user))
|
|
||||||
subject = Header("Password vergessen")
|
|
||||||
text = MIMEText(
|
|
||||||
"Hallo {} {},\nDu hast dein Password vergessen!\nDies wurde nun mit Flaschengeist zurückgesetzt.\nDein neues Passwort lautet:\n{}\n\nBitte ändere es sofort in deinem Flaschengeistprolif in https://flaschengeist.wu5.de.".format(
|
|
||||||
user.firstname, user.lastname, data['password']
|
|
||||||
), 'plain'
|
|
||||||
)
|
|
||||||
debug.debug("subject is {{ {} }}, text is {{ {} }}".format(subject, text.as_string()))
|
|
||||||
return (subject, text)
|
|
||||||
|
|
||||||
def sendMail(self, user, type='credit', jobtransact=None, **kwargs):
|
|
||||||
debug.info("send email to user {{ {} }}".format(user))
|
|
||||||
try:
|
|
||||||
if user.mail == 'None' or not user.mail:
|
|
||||||
debug.warning("user {{ {} }} has no email-address".format(user))
|
|
||||||
raise Exception("no valid Email")
|
|
||||||
msg = MIMEMultipart()
|
|
||||||
msg['From'] = self.email
|
|
||||||
msg['To'] = user.mail
|
|
||||||
|
|
||||||
if type == 'credit':
|
|
||||||
subject, text = self.credit(user)
|
|
||||||
elif type == 'jobtransact':
|
|
||||||
subject, text = self.jobTransact(user, jobtransact)
|
|
||||||
elif type == 'jobinvite':
|
|
||||||
subject, text = self.jobInvite(user, jobtransact)
|
|
||||||
elif type == 'passwordReset':
|
|
||||||
subject, text = self.passwordReset(user, kwargs)
|
|
||||||
else:
|
|
||||||
raise Exception("Fail to send Email. No type is set. user={}, type={} , jobtransact={}".format(user, type, jobtransact))
|
|
||||||
|
|
||||||
msg['Subject'] = subject
|
|
||||||
msg.attach(text)
|
|
||||||
|
|
||||||
debug.debug("send email {{ {} }} to user {{ {} }}".format(msg.as_string(), user))
|
|
||||||
self.__connect__()
|
|
||||||
self.smtp.sendmail(self.email, user.mail, msg.as_string())
|
|
||||||
return {'error': False, 'user': {'userId': user.uid, 'firstname': user.firstname, 'lastname': user.lastname}}
|
|
||||||
except Exception:
|
|
||||||
debug.warning("exception in send email", exc_info=True)
|
|
||||||
return {'error': True, 'user': {'userId': user.uid, 'firstname': user.firstname, 'lastname': user.lastname}}
|
|
|
@ -1,10 +1,9 @@
|
||||||
from werkzeug.exceptions import BadRequest, NotFound
|
from werkzeug.exceptions import BadRequest, NotFound
|
||||||
|
|
||||||
from flaschengeist.system.models.event import EventKind, Event, EventSlot, JobSlot, JobKind
|
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
|
||||||
from flaschengeist import logger
|
from flaschengeist import logger
|
||||||
from flaschengeist.system.database import db
|
from flaschengeist.system.database import db
|
||||||
|
from flaschengeist.system.models.event import EventKind, Event, EventSlot, JobSlot, JobKind
|
||||||
|
|
||||||
|
|
||||||
def get_event(id):
|
def get_event(id):
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
from flaschengeist.system.models.user import User, Role
|
||||||
|
from pyhooks import Hook
|
||||||
|
|
||||||
|
|
||||||
|
class Message:
|
||||||
|
def __init__(self, receiver: User or Role, message: str, subject: str):
|
||||||
|
self.message = message
|
||||||
|
self.subject = subject
|
||||||
|
self.receiver = receiver
|
||||||
|
|
||||||
|
|
||||||
|
@Hook
|
||||||
|
def send_message(message: Message):
|
||||||
|
pass
|
|
@ -1,6 +1,6 @@
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
|
||||||
from flaschengeist.system.models.user import User
|
from flaschengeist.system.models.user import User, Role
|
||||||
from flaschengeist.system.database import db
|
from flaschengeist.system.database import db
|
||||||
from flaschengeist import logger
|
from flaschengeist import logger
|
||||||
|
|
||||||
|
@ -44,5 +44,9 @@ def get_users():
|
||||||
return User.query.all()
|
return User.query.all()
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_by_role(role: Role):
|
||||||
|
return User.query.join(User.roles).filter_by(role_id=role.id).all()
|
||||||
|
|
||||||
|
|
||||||
def get_user(uid):
|
def get_user(uid):
|
||||||
return User.query.filter(User.uid == uid).one_or_none()
|
return User.query.filter(User.uid == uid).one_or_none()
|
||||||
|
|
15
setup.py
15
setup.py
|
@ -18,17 +18,18 @@ setup(
|
||||||
"flask_cors",
|
"flask_cors",
|
||||||
"werkzeug",
|
"werkzeug",
|
||||||
"bjoern",
|
"bjoern",
|
||||||
"python-dateutil"
|
"python-dateutil",
|
||||||
|
"pyhooks"
|
||||||
],
|
],
|
||||||
extras_require={"ldap": ["flask_ldapconn", "ldap3"]},
|
extras_require={"ldap": ["flask_ldapconn", "ldap3"]},
|
||||||
entry_points={
|
entry_points={
|
||||||
"flaschengeist.plugin": [
|
"flaschengeist.plugin": [
|
||||||
"auth = flaschengeist.modules.auth:register",
|
"auth = flaschengeist.modules.auth:AuthRoutePlugin",
|
||||||
"users = flaschengeist.modules.users:register",
|
"users = flaschengeist.modules.users:UsersPlugin",
|
||||||
"roles = flaschengeist.modules.roles:register",
|
"roles = flaschengeist.modules.roles:RolesPlugin",
|
||||||
"schedule = flaschengeist.modules.schedule:register",
|
"schedule = flaschengeist.modules.schedule:SchedulePlugin",
|
||||||
],
|
"mail = flaschengeist.modules.message_mail:MailMessagePlugin",
|
||||||
"flaschengeist.auth": [
|
|
||||||
"auth_plain = flaschengeist.modules.auth_plain:AuthPlain",
|
"auth_plain = flaschengeist.modules.auth_plain:AuthPlain",
|
||||||
"auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP [ldap]",
|
"auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP [ldap]",
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue