3434
3535from werkzeug .utils import secure_filename
3636
37- from flask import request , url_for , flash , Response , make_response , redirect , abort , jsonify
37+ from flask import request , url_for , flash , Response , make_response , redirect , abort , jsonify , session
3838from flask import current_app as app
3939from flask import g as flaskg
4040from flask_babel import format_datetime
9595from moin .constants .itemtypes import ITEMTYPE_DEFAULT , ITEMTYPE_TICKET
9696from moin .constants .contenttypes import * # noqa
9797from moin .constants .rights import SUPERUSER
98+ from moin .constants .misc import FLASH_REPEAT
9899from moin .utils import crypto , rev_navigation , close_file , show_time , utcfromtimestamp
99100from moin .utils .crypto import make_uuid , hash_hexdigest
100101from moin .utils .interwiki import url_for_item , split_fqname , CompositeName
@@ -2366,12 +2367,36 @@ def usersettings():
23662367 # TODO: maybe "is_xhr = request.method == 'POST'" would work
23672368 is_xhr = request .accept_mimetypes .best in ("application/json" , "text/javascript" )
23682369
2370+ class ValidUserSettingsPersonal (Validator ):
2371+ """Validator for settings personal change, name, display-name"""
2372+
2373+ def validate (self , element , state ):
2374+ invalid_id_in_use_msg = L_ ("This name is already in use: " )
2375+ invalid_character_msg = L_ ("The Display-Name contains invalid characters: " )
2376+ invalid_character_message = L_ ("The Username contains invalid characters: " )
2377+ errors = []
2378+ if set (form ["name" ].value ) != set (flaskg .user .name ):
2379+ new_names = set (form ["name" ].value ) - set (flaskg .user .name )
2380+ for name in new_names :
2381+ if user .search_users (** {NAME_EXACT : name }):
2382+ # duplicate name
2383+ errors .append (invalid_id_in_use_msg + name )
2384+ if not user .normalizeName (name ) == name :
2385+ errors .append (invalid_character_message + name )
2386+ display_name = form [DISPLAY_NAME ].value
2387+ if display_name :
2388+ if not user .normalizeName (display_name ) == display_name :
2389+ errors .append (invalid_character_msg + display_name )
2390+ if errors :
2391+ return self .note_error (element , state , message = ", " .join (errors ))
2392+ return True
2393+
23692394 # these forms can't be global because we need app object, which is only available within a request:
23702395 class UserSettingsPersonalForm (Form ):
23712396 form_name = "usersettings_personal"
23722397 name = Names .using (label = L_ ("Usernames" )).with_properties (placeholder = L_ ("The login usernames you want to use" ))
23732398 display_name = OptionalText .using (label = L_ ("Display-Name" )).with_properties (
2374- placeholder = L_ ("Your display name (informational )" )
2399+ placeholder = L_ ("Your display name (optional, rarely used )" )
23752400 )
23762401 # _timezones_keys = sorted(Locale('en').time_zones.keys())
23772402 _timezones_keys = [str (tz ) for tz in pytz .common_timezones ]
@@ -2382,6 +2407,8 @@ class UserSettingsPersonalForm(Form):
23822407 )
23832408 submit_label = L_ ("Save" )
23842409
2410+ validators = [ValidUserSettingsPersonal ()]
2411+
23852412 class UserSettingsUIForm (Form ):
23862413 form_name = "usersettings_ui"
23872414 theme_name = RadioChoice .using (label = L_ ("Theme name" )).with_properties (
@@ -2437,24 +2464,6 @@ class UserSettingsUIForm(Form):
24372464 flaskg .user .save ()
24382465 response ["flash" ].append ((_ ("Your password has been changed." ), "info" ))
24392466 else :
2440- if part == "personal" :
2441- if set (form ["name" ].value ) != set (flaskg .user .name ):
2442- new_names = set (form ["name" ].value ) - set (flaskg .user .name )
2443- for name in new_names :
2444- if user .search_users (** {NAME_EXACT : name }):
2445- # duplicate name
2446- response ["flash" ].append (
2447- (_ ("The username '{name}' is already in use." ).format (name = name ), "error" )
2448- )
2449- success = False
2450- if not user .normalizeName (name ) == name :
2451- response ["flash" ].append (
2452- (
2453- _ ("The username '{name}' contains invalid characters" ).format (name = name ),
2454- "error" ,
2455- )
2456- )
2457- success = False
24582467 if part == "notification" :
24592468 if (
24602469 form ["email" ].value != flaskg .user .email
@@ -2513,9 +2522,12 @@ class UserSettingsUIForm(Form):
25132522 else :
25142523 # validation failed
25152524 response ["flash" ].append ((_ ("Nothing saved." ), "error" ))
2525+
25162526 if not response ["flash" ]:
25172527 # if no flash message was added until here, we add a generic success message
2518- response ["flash" ].append ((_ ("Your changes have been saved." ), "info" ))
2528+ msg = _ ("Your changes have been saved." )
2529+ response ["flash" ].append ((msg , "info" ))
2530+ repeat_flash_msg (msg , "info" )
25192531
25202532 if response ["redirect" ] is not None or not is_xhr :
25212533 # if we redirect or it is no XHR request, we just flash() the messages normally
@@ -2544,6 +2556,15 @@ class UserSettingsUIForm(Form):
25442556 return render_template ("usersettings.html" , title_name = title_name , form_objs = forms )
25452557
25462558
2559+ def repeat_flash_msg (msg , level ):
2560+ """
2561+ Add a flash message to flask session. The message will be re-flashed by the next transaction.
2562+ """
2563+ if FLASH_REPEAT not in session :
2564+ session [FLASH_REPEAT ] = []
2565+ session [FLASH_REPEAT ].append ((msg , level ))
2566+
2567+
25472568@frontend .route ("/+bookmark" )
25482569def bookmark ():
25492570 """set bookmark (in time) for recent changes (or delete them)"""
0 commit comments