basefields.py 5.6 KB

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