PageRenderTime 30ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/crgappspanel/forms.py

https://github.com/ron-panduwana/test_gae
Python | 878 lines | 872 code | 6 blank | 0 comment | 10 complexity | 2db09ae3f3e5fb8a9d6541162e8c7661 MD5 | raw file
  1. from django import forms
  2. from django.conf import settings
  3. from django.forms.util import ErrorList
  4. from django.utils.translation import string_concat, ugettext_lazy as _
  5. import crauth
  6. from crauth.models import Role
  7. from crgappspanel import consts, models
  8. from crgappspanel.consts import EMAIL_RELS, PHONE_RELS
  9. from crgappspanel.helpers import fields, widgets
  10. from crlib import regexps
  11. __all__ = ('UserForm', 'UserEmailSettingsForm', 'UserEmailFiltersForm',
  12. 'SharedContactForm', 'CalendarResourceForm')
  13. ENABLE = 'e'
  14. DISABLE = 'd'
  15. ENABLE_DISABLE = (ENABLE, DISABLE)
  16. def create_on_off_keep(on_text, off_text):
  17. return (
  18. ('', _('Don\'t change')),
  19. ('e', _(on_text)),
  20. ('d', _(off_text)),
  21. )
  22. def create_exact_keep(*values):
  23. ret = [('', _('Don\'t change'))]
  24. ret.extend((v, v) for v in values)
  25. return ret
  26. class Form(forms.Form):
  27. def add_error(self, field, msg):
  28. if self._errors.has_key(field):
  29. self._errors[field].append(msg)
  30. else:
  31. self._errors[field] = ErrorList([msg])
  32. ################################################################################
  33. # GENERAL VALIDATION CODE #
  34. ################################################################################
  35. lower_start = ord('a')
  36. lower_end = ord('z')
  37. upper_start = ord('A')
  38. upper_end = ord('Z')
  39. digit_start = ord('0')
  40. digit_end = ord('9')
  41. def enforce_valid(value, lower=False, upper=False, digits=False, other=''):
  42. """Enforces that all characters in value are valid characters.
  43. Valid characters are:
  44. 1. All characters in other argument
  45. 2. Lowercase english letters if lower argument evaluates to True
  46. 3. Uppercase english letters if upper argument evaluates to True
  47. 4. Digits is digits argument evaluates to True
  48. Returns value if passed, throws ValidationError otherwise.
  49. """
  50. if not value:
  51. return value
  52. for c in value:
  53. x = ord(c)
  54. if c in other:
  55. pass
  56. elif lower_start <= x <= lower_end:
  57. if not lower:
  58. msg = _('Lowercase english letters are not allowed.')
  59. raise forms.ValidationError(msg)
  60. elif upper_start <= x <= upper_end:
  61. if not upper:
  62. msg = _('Uppercase english letters are not allowed.')
  63. raise forms.ValidationError(msg)
  64. elif digit_start <= x <= digit_end:
  65. if not digits:
  66. msg = _('Digits are not allowed.')
  67. raise forms.ValidationError(msg)
  68. else:
  69. msg = _('Character \'%(char)s\' is not allowed.') % dict(char=c)
  70. raise forms.ValidationError(msg)
  71. return value
  72. def enforce_invalid(value, lower=False, upper=False, digits=False, other=''):
  73. """Enforces that no single character in value is invalid character.
  74. Invalid characters are:
  75. 1. All characters in other argument
  76. 2. Lowercase english letters if lower argument evaluates to True
  77. 3. Uppercase english letters if upper argument evaluates to True
  78. 4. Digits is digits argument evaluates to True
  79. Returns value if passed, throws ValidationError otherwise.
  80. """
  81. if not value:
  82. return value
  83. for c in value:
  84. x = ord(c)
  85. if c in other:
  86. msg = _('Character \'%(char)s\' is not allowed.') % dict(char=c)
  87. raise forms.ValidationError(msg)
  88. elif lower_start <= x <= lower_end:
  89. if lower:
  90. msg = _('Lowercase english letters are not allowed.')
  91. raise forms.ValidationError(msg)
  92. elif upper_start <= x <= upper_end:
  93. if upper:
  94. msg = _('Uppercase english letters are not allowed.')
  95. raise forms.ValidationError(msg)
  96. elif digit_start <= x <= digit_end:
  97. if digits:
  98. msg = _('Digits are not allowed.')
  99. raise forms.ValidationError(msg)
  100. return value
  101. def enforce_some_alnum(value):
  102. """Enforces that at least one alphanumeric character exists in value.
  103. Returns value is passed, throws ValidationError otherwise.
  104. """
  105. if value:
  106. for c in value:
  107. x = ord(c)
  108. if lower_start <= x <= lower_end:
  109. return value
  110. elif upper_start <= x <= upper_end:
  111. return value
  112. elif digit_start <= x <= digit_end:
  113. return value
  114. msg = _('There must be at least one letter or digit.')
  115. raise forms.ValidationError(msg)
  116. ################################################################################
  117. # USERS #
  118. ################################################################################
  119. password_c = _('%(widget)s%(link_start)sChange password%(link_end)s WARNING: '
  120. 'dangerous, without confirmation yet!')
  121. password_1 = widgets.DoubleWidget(forms.HiddenInput(), forms.HiddenInput())
  122. password_e = _('Enter new password:<br/>%(widget)s '
  123. '%(link_start)sCancel%(link_end)s')
  124. password_2 = widgets.DoubleWidget(forms.PasswordInput(), forms.PasswordInput())
  125. nicknames_c = _('%(link_start)sAdd nickname%(link_end)s')
  126. nicknames_e = _('Enter nickname:<br/>%(widget)s '
  127. '%(link_start)sCancel%(link_end)s')
  128. full_name_kwargs = {
  129. 'regex': regexps.RE_FIRST_LAST_NAME,
  130. 'error_messages': {'invalid': regexps.ERROR_FIRST_LAST_NAME},
  131. }
  132. class UserForm(Form):
  133. user_name = forms.RegexField(
  134. regex=regexps.RE_USERNAME, label=_('Username'),
  135. error_messages={'invalid': regexps.ERROR_USERNAME})
  136. password = fields.CharField2(label=_('Password'), required=False, widget=password_2)
  137. change_password = forms.BooleanField(label=_('Password'), required=False,
  138. help_text=_('Require a change of password in the next sign in'))
  139. full_name = fields.RegexField2(
  140. label=_('Full name'), kwargs1=full_name_kwargs,
  141. kwargs2=full_name_kwargs)
  142. nicknames = forms.CharField(label=_('Nicknames'), required=False,
  143. widget=widgets.SwapWidget(nicknames_c, forms.TextInput(), nicknames_e))
  144. def create(self):
  145. data = self.cleaned_data
  146. password = data['password']
  147. if not password or password[0] == '' or password[0] != password[1]:
  148. return None
  149. return models.GAUser(
  150. user_name=data['user_name'],
  151. password=password,
  152. given_name=data['full_name'][0],
  153. family_name=data['full_name'][1])
  154. def populate(self, user):
  155. data = self.cleaned_data
  156. user.user_name = data['user_name']
  157. password = data['password']
  158. if password and password[0] and password[0] == password[1]:
  159. user.password = password[0]
  160. user.change_password = data['change_password']
  161. user.given_name = data['full_name'][0]
  162. user.family_name = data['full_name'][1]
  163. def get_nickname(self):
  164. return self.cleaned_data['nicknames']
  165. def clean_full_name(self):
  166. data = self.cleaned_data['full_name']
  167. first_name = data[0].strip()
  168. family_name = data[1].strip()
  169. if first_name == '':
  170. raise forms.ValidationError(_('First name is required.'))
  171. if family_name == '':
  172. raise forms.ValidationError(_('Family name is required.'))
  173. return [first_name, family_name]
  174. def clean_nicknames(self):
  175. data = self.cleaned_data['nicknames']
  176. if data and not regexps.RE_USERNAME.match(data):
  177. raise forms.ValidationError(regexps.ERROR_NICKNAME)
  178. return data
  179. def clean_password(self):
  180. password = self.cleaned_data['password']
  181. if not password:
  182. return password
  183. pass_a, pass_b = password
  184. if pass_a != pass_b:
  185. raise forms.ValidationError(_('These passwords don\'t match.'))
  186. return [pass_a, pass_b]
  187. roles_c = _('%(link_start)sAdd role%(link_end)s')
  188. roles_e = _('Choose role:<br/>%(widget)s %(link_start)sCancel%(link_end)s')
  189. class UserRolesForm(forms.Form):
  190. roles = forms.CharField(label=_('Roles'), required=False,
  191. widget=widgets.SwapWidget(roles_c, forms.Select(), roles_e))
  192. def __init__(self, *args, **kwargs):
  193. if 'choices' in kwargs:
  194. choices = kwargs['choices']
  195. del kwargs['choices']
  196. else:
  197. choices = None
  198. super(UserRolesForm, self).__init__(*args, **kwargs)
  199. if choices:
  200. self.fields['roles'].widget.widget.choices = choices
  201. ADD_AS_CHOICES = (('owner', _('Owner')), ('member', _('Member')))
  202. class UserGroupsForm(forms.Form):
  203. groups = forms.MultipleChoiceField(label=_('Add to groups'), choices=(),
  204. widget=forms.SelectMultiple(attrs={'class':'long'}))
  205. add_as = forms.ChoiceField(label=_('Add as'), choices=ADD_AS_CHOICES)
  206. ENABLE_DISABLE_KEEP = create_on_off_keep(_('Enable'), _('Disable'))
  207. LANGUAGE_CHOICES = [('', _('Don\'t change'))]
  208. LANGUAGE_CHOICES.extend(consts.LANGUAGES)
  209. FORWARD_CHOICES = (
  210. ('', _('Don\'t change')),
  211. ('ek', _('Forward and keep')),
  212. ('ea', _('Forward and archive')),
  213. ('ed', _('Forward and delete')),
  214. ('d', _('Don\'t forward')),
  215. )
  216. FORWARD_ENABLES = ('ek', 'ea', 'ed')
  217. FORWARD_DISABLES = ('d')
  218. POP3_CHOICES = (
  219. ('', _('Don\'t change')),
  220. ('ea', _('Enable for all emails')),
  221. ('en', _('Enable for emails for now on')),
  222. ('d', _('Disable')),
  223. )
  224. POP3_ENABLES = ('ea', 'en')
  225. POP3_DISABLES = ('d')
  226. MESSAGES_PER_PAGE_CHOICES = create_exact_keep(u'25', u'50', u'100')
  227. UNICODE_CHOICES = create_on_off_keep(_('Use Unicode (UTF-8)'), _('Use default text encoding'))
  228. #forward_c = '%(link_start)sEnable forwarding%(link_end)s'
  229. #forward_e = 'Forward to: %(widget)s %(link_start)sCancel%(link_end)s'
  230. class UserEmailSettingsForm(forms.Form):
  231. language = forms.ChoiceField(label=_('Language'),
  232. choices=LANGUAGE_CHOICES, required=False)
  233. forward = forms.ChoiceField(label=_('Forwarding'),
  234. choices=FORWARD_CHOICES, required=False)
  235. forward_to = forms.EmailField(label=_('Forward to'), required=False,
  236. widget=forms.TextInput(attrs={'class':'long'}))
  237. pop3 = forms.ChoiceField(label=_('POP3'),
  238. choices=POP3_CHOICES, required=False)
  239. imap = forms.ChoiceField(label=_('IMAP'),
  240. choices=ENABLE_DISABLE_KEEP, required=False)
  241. messages_per_page = forms.ChoiceField(label=_('Messages per page'),
  242. choices=MESSAGES_PER_PAGE_CHOICES, required=False)
  243. web_clips = forms.ChoiceField(label=_('Web Clips'),
  244. choices=ENABLE_DISABLE_KEEP, required=False)
  245. snippets = forms.ChoiceField(label=_('Snippets'),
  246. choices=ENABLE_DISABLE_KEEP, required=False)
  247. shortcuts = forms.ChoiceField(label=_('Keyboard shortcuts'),
  248. choices=ENABLE_DISABLE_KEEP, required=False)
  249. arrows = forms.ChoiceField(label=_('Personal level indicators'),
  250. choices=ENABLE_DISABLE_KEEP, required=False)
  251. unicode = forms.ChoiceField(label=_('Outgoing mail encoding'),
  252. choices=UNICODE_CHOICES, required=False)
  253. signature = forms.ChoiceField(label=_('Signature'),
  254. choices=ENABLE_DISABLE_KEEP, required=False)
  255. signature_new = forms.CharField(label='', required=False,
  256. widget=forms.Textarea(attrs=dict(rows=3, cols=30)))
  257. def get_boolean(self, key):
  258. value = self.cleaned_data[key]
  259. if value in ENABLE_DISABLE:
  260. return value == ENABLE
  261. return None
  262. def clean(self):
  263. data = self.cleaned_data
  264. forward = data.get('forward')
  265. forward_to = data.get('forward_to')
  266. signature = data.get('signature')
  267. signature_new = data.get('signature_new')
  268. domain = crauth.users.get_current_user().domain_name
  269. # enabling forwarding => forward_to must be filled
  270. if forward in FORWARD_ENABLES and not forward_to:
  271. msg = _('Forwarding address must be specified when enabling forwarding.')
  272. self._errors['forward_to'] = ErrorList([msg])
  273. data.pop('forward', None)
  274. data.pop('forward_to', None)
  275. elif forward in FORWARD_ENABLES and not forward_to.endswith(domain):
  276. msg = _('Forwarding address must point to %(domain)s or its '
  277. 'subdomain.' % {'domain': domain})
  278. self._errors['forward_to'] = ErrorList([msg])
  279. data.pop('forward', None)
  280. data.pop('forward_to', None)
  281. # not enabling forwarding => forward_to must be empty
  282. if forward not in FORWARD_ENABLES and forward_to:
  283. msg = _('Forwarding address must not be specified when not enabling forwarding.')
  284. self._errors['forward_to'] = ErrorList([msg])
  285. data.pop('forward', None)
  286. data.pop('forward_to', None)
  287. # enabling signature => signature_new must be filled
  288. if signature == ENABLE and not signature_new:
  289. msg = _('Signature must be specified when enabling signature.')
  290. self._errors['signature_new'] = ErrorList([msg])
  291. data.pop('signature')
  292. data.pop('signature_new')
  293. # not enabling signature => signature_new must be empty
  294. if signature != ENABLE and signature_new:
  295. msg = _('Signature must not be specified when not enabling signature.')
  296. self._errors['signature_new'] = ErrorList([msg])
  297. data.pop('signature')
  298. data.pop('signature_new')
  299. return data
  300. HAS_ATTACHMENT_CHOICES = (
  301. ('', _('Doesn\'t matter')),
  302. ('e', _('Must have')),
  303. )
  304. class UserEmailFiltersForm(forms.Form):
  305. from_ = forms.EmailField(label=_('From'), required=False,
  306. widget=forms.TextInput(attrs={'class':'long'}))
  307. to = forms.EmailField(label=_('To'), required=False,
  308. widget=forms.TextInput(attrs={'class':'long'}))
  309. subject = forms.CharField(label=_('Subject'), required=False)
  310. has_the_word = forms.CharField(label=_('Has the words'), required=False)
  311. does_not_have_the_word = forms.CharField(label=_('Doesn\'t have'),
  312. required=False)
  313. has_attachment = forms.ChoiceField(label=_('Has attachment'),
  314. choices=HAS_ATTACHMENT_CHOICES, required=False)
  315. label = forms.CharField(label=_('Apply label'), required=False)
  316. should_mark_as_read = forms.BooleanField(label=_('Mark as read'),
  317. required=False)
  318. should_archive = forms.BooleanField(label=_('Archive'), required=False)
  319. def clean_subject(self):
  320. return self.verify_illegal_chars('subject')
  321. def clean_has_the_word(self):
  322. return self.verify_illegal_chars('has_the_word')
  323. def clean_does_not_have_the_word(self):
  324. return self.verify_illegal_chars('does_not_have_the_word')
  325. def clean(self):
  326. data = self.cleaned_data
  327. filter_fields = ('from_', 'to', 'subject', 'has_the_word',
  328. 'does_not_have_the_word', 'has_attachment')
  329. action_fields = ('label', 'should_mark_as_read', 'should_archive')
  330. if not any(data.get(key) for key in filter_fields):
  331. msg = _('At least one of fields: from, to, subject, has words, '
  332. 'doesn\'t have, has attachment must be filled.')
  333. raise forms.ValidationError(msg)
  334. if not any(data.get(key) for key in action_fields):
  335. msg = _('At least one of fields apply label, mark as read, '
  336. 'archive must be filled.')
  337. raise forms.ValidationError(msg)
  338. return data
  339. def verify_illegal_chars(self, key):
  340. value = self.cleaned_data[key]
  341. return enforce_invalid(value, other='[]()$&*')
  342. VACATION_STATE_CHOICES = (
  343. ('true', _('Enabled')),
  344. ('false', _('Disabled')),
  345. )
  346. VACATION_CONTACTS_ONLY_CHOICES = (
  347. ('true', _('Only send a response to people in my Contacts')),
  348. ('false', _('Send to all')),
  349. )
  350. class UserEmailVacationForm(forms.Form):
  351. state = forms.ChoiceField(
  352. label=_('Out of Office AutoReply'), choices=VACATION_STATE_CHOICES,
  353. widget=forms.Select(attrs={
  354. 'onchange': 'return cr.snippets.vacationStateChanged(this.value);',
  355. }))
  356. subject = forms.CharField(
  357. label=_('Subject'), max_length=500, required=False)
  358. message = forms.CharField(
  359. label=_('Message'), widget=forms.Textarea, required=False)
  360. contacts_only = forms.ChoiceField(
  361. label=_('Send to'), choices=VACATION_CONTACTS_ONLY_CHOICES,
  362. required=False)
  363. def clean_subject(self):
  364. enabled = self.cleaned_data.get('state', 'true') == 'true'
  365. if enabled and not self.cleaned_data['subject']:
  366. raise forms.ValidationError(
  367. _('Subject field is required'))
  368. return self.cleaned_data['subject']
  369. def clean_message(self):
  370. enabled = self.cleaned_data.get('state', 'true') == 'true'
  371. if enabled and not self.cleaned_data['message']:
  372. raise forms.ValidationError(
  373. _('Message field is required'))
  374. return self.cleaned_data['message']
  375. def clean_contacts_only(self):
  376. enabled = self.cleaned_data.get('state', 'true') == 'true'
  377. if enabled and not self.cleaned_data['contacts_only']:
  378. raise forms.ValidationError(
  379. _('Message field is required'))
  380. return self.cleaned_data['contacts_only']
  381. reply_to_c = _('Set %(link_start)sanother%(link_end)s reply to address')
  382. reply_to_e = _('%(widget)s %(link_start)sCancel%(link_end)s')
  383. class UserEmailAliasesForm(Form):
  384. name = forms.CharField(label=_('Name'), max_length=250)
  385. address = forms.EmailField(label=_('Email address'),
  386. widget=forms.TextInput(attrs={'class':'long'}))
  387. reply_to = forms.EmailField(label=_('Reply to'), required=False,
  388. widget=widgets.SwapWidget(reply_to_c,
  389. forms.TextInput(attrs={'class':'long'}), reply_to_e))
  390. make_default = forms.BooleanField(label=_('Make default'), required=False)
  391. ################################################################################
  392. # GROUPS #
  393. ################################################################################
  394. class GroupForm(Form):
  395. id = forms.CharField(label=_('Email address'))
  396. name = forms.CharField(label=_('Name'), required=True)
  397. email_permission = forms.ChoiceField(label=_('Email permission'),
  398. choices=consts.GROUP_EMAIL_PERMISSION_CHOICES)
  399. description = forms.CharField(label=_('Description'), required=False,
  400. widget=forms.Textarea(attrs=dict(rows=3, cols=30)))
  401. def create(self, domain):
  402. data = self.cleaned_data
  403. return models.GAGroup(
  404. id='%s@%s' % (data['id'], domain),
  405. name=data['name'],
  406. email_permission=data['email_permission'],
  407. description=data['description'])
  408. def populate(self, group):
  409. data = self.cleaned_data
  410. group.name = data['name']
  411. group.email_permission = data['email_permission']
  412. group.description = data['description']
  413. return data['id']
  414. def clean_id(self):
  415. id = self.cleaned_data['id']
  416. enforce_valid(id, lower=True, upper=True, digits=True, other='_.-+')
  417. enforce_some_alnum(id)
  418. return id
  419. def clean_name(self):
  420. data = self.cleaned_data['name'].strip()
  421. if data == '':
  422. raise forms.ValidationError(_('Group name is required.'))
  423. return data
  424. owner_c = _('%(link_start)sAdd%(link_end)s another owner')
  425. owner_e = _('%(widget)s %(link_start)sCancel%(link_end)s')
  426. member_c = _('%(link_start)sAdd%(link_end)s another member')
  427. member_e = _('%(widget)s %(link_start)sCancel%(link_end)s')
  428. class GroupMembersForm(forms.Form):
  429. owner = forms.EmailField(label=_('Owners'), required=False,
  430. widget=widgets.SwapWidget(owner_c,
  431. forms.TextInput(attrs={'class':'long', 'id':'owner'}), owner_e))
  432. member = forms.EmailField(label=_('Members'), required=False,
  433. widget=widgets.SwapWidget(member_c,
  434. forms.TextInput(attrs={'class':'long', 'id':'member'}), member_e))
  435. ################################################################################
  436. # ROLES #
  437. ################################################################################
  438. PERMISSION_NAMES = crauth.permissions.permission_names(False)
  439. PERMISSION_DEPS = list(crauth.permissions.permission_deps(False))
  440. OBJECT_TYPES = (
  441. ('users', _('Manage Users'), (
  442. ('gauser', _('General')),
  443. ('gausersettings', _('Email Settings')),
  444. ('gauserfilters', _('Filters')),
  445. ('gausersendas', _('Send as')),
  446. ('gauservacation', _('Vacation responder')),
  447. )),
  448. ('groups', _('Manage Groups'), (
  449. ('gagroup', _('General')),
  450. )),
  451. ('roles', _('Manage Roles'), (
  452. ('role', _('General')),
  453. )),
  454. ('shared_contacts', _('Manage Shared Contacts'), (
  455. ('sharedcontact', _('General')),
  456. )),
  457. ('calendar_resources', _('Manage Calendar Resources'), (
  458. ('calendarresource', _('General')),
  459. )),
  460. )
  461. class ObjectTypeFields(object):
  462. def __init__(self, form, obj_type, name=None):
  463. self.form = form
  464. self.obj_type = obj_type
  465. self.name = name or obj_type
  466. def obj_name(self):
  467. return
  468. def add(self):
  469. return self.get('add_%s' % self.obj_type)
  470. def change(self):
  471. return self.get('change_%s' % self.obj_type)
  472. def read(self):
  473. return self.get('read_%s' % self.obj_type)
  474. def get(self, key):
  475. try:
  476. return self.form[key]
  477. except KeyError:
  478. return None
  479. class PermissionWidget(forms.CheckboxInput):
  480. def render(self, name, value, attrs=None):
  481. from django.utils.safestring import mark_safe
  482. from django.forms.util import flatatt
  483. from django.template.loader import render_to_string
  484. final_attrs = self.build_attrs(attrs, type='checkbox', name=name)
  485. depends_on = final_attrs.pop('depends_on', '')
  486. try:
  487. result = self.check_test(value)
  488. except Exception: # Silently catch exceptions
  489. result = False
  490. if result:
  491. final_attrs['checked'] = 'checked'
  492. if value not in ('', True, False, None):
  493. # Only add the 'value' attribute if a value is non-empty.
  494. final_attrs['value'] = force_unicode(value)
  495. return render_to_string(
  496. 'snippets/permission_widget.html', {
  497. 'flatatt': flatatt(final_attrs),
  498. 'id': final_attrs['id'],
  499. 'depends_on': depends_on,
  500. })
  501. class RoleForm(forms.Form):
  502. name = forms.CharField(label=_('Name'), required=True)
  503. def __init__(self, *args, **kwargs):
  504. super(forms.Form, self).__init__(*args, **kwargs)
  505. self.sections = dict()
  506. perms = dict()
  507. for perm, depends_on in PERMISSION_DEPS:
  508. action, obj_type = perm.split('_')
  509. actions = perms[obj_type] if obj_type in perms else set()
  510. actions.add((action, depends_on))
  511. perms[obj_type] = actions
  512. for section in OBJECT_TYPES:
  513. self._add_section(section, perms)
  514. self._permissions = None
  515. def _data_to_permissions(self):
  516. data = self.cleaned_data
  517. if not self._permissions:
  518. permissions = set()
  519. for perm, depends_on in PERMISSION_DEPS:
  520. if perm in data and data[perm]:
  521. permissions.add(perm)
  522. if depends_on:
  523. permissions.add(depends_on)
  524. self._permissions = list(permissions)
  525. return self._permissions
  526. def create(self, domain):
  527. return crauth.models.Role(
  528. parent=domain, name=self.cleaned_data['name'],
  529. permissions=self._data_to_permissions())
  530. def populate(self, role):
  531. role.name = self.cleaned_data['name']
  532. role.permissions = self._data_to_permissions()
  533. def _add_section(self, section, perms):
  534. section_obj = dict(name=section[1], groups=[])
  535. # iterating through section groups
  536. for obj_type, name in section[2]:
  537. actions = list(perms[obj_type])
  538. actions.sort()
  539. # adding fields to the form
  540. for action, depends_on in actions:
  541. field = self._add_field(obj_type, action, depends_on)
  542. # adding group to section
  543. group = ObjectTypeFields(self, obj_type, name=name)
  544. section_obj['groups'].append(group)
  545. self.sections[section[0]] = section_obj
  546. def _add_field(self, obj_type, action, depends_on):
  547. field_name = '%s_%s' % (action, obj_type)
  548. field = forms.BooleanField(
  549. required=False, widget=PermissionWidget(
  550. attrs={
  551. 'class': 'perm_%s' % action,
  552. 'depends_on': depends_on,
  553. }))
  554. self.fields[field_name] = field
  555. return field
  556. def clean_name(self):
  557. name = self.cleaned_data['name'].strip()
  558. if name == '':
  559. raise forms.ValidationError(_('Role name is required.'))
  560. if name in ('.', '..'):
  561. raise forms.ValidationError(_('Invalid role name.'))
  562. if not hasattr(self, 'old_name') or name != self.old_name:
  563. role = Role.for_domain(crauth.users.get_current_domain()).filter(
  564. 'name', name).get()
  565. if role or name == _('Administrator'):
  566. raise forms.ValidationError(_('Role with this name already exists.'))
  567. return name
  568. def clean(self):
  569. permissions = self._data_to_permissions()
  570. if not permissions:
  571. raise forms.ValidationError(
  572. _('You have to select at least one permission.'))
  573. return self.cleaned_data
  574. ################################################################################
  575. # SHARED CONTACTS #
  576. ################################################################################
  577. emails_c = _('%(link_start)sAdd email%(link_end)s')
  578. emails_e = _('Enter email:<br/>%(widget)s %(link_start)sCancel%(link_end)s')
  579. phone_numbers_c = _('%(link_start)sAdd phone number%(link_end)s')
  580. phone_numbers_e = _('Enter phone number:<br/>%(widget)s '
  581. '%(link_start)sCancel%(link_end)s')
  582. class SharedContactForm(Form):
  583. full_name = forms.CharField(label=_('Display name'))
  584. real_name = fields.RealNameField(label=_('Real name'), required=False)
  585. notes = forms.CharField(label=_('Notes'), required=False,
  586. widget=forms.Textarea(attrs=dict(rows=3, cols=30)))
  587. company = forms.CharField(label=_('Company'), required=False)
  588. role = forms.CharField(label=_('Role'), required=False)
  589. # email field to show when creating contact
  590. email = forms.EmailField(label=_('Email'), required=False,
  591. widget=forms.TextInput(attrs={'class':'long'}))
  592. # emails filed to show when editing contact
  593. emails = forms.EmailField(label=_('Emails'), required=False,
  594. widget=widgets.SwapWidget(emails_c,
  595. forms.TextInput(attrs={'class':'long'}), emails_e))
  596. # phone number field to show when creating contact
  597. phone_number = forms.CharField(label=_('Phone number'), required=False)
  598. # phone numbers field to show when editing contact
  599. phone_numbers = forms.CharField(label=_('Phone numbers'), required=False,
  600. widget=widgets.SwapWidget(phone_numbers_c,
  601. forms.TextInput(), phone_numbers_e))
  602. def create(self):
  603. data = self.cleaned_data
  604. name = models.Name(
  605. full_name=data['full_name'],
  606. given_name=data['real_name'][0], family_name=data['real_name'][1])
  607. email = data['email']
  608. emails = [self._email(email)] if email else []
  609. phone_number = data['phone_number']
  610. phone_numbers = [self._phone_number(phone_number)] if phone_number else []
  611. contact = models.SharedContact(
  612. name=name, notes=data['notes'],
  613. emails=emails, phone_numbers=phone_numbers)
  614. company, role = data['company'], data['role']
  615. if company or role:
  616. contact.organization = models.Organization(
  617. name=company, title=role)
  618. contact.organization.save()
  619. return contact
  620. def populate(self, shared_contact):
  621. data = self.cleaned_data
  622. email = data['emails']
  623. phone_number = data['phone_numbers']
  624. shared_contact.name.full_name = data['full_name']
  625. shared_contact.name.given_name = data['real_name'][0]
  626. shared_contact.name.family_name = data['real_name'][1]
  627. shared_contact.notes = data['notes']
  628. return {
  629. 'emails': [self._email(email)] if email else [],
  630. 'phone_numbers': [self._phone_number(phone_number)] if phone_number else [],
  631. 'company_str': data['company'],
  632. 'role_str': data['role'],
  633. }
  634. def _email(self, email):
  635. return models.Email(address=email, rel=EMAIL_RELS[0])
  636. def _phone_number(self, phone_number):
  637. return models.PhoneNumber(number=phone_number, rel=PHONE_RELS[0])
  638. def clean(self):
  639. data = self.cleaned_data
  640. company = data.get('company')
  641. role = data.get('role')
  642. # role filled => company must be filled
  643. if not company and role:
  644. msg = _('Company is required if role is not empty.')
  645. self._errors['company'] = ErrorList([msg])
  646. data.pop('company', None)
  647. data.pop('role', None)
  648. return data
  649. ################################################################################
  650. # CALENDAR RESOURCES #
  651. ################################################################################
  652. class CalendarResourceForm(Form):
  653. common_name = forms.CharField(label=_('Name'), max_length=1000)
  654. type = forms.CharField(
  655. label=_('Type'), required=False, max_length=100)
  656. description = forms.CharField(
  657. label=_('Description'), required=False,
  658. max_length=1000, widget=forms.Textarea(attrs=dict(rows=3, cols=30)))
  659. def create(self, id):
  660. data = self.cleaned_data
  661. return models.CalendarResource(
  662. id=id, common_name=data['common_name'], type=data['type'],
  663. description=data['description'])
  664. def populate(self, resource):
  665. data = self.cleaned_data
  666. resource.common_name = data['common_name']
  667. resource.type = data['type']
  668. resource.description = data['description']
  669. def clean_common_name(self):
  670. name = self.cleaned_data['common_name'].strip()
  671. if name == '':
  672. raise forms.ValidationError(_('Name is required.'))
  673. return name
  674. ################################################################################
  675. # SETTINGS #
  676. ################################################################################
  677. class SettingsForm(forms.ModelForm):
  678. class Meta:
  679. model = models.Preferences
  680. fields = ('language', 'items_per_page',)
  681. ITEMS_PER_PAGE_CHOICES = (
  682. (20, '20'),
  683. (50, '50'),
  684. (100, '100'),
  685. )
  686. language = forms.ChoiceField(
  687. label=_('Language'), choices=settings.LANGUAGES)
  688. items_per_page = forms.TypedChoiceField(
  689. label=_('Items per page'),
  690. choices=ITEMS_PER_PAGE_CHOICES, coerce=int,
  691. help_text=_('How many items to show at once on listing pages.'))