118 lines
4.2 KiB
Python
118 lines
4.2 KiB
Python
import ldap
|
|
import flask
|
|
import flask_wtf
|
|
|
|
from webapp import app, context, config, validation, avatar
|
|
from webapp.auth import login_required
|
|
|
|
bp = flask.Blueprint('vcard', __name__)
|
|
|
|
perm_errors = {
|
|
'add': 'You cannot add this attribute!',
|
|
'mod': 'You cannot change this attribute!',
|
|
'del': 'You cannot delete this attribute!',
|
|
}
|
|
|
|
templates = {
|
|
'add': 'ops/add.html',
|
|
'mod': 'ops/mod.html',
|
|
'del': 'ops/del.html',
|
|
}
|
|
|
|
def attr_op(op, attrName, uid = None, success_redirect='/vcard',
|
|
fatal_redirect='/vcard'):
|
|
try:
|
|
attr, old_value = None, None
|
|
if uid:
|
|
attr = context.get_profile()[uid]
|
|
attrName = attr.name
|
|
old_value = str(attr)
|
|
form = DelForm() if op == 'del' else app.forms[attrName](value=old_value)
|
|
form.attr_data = attr
|
|
if attrName not in config.can[op]:
|
|
flask.flash(perm_errors[op], 'danger')
|
|
return flask.redirect(fatal_redirect)
|
|
if form.validate_on_submit():
|
|
if op in ['add', 'mod']:
|
|
new_value = form.value.data
|
|
admin = attrName in config.admin_required
|
|
conn = context.get_admin_connection() if admin else context.get_connection()
|
|
dn = context.get_dn()
|
|
|
|
# Most fields should be modified by remove/add.
|
|
if op == 'mod' and attrName not in ['commonname']:
|
|
op = 'modreadd'
|
|
|
|
if attrName == 'jpegphoto':
|
|
# Temporary workaround: deleting jpegPhoto doesn't work, set to empty instead
|
|
if op == 'del':
|
|
op = 'mod'
|
|
new_value = ''
|
|
else:
|
|
try:
|
|
op = 'mod'
|
|
processed_avatar = avatar.process_upload(new_value.read())
|
|
new_value = processed_avatar
|
|
print(f'Uplading avatar (size: {len(processed_avatar)}) for {dn}')
|
|
except Exception as e:
|
|
flask.flash('Could not process avatar: {}'.format(e), 'danger')
|
|
return flask.redirect(fatal_redirect)
|
|
|
|
def to_ldap(s):
|
|
if isinstance(s, bytes):
|
|
return s
|
|
return s.encode('utf-8')
|
|
|
|
if op in ['del', 'modreadd']:
|
|
conn.modify_s(dn, [(ldap.MOD_DELETE, attrName, to_ldap(old_value))])
|
|
if op in ['add', 'modreadd']:
|
|
conn.modify_s(dn, [(ldap.MOD_ADD, attrName, to_ldap(new_value))])
|
|
|
|
if op in ['mod']:
|
|
conn.modify_s(dn, [(ldap.MOD_REPLACE, attrName, to_ldap(new_value))])
|
|
|
|
context.refresh_profile()
|
|
return flask.redirect(success_redirect)
|
|
if form.is_submitted():
|
|
for field, errors in form.errors.items():
|
|
for error in errors:
|
|
flask.flash("Error in the {} field - {}".format(
|
|
getattr(form, field).label.text,
|
|
error
|
|
), 'danger')
|
|
return flask.redirect(success_redirect)
|
|
status = 400 if form.is_submitted() else 200
|
|
return flask.make_response(flask.render_template(templates[op], fatal_redirect=fatal_redirect,
|
|
attr_op=op, form=form, attr_name=attrName, uid=uid), status)
|
|
except ldap.LDAPError as e:
|
|
print('LDAP error:', e)
|
|
flask.flash('Could not modify profile', 'danger')
|
|
return flask.redirect(fatal_redirect)
|
|
|
|
class DelForm(flask_wtf.FlaskForm):
|
|
pass
|
|
|
|
@bp.route('/vcard', methods=['GET'])
|
|
@login_required
|
|
def vcard():
|
|
data = {}
|
|
for v in context.get_profile().values():
|
|
data.setdefault(v.name, []).append(v)
|
|
return flask.render_template('vcard.html', can_add=config.can['add'],
|
|
can_modify=config.can['mod'], can_delete=config.can['del'], profile=data)
|
|
|
|
@bp.route('/vcard/add/<attrName>', methods=['GET', 'POST'])
|
|
@login_required
|
|
def add_attr(attrName):
|
|
return attr_op('add', attrName)
|
|
|
|
@bp.route('/vcard/delete/<uid>', methods=['GET', 'POST'])
|
|
@login_required
|
|
def del_attr(uid):
|
|
return attr_op('del', None, uid)
|
|
|
|
@bp.route('/vcard/modify/<uid>', methods=['GET', 'POST'])
|
|
@login_required
|
|
def mod_attr(uid):
|
|
return attr_op('mod', None, uid)
|