basefields.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. from django import forms
  2. from django.db.models import Q
  3. from django.utils import html
  4. from django.utils.six import text_type
  5. from misago.core.utils import format_plaintext_for_html
  6. __all__ = [
  7. 'ProfileField',
  8. 'TextProfileField',
  9. 'UrlProfileField',
  10. 'TextareaProfileField',
  11. 'ChoiceProfileField',
  12. ]
  13. class ProfileField(object):
  14. """
  15. Basic profile field
  16. """
  17. fieldname = None
  18. label = None
  19. help_text = None
  20. readonly = False
  21. def is_editable(self, request, user):
  22. return not self.readonly
  23. def get_label(self, user):
  24. if not self.label:
  25. raise NotImplementedError(
  26. "profile field class has to define label "
  27. "attribute or get_label(user) method"
  28. )
  29. return self.label
  30. def get_help_text(self, user):
  31. return self.help_text
  32. def get_form_field(self, request, user):
  33. return None
  34. def get_form_field_json(self, request, user):
  35. input_json = self.get_input_json(request, user)
  36. if not input_json:
  37. return None
  38. return {
  39. 'fieldname': self.fieldname,
  40. 'label': self.get_label(user),
  41. 'help_text': self.get_help_text(user),
  42. 'initial': user.profile_fields.get(self.fieldname, ''),
  43. 'input': input_json,
  44. }
  45. def get_input_json(self, request, user):
  46. return None
  47. def clean(self, request, user, data):
  48. return data
  49. def get_display_data(self, request, user):
  50. value = user.profile_fields.get(self.fieldname, '')
  51. if not self.readonly and not len(value):
  52. return None
  53. data = self.get_value_display_data(request, user, value)
  54. if not data:
  55. return None
  56. data.update({
  57. 'fieldname': self.fieldname,
  58. 'name': text_type(self.get_label(user)),
  59. })
  60. return data
  61. def get_value_display_data(self, request, user, value):
  62. return {
  63. 'text': value
  64. }
  65. def search_users(self, criteria, queryset):
  66. if self.readonly:
  67. return None
  68. return Q(**{
  69. 'profile_fields__{}__contains'.format(self.fieldname): criteria
  70. })
  71. class ChoiceProfileField(ProfileField):
  72. choices = None
  73. def get_choices(self, user=None):
  74. if not self.choices:
  75. raise NotImplementedError(
  76. "profile field ChoiceProfileField has to define "
  77. "choices attribute or get_choices(user) method"
  78. )
  79. return self.choices
  80. def get_form_field(self, request, user):
  81. return forms.ChoiceField(
  82. label=self.get_label(user),
  83. help_text=self.get_help_text(user),
  84. initial=user.profile_fields.get(self.fieldname),
  85. choices=self.get_choices(user),
  86. disabled=self.readonly,
  87. required=False,
  88. )
  89. def get_input_json(self, request, user):
  90. choices = []
  91. for key, choice in self.get_choices():
  92. choices.append({
  93. 'value': key,
  94. 'label': choice,
  95. })
  96. return {
  97. 'type': 'select',
  98. 'choices': choices,
  99. }
  100. def get_value_display_data(self, request, user, value):
  101. for key, name in self.get_choices():
  102. if key == value:
  103. return {
  104. 'text': text_type(name),
  105. }
  106. return None
  107. def search_users(self, criteria, queryset):
  108. """custom search implementation for choice fields"""
  109. q_obj = Q(**{
  110. 'profile_fields__{}__contains'.format(self.fieldname): criteria
  111. })
  112. for key, choice in self.get_choices():
  113. if key and criteria.lower() in text_type(choice).lower():
  114. q_obj = q_obj | Q(**{
  115. 'profile_fields__{}'.format(self.fieldname): key
  116. })
  117. return q_obj
  118. class TextProfileField(ProfileField):
  119. def get_form_field(self, request, user):
  120. return forms.CharField(
  121. label=self.get_label(user),
  122. help_text=self.get_help_text(user),
  123. initial=user.profile_fields.get(self.fieldname),
  124. max_length=250,
  125. disabled=self.readonly,
  126. required=False,
  127. )
  128. def get_input_json(self, request, user):
  129. return {
  130. 'type': 'text',
  131. }
  132. class TextareaProfileField(ProfileField):
  133. def get_form_field(self, request, user):
  134. return forms.CharField(
  135. label=self.get_label(user),
  136. help_text=self.get_help_text(user),
  137. initial=user.profile_fields.get(self.fieldname),
  138. max_length=500,
  139. widget=forms.Textarea(
  140. attrs={'rows': 4},
  141. ),
  142. disabled=self.readonly,
  143. required=False,
  144. )
  145. def get_input_json(self, request, user):
  146. return {
  147. 'type': 'textarea',
  148. }
  149. def get_value_display_data(self, request, user, value):
  150. return {
  151. 'html': html.linebreaks(html.escape(value)),
  152. }
  153. class UrlifiedTextareaProfileField(TextareaProfileField):
  154. def get_value_display_data(self, request, user, value):
  155. return {
  156. 'html': format_plaintext_for_html(value),
  157. }
  158. class UrlProfileField(TextProfileField):
  159. def get_form_field(self, request, user):
  160. return forms.URLField(
  161. label=self.get_label(user),
  162. help_text=self.get_help_text(user),
  163. initial=user.profile_fields.get(self.fieldname),
  164. max_length=250,
  165. disabled=self.readonly,
  166. required=False,
  167. )
  168. def get_value_display_data(self, request, user, value):
  169. return {
  170. 'text': value,
  171. 'url': value,
  172. }