basefields.py 5.6 KB

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