basefields.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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. return Q(**{
  67. 'profile_fields__{}__contains'.format(self.fieldname): criteria
  68. })
  69. class ChoiceProfileField(ProfileField):
  70. choices = None
  71. def get_choices(self, user=None):
  72. if not self.choices:
  73. raise NotImplementedError(
  74. "profile field ChoiceProfileField has to define "
  75. "choices attribute or get_choices(user) method"
  76. )
  77. return self.choices
  78. def get_form_field(self, request, user):
  79. return forms.ChoiceField(
  80. label=self.get_label(user),
  81. help_text=self.get_help_text(user),
  82. initial=user.profile_fields.get(self.fieldname),
  83. choices=self.get_choices(user),
  84. disabled=self.readonly,
  85. required=False,
  86. )
  87. def get_input_json(self, request, user):
  88. choices = []
  89. for key, choice in self.get_choices():
  90. choices.append({
  91. 'value': key,
  92. 'label': choice,
  93. })
  94. return {
  95. 'type': 'select',
  96. 'choices': choices,
  97. }
  98. def get_value_display_data(self, request, user, value):
  99. for key, name in self.get_choices():
  100. if key == value:
  101. return {
  102. 'text': text_type(name),
  103. }
  104. return None
  105. def search_users(self, criteria, queryset):
  106. """custom search implementation for choice fields"""
  107. q_obj = Q(**{
  108. 'profile_fields__{}__contains'.format(self.fieldname): criteria
  109. })
  110. for key, choice in self.get_choices():
  111. if key and criteria.lower() in text_type(choice).lower():
  112. q_obj = q_obj | Q(**{
  113. 'profile_fields__{}'.format(self.fieldname): key
  114. })
  115. return q_obj
  116. class TextProfileField(ProfileField):
  117. def get_form_field(self, request, user):
  118. return forms.CharField(
  119. label=self.get_label(user),
  120. help_text=self.get_help_text(user),
  121. initial=user.profile_fields.get(self.fieldname),
  122. max_length=250,
  123. disabled=self.readonly,
  124. required=False,
  125. )
  126. def get_input_json(self, request, user):
  127. return {
  128. 'type': 'text',
  129. }
  130. class TextareaProfileField(ProfileField):
  131. def get_form_field(self, request, user):
  132. return forms.CharField(
  133. label=self.get_label(user),
  134. help_text=self.get_help_text(user),
  135. initial=user.profile_fields.get(self.fieldname),
  136. max_length=500,
  137. widget=forms.Textarea(
  138. attrs={'rows': 4},
  139. ),
  140. disabled=self.readonly,
  141. required=False,
  142. )
  143. def get_input_json(self, request, user):
  144. return {
  145. 'type': 'textarea',
  146. }
  147. def get_value_display_data(self, request, user, value):
  148. return {
  149. 'html': html.linebreaks(html.escape(value)),
  150. }
  151. class UrlifiedTextareaProfileField(TextareaProfileField):
  152. def get_value_display_data(self, request, user, value):
  153. return {
  154. 'html': format_plaintext_for_html(value),
  155. }
  156. class UrlProfileField(TextProfileField):
  157. def get_form_field(self, request, user):
  158. return forms.URLField(
  159. label=self.get_label(user),
  160. help_text=self.get_help_text(user),
  161. initial=user.profile_fields.get(self.fieldname),
  162. max_length=250,
  163. disabled=self.readonly,
  164. required=False,
  165. )
  166. def get_value_display_data(self, request, user, value):
  167. return {
  168. 'text': value,
  169. 'url': value,
  170. }