Browse Source

wip #865: some experiments with profile fiels

Rafał Pitoń 8 years ago
parent
commit
e3cada3949

+ 10 - 0
misago/templates/misago/admin/users/edit.html

@@ -116,6 +116,16 @@ class="form-horizontal"
     {% form_row form.signature_lock_staff_message label_class field_class %}
     {% form_row form.signature_lock_staff_message label_class field_class %}
 
 
   </fieldset>
   </fieldset>
+  {% for group in form.get_profile_fields_groups %}
+    <fieldset>
+      <legend>{% trans group.name %}</legend>
+
+      {% for field in group.fields %}
+        {% form_row field label_class field_class %}
+      {% endfor %}
+
+    </fieldset>
+  {% endfor %}
   <fieldset>
   <fieldset>
     <legend>{% trans "Forum options" %}</legend>
     <legend>{% trans "Forum options" %}</legend>
 
 

+ 3 - 0
misago/users/forms/admin.py

@@ -10,6 +10,7 @@ from misago.core import threadstore
 from misago.core.forms import IsoDateTimeField, YesNoSwitch
 from misago.core.forms import IsoDateTimeField, YesNoSwitch
 from misago.core.validators import validate_sluggable
 from misago.core.validators import validate_sluggable
 from misago.users.models import Ban, Rank
 from misago.users.models import Ban, Rank
+from misago.users.profilefields import profilefields
 from misago.users.validators import validate_email, validate_username
 from misago.users.validators import validate_email, validate_username
 
 
 
 
@@ -274,6 +275,8 @@ def EditUserFormFactory(FormType, instance, add_is_active_fields=False, add_admi
     if add_admin_fields:
     if add_admin_fields:
         FormType = StaffFlagUserFormFactory(FormType, instance)
         FormType = StaffFlagUserFormFactory(FormType, instance)
 
 
+    FormType = profilefields.extend_admin_form(FormType, instance)
+
     return FormType
     return FormType
 
 
 
 

+ 89 - 0
misago/users/profilefields/__init__.py

@@ -0,0 +1,89 @@
+from django.utils.module_loading import import_string
+
+from misago.conf import settings
+
+from .base import ProfileField, TextProfileField
+
+
+class ProfileFields(object):
+    def __init__(self, fields_groups):
+        self.is_loaded = False
+
+        self.fields_groups = fields_groups
+        self.fields_dict = {}
+
+    def load(self):
+        self.fields_dict = {}
+
+        for group in self.fields_groups:
+            for field_path in group['fields']:
+                field = import_string(field_path)
+                field._field_path = field_path
+                if not field.fieldname:
+                    raise ValueError(
+                        "{} profile field has to specify fieldname attribute".format(
+                            field._field_path,
+                        )
+                    )
+                if field.fieldname in self.fields_dict:
+                    raise ValueError(
+                        (
+                            '{} profile field defines fieldname "{}" '
+                            'that is already in use by the {}'
+                        ).format(
+                            field._field_path,
+                            field.fieldname,
+                            dict_from_map[field.fieldname]._field_path,
+                        )
+                    )
+                self.fields_dict[field_path] = field
+
+        self.is_loaded = True
+
+    def extend_admin_form(self, form, user):
+        class ProfileFieldsForm(form, ProfileFieldsMixin):
+            profile_fields_groups = []
+
+        new_form = ProfileFieldsForm
+
+        if not self.is_loaded:
+            self.load()
+
+        for group in self.fields_groups:
+            group_dict = {
+                'name': group['name'],
+                'fields': [],
+            }
+
+            for field_path in group['fields']:
+                old_form = new_form
+
+                field = self.fields_dict[field_path]()
+                new_form = field.extend_admin_form(old_form, user)
+
+                if new_form != old_form:
+                   group_dict['fields'].append(field.fieldname)
+
+            if group_dict['fields']:
+                new_form.profile_fields_groups.append(group_dict)
+
+        return new_form
+
+
+class ProfileFieldsMixin(object):
+    def get_profile_fields_groups(self):
+        profile_fields_groups = []
+        for group in self.profile_fields_groups:
+            fields_group = {
+                'name': group['name'],
+                'fields': [],
+            }
+
+            for fieldname in group['fields']:
+                fields_group['fields'].append(self[fieldname])
+
+            profile_fields_groups.append(fields_group)
+        return profile_fields_groups
+
+
+profilefields = ProfileFields(settings.MISAGO_PROFILE_FIELDS)

+ 51 - 0
misago/users/profilefields/base.py

@@ -0,0 +1,51 @@
+from django import forms
+
+
+class ProfileField(object):
+    """
+    Basic profile field
+    """
+    fieldname = None
+    label = None
+
+    def get_label(self, user):
+        if not self.label:
+            raise NotImplementedError(
+                "profile field class has to define label "
+                "attribute or get_label(user) method"
+            )
+        return self.label
+
+    def extend_admin_form(self, form, user):
+        return form
+
+
+class TextProfileField(ProfileField):
+    def extend_admin_form(self, form, user):
+        fieldname = self.fieldname
+
+        return type('TextProfileFieldForm', (form,), {
+            fieldname: self.get_admin_form_field(
+                user, fieldname, self.get_label(user)),
+            'clean_{}'.format(fieldname): self.get_admin_form_field_clean(
+                user, fieldname),
+        })
+
+    def get_admin_form_field(self, user, fieldname, label):
+        return forms.CharField(
+            label=label,
+            initial=user.extra.get(fieldname),
+            max_length=250,
+            required=False,
+        )
+
+    def get_admin_form_field_clean(self, user, fieldname):
+        def clean_field(self):
+            data = self.cleaned_data.get(fieldname)
+            user.extra[fieldname] = data
+            return data
+        return clean_field
+
+
+class TextareaProfileField(TextProfileField):
+    pass

+ 8 - 0
misago/users/profilefields/fullname.py

@@ -0,0 +1,8 @@
+from django.utils.translation import ugettext_lazy as _
+
+from . import TextProfileField
+
+
+class FullNameField(TextProfileField):
+    fieldname = 'fullname'
+    label = _("Full name")