@@ -296,7 +296,7 @@ class RegistrationFormFactory(object):
296296
297297 DEFAULT_FIELDS = ["email" , "name" , "username" , "password" ]
298298
299- EXTRA_FIELDS = [
299+ EXTRA_FIELDS_BASE = [
300300 "confirm_email" ,
301301 "first_name" ,
302302 "last_name" ,
@@ -344,7 +344,7 @@ def __init__(self):
344344 self .field_handlers = {}
345345 valid_fields = self .DEFAULT_FIELDS + self .EXTRA_FIELDS
346346 for field_name in valid_fields :
347- handler = getattr (self , "_add_{field_name}_field" .format (field_name = field_name ))
347+ handler = getattr (self , "_add_{field_name}_field" .format (field_name = field_name ), self . _add_custom_field )
348348 self .field_handlers [field_name ] = handler
349349
350350 field_order = configuration_helpers .get_value ('REGISTRATION_FIELD_ORDER' )
@@ -358,6 +358,20 @@ def __init__(self):
358358
359359 self .field_order = field_order
360360
361+ @property
362+ def EXTRA_FIELDS (self ):
363+ """eduNEXT: Property that returns extra fields list plus extended profile fields. This
364+ property allows us to add custom fields to the registration form using extended_profile_fields.
365+ """
366+ extended_profile_fields = getattr (settings , 'extended_profile_fields' , [])
367+
368+ # In case there's duplicates
369+ if set (self .EXTRA_FIELDS_BASE ) != set (extended_profile_fields ):
370+ difference = set (extended_profile_fields ).difference (set (self .EXTRA_FIELDS_BASE ))
371+ return self .EXTRA_FIELDS_BASE + list (difference )
372+
373+ return self .EXTRA_FIELDS_BASE + extended_profile_fields
374+
361375 def get_registration_form (self , request ):
362376 """Return a description of the registration form.
363377 This decouples clients from the API definition:
@@ -425,9 +439,12 @@ def get_registration_form(self, request):
425439 if field_name in self .DEFAULT_FIELDS :
426440 self .field_handlers [field_name ](form_desc , required = True )
427441 elif self ._is_field_visible (field_name ):
428- self .field_handlers [field_name ](
442+ field_handler = self .field_handlers [field_name ]
443+ extra_field = {"field_name" : field_name } if field_handler .__name__ == "_add_custom_field" else {}
444+ field_handler (
429445 form_desc ,
430- required = self ._is_field_required (field_name )
446+ required = self ._is_field_required (field_name ),
447+ ** extra_field
431448 )
432449
433450 return form_desc
@@ -625,6 +642,77 @@ def _add_year_of_birth_field(self, form_desc, required=True):
625642 required = required
626643 )
627644
645+ def _get_custom_field_dict (self , field_name ):
646+ """Given a field name searches for its definition dictionary.
647+ Arguments:
648+ field_name (str): the name of the field to search for.
649+ """
650+ custom_fields = getattr (settings , "EDNX_CUSTOM_REGISTRATION_FIELDS" , [])
651+ for field in custom_fields :
652+ if field .get ("name" ) == field_name :
653+ return field
654+ return {}
655+
656+ def _get_custom_html_override (self , text_field , html_piece = None ):
657+ """Overrides field with html piece.
658+ Arguments:
659+ text_field: field to override. It must have the following format:
660+ "Here {} goes the HTML piece." In `{}` will be inserted the HTML piece.
661+
662+ Keyword Arguments:
663+ html_piece: string containing HTML components to be inserted.
664+ """
665+ if html_piece :
666+ html_piece = HTML (html_piece ) if isinstance (html_piece , six .string_types ) else ""
667+ return Text (_ (text_field )).format (html_piece ) # pylint: disable=translation-of-non-string
668+ return text_field
669+
670+ def _add_custom_field (self , form_desc , required = True , ** kwargs ):
671+ """Adds custom fields to a form description.
672+ Arguments:
673+ form_desc: A form description
674+
675+ Keyword Arguments:
676+ required (bool): Whether this field is required; defaults to False
677+ field_name (str): Name used to get field information when creating it.
678+ """
679+ field_name = kwargs .pop ("field_name" )
680+ custom_field_dict = self ._get_custom_field_dict (field_name )
681+ if not custom_field_dict :
682+ msg = "Field with name {} must have a definition dictionary." .format (field_name )
683+ raise ImproperlyConfigured (msg )
684+
685+ # Check to convert options:
686+ field_options = custom_field_dict .get ("options" )
687+ if field_options :
688+ field_options = [(six .text_type (option .lower ()), option ) for option in field_options ]
689+
690+ # Set default option if applies:
691+ default_option = custom_field_dict .get ("default" )
692+ if default_option :
693+ form_desc .override_field_properties (
694+ field_name ,
695+ default = default_option
696+ )
697+
698+ field_type = custom_field_dict .get ("type" )
699+
700+ form_desc .add_field (
701+ field_name ,
702+ label = self ._get_custom_html_override (
703+ custom_field_dict .get ("label" ),
704+ custom_field_dict .get ("html_override" ),
705+ ),
706+ field_type = field_type ,
707+ options = field_options ,
708+ instructions = custom_field_dict .get ("instructions" ),
709+ placeholder = custom_field_dict .get ("placeholder" ),
710+ restrictions = custom_field_dict .get ("restrictions" ),
711+ include_default_option = bool (default_option ) or field_type == "select" ,
712+ required = required ,
713+ error_messages = custom_field_dict .get ("errorMessages" )
714+ )
715+
628716 def _add_field_with_configurable_select_options (self , field_name , field_label , form_desc , required = False ):
629717 """Add a field to a form description.
630718 If select options are given for this field, it will be a select type
@@ -637,11 +725,10 @@ def _add_field_with_configurable_select_options(self, field_name, field_label, f
637725
638726 Keyword Arguments:
639727 required (bool): Whether this field is required; defaults to False
640-
641728 """
642-
643- extra_field_options = configuration_helpers .get_value ('EXTRA_FIELD_OPTIONS' )
644- if extra_field_options is None or extra_field_options . get ( field_name ) is None :
729+ custom_options = self . _get_custom_field_dict ( field_name ). get ( "options" )
730+ extra_field_options = configuration_helpers .get_value ('EXTRA_FIELD_OPTIONS' , {} )
731+ if extra_field_options . get ( field_name ) is None and custom_options is None :
645732 field_type = "text"
646733 include_default_option = False
647734 options = None
@@ -650,7 +737,7 @@ def _add_field_with_configurable_select_options(self, field_name, field_label, f
650737 else :
651738 field_type = "select"
652739 include_default_option = True
653- field_options = extra_field_options .get (field_name )
740+ field_options = extra_field_options .get (field_name , custom_options )
654741 options = [(six .text_type (option .lower ()), option ) for option in field_options ]
655742 error_msg = ''
656743 error_msg = getattr (accounts , u'REQUIRED_FIELD_{}_SELECT_MSG' .format (field_name .upper ()))
0 commit comments