|
1 # |
|
2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net> |
|
3 # All Rights Reserved. |
|
4 # |
|
5 # This software is subject to the provisions of the Zope Public License, |
|
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
|
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
|
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
|
10 # FOR A PARTICULAR PURPOSE. |
|
11 # |
|
12 |
|
13 __docformat__ = 'restructuredtext' |
|
14 |
|
15 |
|
16 # import standard library |
|
17 |
|
18 # import interfaces |
|
19 from pyams_form.interfaces.form import IWidgetsSuffixViewletsManager |
|
20 from pyams_security.interfaces import ILoginView, ISecurityManager, IUserRegistrationInfo, \ |
|
21 IUserRegistrationConfirmationInfo |
|
22 from pyams_skin.interfaces import IModalFullPage |
|
23 from pyams_skin.layer import IPyAMSLayer |
|
24 from z3c.form.interfaces import HIDDEN_MODE, IDataExtractedEvent |
|
25 |
|
26 # import packages |
|
27 from pyams_form.form import DialogAddForm, AJAXAddForm, AddForm |
|
28 from pyams_form.schema import CloseButton |
|
29 from pyams_pagelet.pagelet import pagelet_config |
|
30 from pyams_security.plugin.userfolder import User |
|
31 from pyams_template.template import template_config |
|
32 from pyams_utils.registry import query_utility, get_utility |
|
33 from pyams_viewlet.viewlet import viewlet_config, Viewlet |
|
34 from pyramid.events import subscriber |
|
35 from pyramid.httpexceptions import HTTPNotFound |
|
36 from pyramid.view import view_config |
|
37 from z3c.form import field, button |
|
38 from zope.interface import implementer, Interface, Invalid |
|
39 |
|
40 from pyams_security import _ |
|
41 |
|
42 |
|
43 # |
|
44 # User registration form |
|
45 # |
|
46 |
|
47 @viewlet_config(name='user-registration-suffix', layer=IPyAMSLayer, |
|
48 manager=IWidgetsSuffixViewletsManager, view=ILoginView, weight=25) |
|
49 @template_config(template='templates/user-registration.pt') |
|
50 class UserRegistrationViewletsSuffix(Viewlet): |
|
51 """User registration viewlet suffix""" |
|
52 |
|
53 button_label = _("Register new account") |
|
54 |
|
55 def __new__(cls, *args, **kwargs): |
|
56 manager = query_utility(ISecurityManager) |
|
57 if not manager.open_registration: |
|
58 return None |
|
59 return Viewlet.__new__(cls) |
|
60 |
|
61 |
|
62 class IUserRegistrationFormButtons(Interface): |
|
63 """User registration form buttons""" |
|
64 |
|
65 cancel = CloseButton(name='close', title=_("Cancel")) |
|
66 register = button.Button(name='register', title=_("Register")) |
|
67 |
|
68 |
|
69 @pagelet_config(name='user-registration.html', layer=IPyAMSLayer) |
|
70 class UserRegistrationForm(DialogAddForm): |
|
71 """User registration form""" |
|
72 |
|
73 title = _("User registration") |
|
74 legend = _("Please enter registration info") |
|
75 icon_css_class = 'fa fa-fw fa-user' |
|
76 |
|
77 fields = field.Fields(IUserRegistrationInfo) |
|
78 buttons = button.Buttons(IUserRegistrationFormButtons) |
|
79 ajax_handler = 'user-registration.json' |
|
80 edit_permission = None |
|
81 |
|
82 def updateActions(self): |
|
83 super(UserRegistrationForm, self).updateActions() |
|
84 if 'register' in self.actions: |
|
85 self.actions['register'].addClass('btn-primary') |
|
86 |
|
87 def updateWidgets(self, prefix=None): |
|
88 super(UserRegistrationForm, self).updateWidgets() |
|
89 self.widgets['password'].input_css_class = 'col-md-4' |
|
90 self.widgets['confirmed_password'].input_css_class = 'col-md-4' |
|
91 |
|
92 def create(self, data): |
|
93 return User() |
|
94 |
|
95 def update_content(self, user, data): |
|
96 user.login = data.get('login') |
|
97 user.email = data.get('email') |
|
98 user.firstname = data.get('firstname') |
|
99 user.lastname = data.get('lastname') |
|
100 user.company_name = data.get('company_name') |
|
101 user.password = data.get('password') |
|
102 user.generate_secret() |
|
103 |
|
104 def add(self, user): |
|
105 manager = get_utility(ISecurityManager) |
|
106 folder = manager.get(manager.users_folder) |
|
107 folder[user.login] = user |
|
108 |
|
109 |
|
110 @subscriber(IDataExtractedEvent, form_selector=UserRegistrationForm) |
|
111 def handle_registration_data_extraction(event): |
|
112 """Handle registration data extraction""" |
|
113 data = event.data |
|
114 if not data.get('login'): |
|
115 data['login'] = data['email'] |
|
116 manager = get_utility(ISecurityManager) |
|
117 folder = manager.get(manager.users_folder) |
|
118 if folder is None: |
|
119 event.form.widgets.errors += (Invalid(_("Can't create user profile. Please contact system administrator.")),) |
|
120 elif not folder.check_login(data.get('login')): |
|
121 event.form.widgets.errors += (Invalid(_("Specified login can't be used!")),) |
|
122 |
|
123 |
|
124 @view_config(name='user-registration.json', request_type=IPyAMSLayer, renderer='json', xhr=True) |
|
125 class UserRegistrationAJAXForm(AJAXAddForm, UserRegistrationForm): |
|
126 """User registration form, AJAX view""" |
|
127 |
|
128 def get_ajax_output(self, changes): |
|
129 translate = self.request.localizer.translate |
|
130 return {'status': 'success', |
|
131 'messagebox': {'status': 'success', |
|
132 'title': translate(_("Your registration is recorded!")), |
|
133 'icon': 'fa fa-fw fa-2x fa-user', |
|
134 'content': translate(_("Your registration is recorded. You should receive a " |
|
135 "confirmation email soon which will allow you to " |
|
136 "confirm your inscription.")), |
|
137 'timeout': None}} |
|
138 |
|
139 |
|
140 # |
|
141 # Registration confirmation form |
|
142 # |
|
143 |
|
144 class IUserConfirmationFormButtons(Interface): |
|
145 """User confirmation form buttons""" |
|
146 |
|
147 confirm = button.Button(name='confirm', title=_("Finalize registration")) |
|
148 |
|
149 |
|
150 @pagelet_config(name='user-confirmation.html', layer=IPyAMSLayer) |
|
151 @implementer(IModalFullPage) |
|
152 class UserConfirmationForm(AddForm): |
|
153 """User registration confirmation form""" |
|
154 |
|
155 title = _("User registration confirmation") |
|
156 legend = _("Please confirm your registration info") |
|
157 icon_css_class = 'fa fa-fw fa-user' |
|
158 |
|
159 fields = field.Fields(IUserRegistrationConfirmationInfo) |
|
160 buttons = button.Buttons(IUserConfirmationFormButtons) |
|
161 ajax_handler = 'user-confirmation.json' |
|
162 edit_permission = None |
|
163 |
|
164 def updateWidgets(self, prefix=None): |
|
165 super(UserConfirmationForm, self).updateWidgets() |
|
166 self.widgets['activation_hash'].mode = HIDDEN_MODE |
|
167 self.widgets['activation_hash'].value = self.request.form.get('hash') or self.widgets['activation_hash'].value |
|
168 |
|
169 def updateActions(self): |
|
170 super(UserConfirmationForm, self).updateActions() |
|
171 if 'confirm' in self.actions: |
|
172 self.actions['confirm'].addClass('btn-primary') |
|
173 |
|
174 def createAndAdd(self, data): |
|
175 user = data.get('user') |
|
176 if user is None: |
|
177 raise HTTPNotFound() |
|
178 self._finishedAdd = True |
|
179 |
|
180 def nextURL(self): |
|
181 return '/' |
|
182 |
|
183 |
|
184 @subscriber(IDataExtractedEvent, form_selector=UserConfirmationForm) |
|
185 def handle_confirmation_data_extraction(event): |
|
186 """Handle confirmation data extraction""" |
|
187 data = event.data |
|
188 if 'user' in data: |
|
189 del data['user'] |
|
190 manager = get_utility(ISecurityManager) |
|
191 folder = manager.get(manager.users_folder) |
|
192 if folder is None: |
|
193 event.form.widgets.errors += (Invalid(_("Can't check user profile. Please contact system administrator.")),) |
|
194 else: |
|
195 login = data.get('login') |
|
196 user = folder.get(login) |
|
197 if user is None: |
|
198 event.form.widgets.errors += (Invalid(_("Can't retrieve user profile!")),) |
|
199 else: |
|
200 try: |
|
201 user.check_activation(data.get('activation_hash'), login, data.get('password')) |
|
202 except Invalid as error: |
|
203 event.form.widgets.errors += (error,) |
|
204 else: |
|
205 data['user'] = user |
|
206 |
|
207 |
|
208 @view_config(name='user-confirmation.json', request_type=IPyAMSLayer, renderer='json', xhr=True) |
|
209 class UserConfirmationAJAXForm(AJAXAddForm, UserConfirmationForm): |
|
210 """User registration confirmation form, AJAX view""" |
|
211 |
|
212 def get_ajax_output(self, changes): |
|
213 return {'status': 'redirect', |
|
214 'location': 'user-registration-end.html'} |
|
215 |
|
216 |
|
217 @pagelet_config(name='user-registration-end.html', layer=IPyAMSLayer) |
|
218 @template_config(template='templates/user-registration-end.pt', layer=IPyAMSLayer) |
|
219 @implementer(IModalFullPage) |
|
220 class UserRegistrationEnd(object): |
|
221 """User registration end""" |
|
222 |