__init__.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. from __future__ import unicode_literals
  2. import copy
  3. import logging
  4. from django.core.exceptions import ValidationError
  5. from django.urls import reverse
  6. from django.utils.module_loading import import_string
  7. from django.utils.translation import ugettext as _
  8. from misago.conf import settings
  9. from .basefields import *
  10. from .serializers import serialize_profilefields_data
  11. logger = logging.getLogger('misago.users.ProfileFields')
  12. class ProfileFields(object):
  13. def __init__(self, fields_groups):
  14. self.is_loaded = False
  15. self.fields_groups = fields_groups
  16. self.fields_dict = {}
  17. def load(self):
  18. self.fields_dict = {}
  19. fieldnames = {}
  20. for group in self.fields_groups:
  21. for field_path in group['fields']:
  22. field = import_string(field_path)
  23. field._field_path = field_path
  24. if field_path in self.fields_dict:
  25. raise ValueError(
  26. "{} profile field has been specified twice".format(field._field_path)
  27. )
  28. if not getattr(field, 'fieldname', None):
  29. raise ValueError(
  30. "{} profile field has to specify fieldname attribute".format(
  31. field._field_path,
  32. )
  33. )
  34. if field.fieldname in fieldnames:
  35. raise ValueError(
  36. (
  37. '{} profile field defines fieldname "{}" '
  38. 'that is already in use by the {}'
  39. ).format(
  40. field._field_path,
  41. field.fieldname,
  42. fieldnames[field.fieldname],
  43. )
  44. )
  45. fieldnames[field.fieldname] = field_path
  46. self.fields_dict[field_path] = field()
  47. self.is_loaded = True
  48. def get_fields(self):
  49. if not self.is_loaded:
  50. self.load()
  51. return self.fields_dict.values()
  52. def get_fields_groups(self):
  53. if not self.is_loaded:
  54. self.load()
  55. groups = []
  56. for group in self.fields_groups:
  57. group_dict = {
  58. 'name': _(group['name']),
  59. 'fields': [],
  60. }
  61. for field_path in group['fields']:
  62. field = self.fields_dict[field_path]
  63. group_dict['fields'].append(field)
  64. if group_dict['fields']:
  65. groups.append(group_dict)
  66. return groups
  67. def add_fields_to_form(self, request, user, form):
  68. if not self.is_loaded:
  69. self.load()
  70. form._profile_fields = []
  71. for field in self.get_fields():
  72. if not field.is_editable(request, user):
  73. continue
  74. form._profile_fields.append(field.fieldname)
  75. form.fields[field.fieldname] = field.get_form_field(request, user)
  76. def add_fields_to_admin_form(self, request, user, form):
  77. self.add_fields_to_form(request, user, form)
  78. form._profile_fields_groups = []
  79. for group in self.fields_groups:
  80. group_dict = {
  81. 'name': _(group['name']),
  82. 'fields': [],
  83. }
  84. for field_path in group['fields']:
  85. field = self.fields_dict[field_path]
  86. if field.fieldname in form._profile_fields:
  87. group_dict['fields'].append(field.fieldname)
  88. if group_dict['fields']:
  89. form._profile_fields_groups.append(group_dict)
  90. def clean_form(self, request, user, form, cleaned_data):
  91. for field in self.get_fields():
  92. if field.fieldname not in cleaned_data:
  93. continue
  94. try:
  95. cleaned_data[field.fieldname] = field.clean(
  96. request, user, cleaned_data[field.fieldname])
  97. except ValidationError as e:
  98. form.add_error(field.fieldname, e)
  99. return cleaned_data
  100. def update_user_profile_fields(self, request, user, form):
  101. old_fields = copy.copy(user.profile_fields or {})
  102. new_fields = {}
  103. for fieldname in form._profile_fields:
  104. if fieldname in form.cleaned_data:
  105. new_fields[fieldname] = form.cleaned_data[fieldname]
  106. user.profile_fields = new_fields
  107. if old_fields != new_fields:
  108. if request.user == user:
  109. log_message = "{} edited own profile fields".format(user.username)
  110. else:
  111. log_message = "{} edited {}'s (#{}) profile fields".format(request.user, user.username, user.pk)
  112. logger.info(
  113. log_message,
  114. extra={
  115. 'old_fields': old_fields,
  116. 'new_fields': new_fields,
  117. 'tags': {
  118. 'absolute_url': request.build_absolute_uri(
  119. reverse(
  120. 'misago:user-details',
  121. kwargs={
  122. 'slug': user.slug,
  123. 'pk': user.pk,
  124. },
  125. )
  126. ),
  127. },
  128. }
  129. )
  130. def search_users(self, criteria, queryset):
  131. if not self.is_loaded:
  132. self.load()
  133. q_obj = None
  134. for field in self.fields_dict.values():
  135. q = field.search_users(criteria)
  136. if q:
  137. if q_obj:
  138. q_obj = q_obj | q
  139. else:
  140. q_obj = q
  141. if q_obj:
  142. return queryset.filter(q_obj)
  143. return queryset
  144. profilefields = ProfileFields(settings.MISAGO_PROFILE_FIELDS)