basefields.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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.update({
  50. 'fieldname': self.fieldname,
  51. 'name': text_type(self.get_label(user)),
  52. })
  53. return data
  54. def get_display_data(self, request, user, data):
  55. return {
  56. 'text': data
  57. }
  58. def can_edit(self, request, user):
  59. return not self.readonly
  60. def get_edit_field_json(self, request, user):
  61. return {
  62. 'fieldname': self.fieldname,
  63. 'label': self.get_label(user),
  64. 'help_text': self.get_help_text(user),
  65. 'initial': user.profile_fields.get(self.fieldname, ''),
  66. 'input': self.get_edit_field_input_attrs(request, user)
  67. }
  68. def get_edit_field_input_attrs(self, request, user):
  69. return {
  70. 'type': 'text',
  71. }
  72. def get_field_for_validation(self, request, user):
  73. return forms.CharField(max_length=250, required=False)
  74. def clean_field(self, request, user, data):
  75. return data
  76. class ChoiceProfileField(ProfileField):
  77. choices = None
  78. def get_choices(self, user=None):
  79. if not self.choices:
  80. raise NotImplementedError(
  81. "profile field ChoiceProfileField has to define "
  82. "choices attribute or get_choices(user) method"
  83. )
  84. return self.choices
  85. def get_admin_field(self, user):
  86. return forms.ChoiceField(
  87. label=self.get_label(user),
  88. help_text=self.get_help_text(user),
  89. initial=user.profile_fields.get(self.fieldname),
  90. choices=self.get_choices(user),
  91. disabled=self.readonly,
  92. required=False,
  93. )
  94. def admin_search(self, criteria, queryset):
  95. """custom search implementation for choice fields"""
  96. q_obj = Q(**{
  97. 'profile_fields__{}__contains'.format(self.fieldname): criteria
  98. })
  99. for key, choice in self.get_choices():
  100. if key and criteria.lower() in text_type(choice).lower():
  101. q_obj = q_obj | Q(**{
  102. 'profile_fields__{}'.format(self.fieldname): key
  103. })
  104. return q_obj
  105. def get_display_data(self, request, user, data):
  106. for key, name in self.get_choices():
  107. if key == data:
  108. return {
  109. 'text': text_type(name),
  110. }
  111. return None
  112. def get_edit_field_input_attrs(self, request, user):
  113. choices = []
  114. for key, choice in self.get_choices():
  115. choices.append({
  116. 'value': key,
  117. 'label': choice,
  118. })
  119. return {
  120. 'type': 'select',
  121. 'choices': choices,
  122. }
  123. def get_field_for_validation(self, request, user):
  124. return forms.ChoiceField(choices=self.get_choices(user), required=False)
  125. class TextProfileField(ProfileField):
  126. def get_admin_field(self, user):
  127. return forms.CharField(
  128. label=self.get_label(user),
  129. help_text=self.get_help_text(user),
  130. initial=user.profile_fields.get(self.fieldname),
  131. max_length=250,
  132. disabled=self.readonly,
  133. required=False,
  134. )
  135. class TextareaProfileField(ProfileField):
  136. def get_admin_field(self, user):
  137. return forms.CharField(
  138. label=self.get_label(user),
  139. help_text=self.get_help_text(user),
  140. initial=user.profile_fields.get(self.fieldname),
  141. max_length=500,
  142. widget=forms.Textarea(
  143. attrs={'rows': 4},
  144. ),
  145. disabled=self.readonly,
  146. required=False,
  147. )
  148. def get_display_data(self, request, user, data):
  149. return {
  150. 'html': html.linebreaks(html.escape(data)),
  151. }
  152. def get_edit_field_input_attrs(self, request, user):
  153. return {
  154. 'type': 'textarea',
  155. }
  156. def get_field_for_validation(self, request, user):
  157. return forms.CharField(max_length=500, required=False)
  158. class UrlifiedTextareaProfileField(TextareaProfileField):
  159. def get_display_data(self, request, user, data):
  160. return {
  161. 'html': format_plaintext_for_html(data),
  162. }
  163. class SlugProfileField(ProfileField):
  164. def get_admin_field(self, user):
  165. return forms.SlugField(
  166. label=self.get_label(user),
  167. help_text=self.get_help_text(user),
  168. initial=user.profile_fields.get(self.fieldname),
  169. max_length=250,
  170. disabled=self.readonly,
  171. required=False,
  172. )
  173. def get_display_data(self, request, user, data):
  174. return {
  175. 'text': data,
  176. 'url': data,
  177. }
  178. def get_field_for_validation(self, request, user):
  179. return forms.SlugField(max_length=250, required=False)
  180. class UrlProfileField(ProfileField):
  181. def get_admin_field(self, user):
  182. return forms.URLField(
  183. label=self.get_label(user),
  184. help_text=self.get_help_text(user),
  185. initial=user.profile_fields.get(self.fieldname),
  186. max_length=250,
  187. disabled=self.readonly,
  188. required=False,
  189. )
  190. def get_display_data(self, request, user, data):
  191. return {
  192. 'text': data,
  193. 'url': data,
  194. }
  195. def get_field_for_validation(self, request, user):
  196. return forms.URLField(max_length=250, required=False)