basefields.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 get_label(self, user):
  22. if not self.label:
  23. raise NotImplementedError(
  24. "profile field class has to define label "
  25. "attribute or get_label(user) method"
  26. )
  27. return self.label
  28. def get_help_text(self, user):
  29. return self.help_text
  30. def get_admin_field(self, user):
  31. return None
  32. def clean_admin_form(self, form, data):
  33. return data
  34. def admin_update_profile_fields(self, user, cleaned_data):
  35. if self.readonly:
  36. return
  37. user.profile_fields[self.fieldname] = cleaned_data.get(self.fieldname)
  38. def admin_search(self, criteria, queryset):
  39. return Q(**{
  40. 'profile_fields__{}__contains'.format(self.fieldname): criteria
  41. })
  42. def get_data(self, request, user):
  43. field_data = user.profile_fields.get(self.fieldname, '')
  44. if not len(field_data):
  45. return None
  46. data = self.get_display_data(request, user, field_data)
  47. if not data:
  48. return None
  49. data['name'] = text_type(self.get_label(user))
  50. return data
  51. def get_display_data(self, request, user, data):
  52. return {
  53. 'text': data
  54. }
  55. def can_edit(self, request, user):
  56. return not self.readonly
  57. def get_edit_field_json(self, request, user):
  58. return {
  59. 'fieldname': self.fieldname,
  60. 'label': self.get_label(user),
  61. 'help_text': self.get_help_text(user),
  62. 'initial': user.profile_fields.get(self.fieldname),
  63. 'input': self.get_edit_field_input_attrs(request, user)
  64. }
  65. def get_edit_field_input_attrs(self, request, user):
  66. return {
  67. 'type': 'text',
  68. }
  69. def get_field_for_validation(self, request, user):
  70. return forms.CharField(max_length=250, required=False)
  71. def clean_field(self, request, user, data):
  72. return data
  73. class ChoiceProfileField(ProfileField):
  74. choices = None
  75. def get_choices(self, user=None):
  76. if not self.choices:
  77. raise NotImplementedError(
  78. "profile field ChoiceProfileField has to define "
  79. "choices attribute or get_choices(user) method"
  80. )
  81. return self.choices
  82. def get_admin_field(self, user):
  83. return forms.ChoiceField(
  84. label=self.get_label(user),
  85. help_text=self.get_help_text(user),
  86. initial=user.profile_fields.get(self.fieldname),
  87. choices=self.get_choices(user),
  88. disabled=self.readonly,
  89. required=False,
  90. )
  91. def admin_search(self, criteria, queryset):
  92. """custom search implementation for choice fields"""
  93. q_obj = Q(**{
  94. 'profile_fields__{}__contains'.format(self.fieldname): criteria
  95. })
  96. for key, choice in self.get_choices():
  97. if key and criteria.lower() in text_type(choice).lower():
  98. q_obj = q_obj | Q(**{
  99. 'profile_fields__{}'.format(self.fieldname): key
  100. })
  101. return q_obj
  102. def get_display_data(self, request, user, data):
  103. for key, name in self.get_choices():
  104. if key == data:
  105. return {
  106. 'text': text_type(name),
  107. }
  108. return None
  109. def get_edit_field_input_attrs(self, request, user):
  110. choices = []
  111. for key, choice in self.get_choices():
  112. choices.append({
  113. 'value': key,
  114. 'label': choice,
  115. })
  116. return {
  117. 'type': 'select',
  118. 'choices': choices,
  119. }
  120. def get_field_for_validation(self, request, user):
  121. return forms.ChoiceField(choices=self.get_choices(user), required=False)
  122. class TextProfileField(ProfileField):
  123. def get_admin_field(self, user):
  124. return forms.CharField(
  125. label=self.get_label(user),
  126. help_text=self.get_help_text(user),
  127. initial=user.profile_fields.get(self.fieldname),
  128. max_length=250,
  129. disabled=self.readonly,
  130. required=False,
  131. )
  132. class TextareaProfileField(ProfileField):
  133. def get_admin_field(self, 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_display_data(self, request, user, data):
  146. return {
  147. 'html': html.linebreaks(html.escape(data)),
  148. }
  149. def get_edit_field_input_attrs(self, request, user):
  150. return {
  151. 'type': 'texarea',
  152. }
  153. def get_field_for_validation(self, request, user):
  154. return forms.CharField(max_length=500, required=False)
  155. class UrlifiedTextareaProfileField(TextareaProfileField):
  156. def get_display_data(self, request, user, data):
  157. return {
  158. 'html': format_plaintext_for_html(data),
  159. }
  160. class SlugProfileField(ProfileField):
  161. def get_admin_field(self, user):
  162. return forms.SlugField(
  163. label=self.get_label(user),
  164. help_text=self.get_help_text(user),
  165. initial=user.profile_fields.get(self.fieldname),
  166. max_length=250,
  167. disabled=self.readonly,
  168. required=False,
  169. )
  170. def get_display_data(self, request, user, data):
  171. return {
  172. 'text': data,
  173. 'url': data,
  174. }
  175. def get_field_for_validation(self, request, user):
  176. return forms.SlugField(max_length=250, required=False)
  177. class UrlProfileField(ProfileField):
  178. def get_admin_field(self, user):
  179. return forms.URLField(
  180. label=self.get_label(user),
  181. help_text=self.get_help_text(user),
  182. initial=user.profile_fields.get(self.fieldname),
  183. max_length=250,
  184. disabled=self.readonly,
  185. required=False,
  186. )
  187. def get_display_data(self, request, user, data):
  188. return {
  189. 'text': data,
  190. 'url': data,
  191. }
  192. def get_field_for_validation(self, request, user):
  193. return forms.URLField(max_length=250, required=False)