From 9e468100a034285cbb17f70a18f68c01c25a33c1 Mon Sep 17 00:00:00 2001 From: Dimitri Huisman Date: Sat, 23 Mar 2024 14:14:43 +0000 Subject: [PATCH] Fix issues with forward_destination in api and user form * form * Fixed: Internal error occurred if an empty forward_destination was entered and forward_enabled was false * Fixed: form did not check if forward_destination is empty. * Fixed: form marked forward_destination field as read-only upon reloading form upon validation error * api - create user and update/patch user * Create/Patch user did not check if forward_destination email address is valid * Create/Patch user did not check if forward_destination is present and forward_enabled is true --- core/admin/mailu/api/v1/user.py | 21 ++++++++++++++++++--- core/admin/mailu/ui/views/users.py | 10 +++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/core/admin/mailu/api/v1/user.py b/core/admin/mailu/api/v1/user.py index 9dc6279e..b0c9d4da 100644 --- a/core/admin/mailu/api/v1/user.py +++ b/core/admin/mailu/api/v1/user.py @@ -109,6 +109,10 @@ class Users(Resource): data = api.payload if not validators.email(data['email']): return { 'code': 400, 'message': f'Provided email address {data["email"]} is not a valid email address'}, 400 + if 'forward_destination' in data and len(data['forward_destination']) > 0: + for dest in data['forward_destination']: + if not validators.email(dest): + return { 'code': 400, 'message': f'Provided forward destination email address {dest} is not a valid email address'}, 400 localpart, domain_name = data['email'].lower().rsplit('@', 1) domain_found = models.Domain.query.get(domain_name) if not domain_found: @@ -118,6 +122,9 @@ class Users(Resource): email_found = models.User.query.filter_by(email=data['email']).first() if email_found: return { 'code': 409, 'message': f'User {data["email"]} already exists'}, 409 + if 'forward_enabled' in data and data['forward_enabled'] is True: + if ('forward_destination' in data and len(data['forward_destination']) == 0) or 'forward_destination' not in data: + return { 'code': 400, 'message': f'forward_destination is mandatory when forward_enabled is true'}, 400 user_new = models.User(email=data['email']) if 'raw_password' in data: @@ -140,7 +147,7 @@ class Users(Resource): user_new.allow_spoofing = data['allow_spoofing'] if 'forward_enabled' in data: user_new.forward_enabled = data['forward_enabled'] - if 'forward_destination' in data: + if 'forward_destination' in data and len(data['forward_destination']) > 0: user_new.forward_destination = data['forward_destination'] if 'forward_keep' in data: user_new.forward_keep = data['forward_keep'] @@ -203,9 +210,16 @@ class User(Resource): data = api.payload if not validators.email(email): return { 'code': 400, 'message': f'Provided email address {email} is not a valid email address'}, 400 + if 'forward_destination' in data and len(data['forward_destination']) > 0: + for dest in data['forward_destination']: + if not validators.email(dest): + return { 'code': 400, 'message': f'Provided forward destination email address {dest} is not a valid email address'}, 400 user_found = models.User.query.get(email) if not user_found: return {'code': 404, 'message': f'User {email} cannot be found'}, 404 + if ('forward_enabled' in data and data['forward_enabled'] is True) or ('forward_enabled' not in data and user_found.forward_enabled): + if ('forward_destination' in data and len(data['forward_destination']) == 0): + return { 'code': 400, 'message': f'forward_destination is mandatory when forward_enabled is true'}, 400 if 'raw_password' in data: user_found.set_password(data['raw_password']) @@ -227,8 +241,9 @@ class User(Resource): user_found.allow_spoofing = data['allow_spoofing'] if 'forward_enabled' in data: user_found.forward_enabled = data['forward_enabled'] - if 'forward_destination' in data: - user_found.forward_destination = data['forward_destination'] + if 'forward_destination' in data and len(data['forward_destination']) > 0: + if len(data['forward_destination']) == 0: + user_found.forward_destination = data['forward_destination'] if 'forward_keep' in data: user_found.forward_keep = data['forward_keep'] if 'reply_enabled' in data: diff --git a/core/admin/mailu/ui/views/users.py b/core/admin/mailu/ui/views/users.py index b0a945ad..d3816c4a 100644 --- a/core/admin/mailu/ui/views/users.py +++ b/core/admin/mailu/ui/views/users.py @@ -93,7 +93,12 @@ def user_settings(user_email): form = forms.UserSettingsForm(obj=user) utils.formatCSVField(form.forward_destination) if form.validate_on_submit(): - form.forward_destination.data = form.forward_destination.data.replace(" ","").split(",") + if form.forward_enabled.data and (form.forward_destination.data in ['', None] or type(form.forward_destination.data) is list): + flask.flash('Destination email address is missing', 'error') + user.forward_enabled = True + return flask.render_template('user/settings.html', form=form, user=user) + if form.forward_enabled.data: + form.forward_destination.data = form.forward_destination.data.replace(" ","").split(",") form.populate_obj(user) models.db.session.commit() form.forward_destination.data = ", ".join(form.forward_destination.data) @@ -101,6 +106,9 @@ def user_settings(user_email): if user_email: return flask.redirect( flask.url_for('.user_list', domain_name=user.domain.name)) + elif form.is_submitted() and not form.validate(): + user.forward_enabled = form.forward_enabled.data + return flask.render_template('user/settings.html', form=form, user=user) return flask.render_template('user/settings.html', form=form, user=user) def _process_password_change(form, user_email):