forms.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. # -*- coding: utf-8 -*-
  2. """
  3. flaskbb.admin.forms
  4. ~~~~~~~~~~~~~~~~~~~~
  5. It provides the forms that are needed for the admin views.
  6. :copyright: (c) 2014 by the FlaskBB Team.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. from flask.ext.wtf import Form
  10. from wtforms import (TextField, TextAreaField, PasswordField, IntegerField,
  11. BooleanField, SelectField, DateField)
  12. from wtforms.validators import (Required, Optional, Email, regexp, Length, URL,
  13. ValidationError)
  14. from wtforms.ext.sqlalchemy.fields import (QuerySelectField,
  15. QuerySelectMultipleField)
  16. from flaskbb.utils.widgets import SelectDateWidget
  17. from flaskbb.extensions import db
  18. from flaskbb.forum.models import Forum, Category
  19. from flaskbb.user.models import User, Group
  20. USERNAME_RE = r'^[\w.+-]+$'
  21. is_username = regexp(USERNAME_RE,
  22. message=("You can only use letters, numbers or dashes"))
  23. def selectable_forums():
  24. return Forum.query.order_by(Forum.position)
  25. def selectable_categories():
  26. return Category.query.order_by(Category.position)
  27. def select_primary_group():
  28. return Group.query.filter(Group.guest == False).order_by(Group.id)
  29. class UserForm(Form):
  30. username = TextField("Username", validators=[
  31. Required(),
  32. is_username])
  33. email = TextField("E-Mail", validators=[
  34. Required(),
  35. Email(message="This email is invalid")])
  36. password = PasswordField("Password", validators=[
  37. Optional()])
  38. birthday = DateField("Birthday", format="%d %m %Y",
  39. widget=SelectDateWidget(),
  40. validators=[Optional()])
  41. gender = SelectField("Gender", default="None", choices=[
  42. ("None", ""),
  43. ("Male", "Male"),
  44. ("Female", "Female")])
  45. location = TextField("Location", validators=[
  46. Optional()])
  47. website = TextField("Website", validators=[
  48. Optional(), URL()])
  49. avatar = TextField("Avatar", validators=[
  50. Optional(), URL()])
  51. signature = TextAreaField("Forum Signature", validators=[
  52. Optional(), Length(min=0, max=250)])
  53. notes = TextAreaField("Notes", validators=[
  54. Optional(), Length(min=0, max=5000)])
  55. primary_group = QuerySelectField("Primary Group",
  56. query_factory=select_primary_group,
  57. get_label="name")
  58. secondary_groups = QuerySelectMultipleField("Secondary Groups",
  59. query_factory=select_primary_group, # TODO: Template rendering errors "NoneType is not callable" without this, figure out why.
  60. allow_blank=True,
  61. get_label="name")
  62. def validate_username(self, field):
  63. if hasattr(self, "user"):
  64. user = User.query.filter(
  65. db.and_(User.username.like(field.data),
  66. db.not_(User.id == self.user.id)
  67. )
  68. ).first()
  69. else:
  70. user = User.query.filter(User.username.like(field.data)).first()
  71. if user:
  72. raise ValidationError("This username is taken")
  73. def validate_email(self, field):
  74. if hasattr(self, "user"):
  75. user = User.query.filter(
  76. db.and_(User.email.like(field.data),
  77. db.not_(User.id == self.user.id)
  78. )
  79. ).first()
  80. else:
  81. user = User.query.filter(User.email.like(field.data)).first()
  82. if user:
  83. raise ValidationError("This email is taken")
  84. def save(self):
  85. user = User(**self.data)
  86. return user.save()
  87. class AddUserForm(UserForm):
  88. pass
  89. class EditUserForm(UserForm):
  90. def __init__(self, user, *args, **kwargs):
  91. self.user = user
  92. kwargs['obj'] = self.user
  93. super(UserForm, self).__init__(*args, **kwargs)
  94. class GroupForm(Form):
  95. name = TextField("Group Name", validators=[
  96. Required(message="Group name required")])
  97. description = TextAreaField("Description", validators=[
  98. Optional()])
  99. admin = BooleanField("Is Admin Group?",
  100. description="With this option the group has access \
  101. to the admin panel.")
  102. super_mod = BooleanField("Is Super Moderator Group?",
  103. description="Check this if the users in this \
  104. group are allowed to moderate every \
  105. forum")
  106. mod = BooleanField("Is Moderator Group?",
  107. description="Check this if the users in this group are \
  108. allowed to moderate specified forums")
  109. banned = BooleanField("Is Banned Group?",
  110. description="Only one Banned group is allowed")
  111. guest = BooleanField("Is Guest Group?",
  112. description="Only one Guest group is allowed")
  113. editpost = BooleanField("Can edit posts",
  114. description="Check this if the users in this \
  115. group can edit posts")
  116. deletepost = BooleanField("Can delete posts",
  117. description="Check this is the users in this \
  118. group can delete posts")
  119. deletetopic = BooleanField("Can delete topics",
  120. description="Check this is the users in this \
  121. group can delete topics")
  122. posttopic = BooleanField("Can create topics",
  123. description="Check this is the users in this \
  124. group can create topics")
  125. postreply = BooleanField("Can post replies",
  126. description="Check this is the users in this \
  127. group can post replies")
  128. def validate_name(self, field):
  129. if hasattr(self, "group"):
  130. group = Group.query.filter(
  131. db.and_(Group.name.like(field.data),
  132. db.not_(Group.id == self.group.id)
  133. )
  134. ).first()
  135. else:
  136. group = Group.query.filter(Group.name.like(field.data)).first()
  137. if group:
  138. raise ValidationError("This name is taken")
  139. def validate_banned(self, field):
  140. if hasattr(self, "group"):
  141. group = Group.query.filter(
  142. db.and_(Group.banned == True,
  143. db.not_(Group.id == self.group.id)
  144. )
  145. ).count()
  146. else:
  147. group = Group.query.filter_by(banned=True).count()
  148. if field.data and group > 0:
  149. raise ValidationError("There is already a Banned group")
  150. def validate_guest(self, field):
  151. if hasattr(self, "group"):
  152. group = Group.query.filter(
  153. db.and_(Group.guest == True,
  154. db.not_(Group.id == self.group.id)
  155. )
  156. ).count()
  157. else:
  158. group = Group.query.filter_by(guest=True).count()
  159. if field.data and group > 0:
  160. raise ValidationError("There is already a Guest group")
  161. def save(self):
  162. group = Group(**self.data)
  163. return group.save()
  164. class EditGroupForm(GroupForm):
  165. def __init__(self, group, *args, **kwargs):
  166. self.group = group
  167. kwargs['obj'] = self.group
  168. super(GroupForm, self).__init__(*args, **kwargs)
  169. class AddGroupForm(GroupForm):
  170. pass
  171. class ForumForm(Form):
  172. _moderators = set()
  173. title = TextField("Forum Title", validators=[
  174. Required(message="Forum title required")])
  175. description = TextAreaField("Description", validators=[
  176. Optional()],
  177. description="You can format your description with BBCode.")
  178. position = IntegerField("Position", default=1, validators=[
  179. Required(message="Forum position required")])
  180. category = QuerySelectField(
  181. "Category",
  182. query_factory=selectable_categories,
  183. allow_blank=False,
  184. get_label="title",
  185. description="The category that contains this forum."
  186. )
  187. moderators = TextField("Moderators",
  188. description="Comma seperated usernames. Leave it \
  189. blank if you do not want to set any \
  190. moderators.")
  191. locked = BooleanField("Locked?", description="Disable new posts and topics \
  192. in this forum.")
  193. def validate_moderators(self, field):
  194. if field.data:
  195. # Check if the usernames exist
  196. for moderator in field.data.split(","):
  197. user = User.query.filter_by(username=moderator).first()
  198. # Check if the user has the permissions to moderate a forum
  199. if user:
  200. if not user.get_permissions()["mod"]:
  201. raise ValidationError("The user is not in a moderators \
  202. group")
  203. else:
  204. self._moderators.add(user.id)
  205. else:
  206. raise ValidationError("User not found")
  207. field.data = self._moderators
  208. def save(self):
  209. forum = Forum(title=self.title.data,
  210. description=self.description.data,
  211. position=self.position.data)
  212. if self.moderators.data and not self.is_category.data:
  213. forum.moderators = self.moderators.data
  214. forum.category_id = self.category.data.id
  215. return forum.save()
  216. class CategoryForm(Form):
  217. title = TextField("Category title", validators=[
  218. Required(message="Category title required")])
  219. description = TextAreaField("Description", validators=[
  220. Optional()],
  221. description="You can format your description with BBCode.")
  222. position = IntegerField("Position", default=1, validators=[
  223. Required(message="Category position required")])
  224. def save(self):
  225. category = Category(**self.data)
  226. return category.save()