Show More
@@ -1,255 +1,242 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 |
|
2 | |||
3 | # Copyright (C) 2010-2016 RhodeCode GmbH |
|
3 | # Copyright (C) 2010-2016 RhodeCode GmbH | |
4 | # |
|
4 | # | |
5 | # This program is free software: you can redistribute it and/or modify |
|
5 | # This program is free software: you can redistribute it and/or modify | |
6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
7 | # (only), as published by the Free Software Foundation. |
|
7 | # (only), as published by the Free Software Foundation. | |
8 | # |
|
8 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
12 | # GNU General Public License for more details. | |
13 | # |
|
13 | # | |
14 | # You should have received a copy of the GNU Affero General Public License |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | # |
|
16 | # | |
17 | # This program is dual-licensed. If you wish to learn more about the |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
18 | # App Enlight Enterprise Edition, including its added features, Support |
|
18 | # App Enlight Enterprise Edition, including its added features, Support | |
19 | # services, and proprietary license terms, please see |
|
19 | # services, and proprietary license terms, please see | |
20 | # https://rhodecode.com/licenses/ |
|
20 | # https://rhodecode.com/licenses/ | |
21 |
|
21 | |||
22 | import datetime |
|
22 | import datetime | |
23 | import logging |
|
23 | import logging | |
24 | import uuid |
|
24 | import uuid | |
25 |
|
25 | |||
26 | import pyramid.security as security |
|
26 | import pyramid.security as security | |
27 |
|
27 | |||
28 | from pyramid.view import view_config |
|
28 | from pyramid.view import view_config | |
29 | from pyramid.httpexceptions import HTTPFound |
|
29 | from pyramid.httpexceptions import HTTPFound | |
30 | from pyramid.response import Response |
|
30 | from pyramid.response import Response | |
31 | from pyramid.security import NO_PERMISSION_REQUIRED |
|
31 | from pyramid.security import NO_PERMISSION_REQUIRED | |
32 | from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignInSuccess |
|
32 | from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignInSuccess | |
33 | from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignInBadAuth |
|
33 | from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignInBadAuth | |
34 | from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignOut |
|
34 | from ziggurat_foundations.ext.pyramid.sign_in import ZigguratSignOut | |
35 |
|
35 | |||
36 | from appenlight.lib.social import handle_social_data |
|
36 | from appenlight.lib.social import handle_social_data | |
37 | from appenlight.models import DBSession |
|
37 | from appenlight.models import DBSession | |
38 | from appenlight.models.user import User |
|
38 | from appenlight.models.user import User | |
39 | from appenlight.models.services.user import UserService |
|
39 | from appenlight.models.services.user import UserService | |
40 | from appenlight.subscribers import _ |
|
40 | from appenlight.subscribers import _ | |
41 | from appenlight import forms |
|
41 | from appenlight import forms | |
42 | from webob.multidict import MultiDict |
|
42 | from webob.multidict import MultiDict | |
43 |
|
43 | |||
44 | log = logging.getLogger(__name__) |
|
44 | log = logging.getLogger(__name__) | |
45 |
|
45 | |||
46 |
|
46 | |||
47 | @view_config(context=ZigguratSignInSuccess, permission=NO_PERMISSION_REQUIRED) |
|
47 | @view_config(context=ZigguratSignInSuccess, permission=NO_PERMISSION_REQUIRED) | |
48 | def sign_in(request): |
|
48 | def sign_in(request): | |
49 | """ |
|
49 | """ | |
50 | Performs sign in by sending proper user identification headers |
|
50 | Performs sign in by sending proper user identification headers | |
51 | Regenerates CSRF token |
|
51 | Regenerates CSRF token | |
52 | """ |
|
52 | """ | |
53 | user = request.context.user |
|
53 | user = request.context.user | |
54 | if user.status == 1: |
|
54 | if user.status == 1: | |
55 | request.session.new_csrf_token() |
|
55 | request.session.new_csrf_token() | |
56 | user.last_login_date = datetime.datetime.utcnow() |
|
56 | user.last_login_date = datetime.datetime.utcnow() | |
57 | social_data = request.session.get('zigg.social_auth') |
|
57 | social_data = request.session.get('zigg.social_auth') | |
58 | if social_data: |
|
58 | if social_data: | |
59 | handle_social_data(request, user, social_data) |
|
59 | handle_social_data(request, user, social_data) | |
60 | else: |
|
60 | else: | |
61 | request.session.flash(_('Account got disabled')) |
|
61 | request.session.flash(_('Account got disabled')) | |
62 |
|
62 | |||
63 | if request.context.came_from != '/': |
|
63 | if request.context.came_from != '/': | |
64 | return HTTPFound(location=request.context.came_from, |
|
64 | return HTTPFound(location=request.context.came_from, | |
65 | headers=request.context.headers) |
|
65 | headers=request.context.headers) | |
66 | else: |
|
66 | else: | |
67 | return HTTPFound(location=request.route_url('/'), |
|
67 | return HTTPFound(location=request.route_url('/'), | |
68 | headers=request.context.headers) |
|
68 | headers=request.context.headers) | |
69 |
|
69 | |||
70 |
|
70 | |||
71 | @view_config(context=ZigguratSignInBadAuth, permission=NO_PERMISSION_REQUIRED) |
|
71 | @view_config(context=ZigguratSignInBadAuth, permission=NO_PERMISSION_REQUIRED) | |
72 | def bad_auth(request): |
|
72 | def bad_auth(request): | |
73 | """ |
|
73 | """ | |
74 | Handles incorrect login flow |
|
74 | Handles incorrect login flow | |
75 | """ |
|
75 | """ | |
76 | request.session.flash(_('Incorrect username or password'), 'warning') |
|
76 | request.session.flash(_('Incorrect username or password'), 'warning') | |
77 | return HTTPFound(location=request.route_url('register'), |
|
77 | return HTTPFound(location=request.route_url('register'), | |
78 | headers=request.context.headers) |
|
78 | headers=request.context.headers) | |
79 |
|
79 | |||
80 |
|
80 | |||
81 | @view_config(context=ZigguratSignOut, permission=NO_PERMISSION_REQUIRED) |
|
81 | @view_config(context=ZigguratSignOut, permission=NO_PERMISSION_REQUIRED) | |
82 | def sign_out(request): |
|
82 | def sign_out(request): | |
83 | """ |
|
83 | """ | |
84 | Removes user identification cookie |
|
84 | Removes user identification cookie | |
85 | """ |
|
85 | """ | |
86 | return HTTPFound(location=request.route_url('register'), |
|
86 | return HTTPFound(location=request.route_url('register'), | |
87 | headers=request.context.headers) |
|
87 | headers=request.context.headers) | |
88 |
|
88 | |||
89 |
|
89 | |||
90 | @view_config(route_name='lost_password', |
|
90 | @view_config(route_name='lost_password', | |
91 | renderer='appenlight:templates/user/lost_password.jinja2', |
|
91 | renderer='appenlight:templates/user/lost_password.jinja2', | |
92 | permission=NO_PERMISSION_REQUIRED) |
|
92 | permission=NO_PERMISSION_REQUIRED) | |
93 | def lost_password(request): |
|
93 | def lost_password(request): | |
94 | """ |
|
94 | """ | |
95 | Presents lost password page - sends password reset link to |
|
95 | Presents lost password page - sends password reset link to | |
96 | specified email address. |
|
96 | specified email address. | |
97 | This link is valid only for 10 minutes |
|
97 | This link is valid only for 10 minutes | |
98 | """ |
|
98 | """ | |
99 | form = forms.LostPasswordForm(request.POST, csrf_context=request) |
|
99 | form = forms.LostPasswordForm(request.POST, csrf_context=request) | |
100 | if request.method == 'POST' and form.validate(): |
|
100 | if request.method == 'POST' and form.validate(): | |
101 | user = User.by_email(form.email.data) |
|
101 | user = User.by_email(form.email.data) | |
102 | if user: |
|
102 | if user: | |
103 | user.regenerate_security_code() |
|
103 | user.regenerate_security_code() | |
104 | user.security_code_date = datetime.datetime.utcnow() |
|
104 | user.security_code_date = datetime.datetime.utcnow() | |
105 | email_vars = { |
|
105 | email_vars = { | |
106 | 'user': user, |
|
106 | 'user': user, | |
107 | 'request': request, |
|
107 | 'request': request, | |
108 | 'email_title': "App Enlight :: New password request" |
|
108 | 'email_title': "App Enlight :: New password request" | |
109 | } |
|
109 | } | |
110 | UserService.send_email( |
|
110 | UserService.send_email( | |
111 | request, recipients=[user.email], |
|
111 | request, recipients=[user.email], | |
112 | variables=email_vars, |
|
112 | variables=email_vars, | |
113 | template='/email_templates/lost_password.jinja2') |
|
113 | template='/email_templates/lost_password.jinja2') | |
114 | msg = 'Password reset email had been sent. ' \ |
|
114 | msg = 'Password reset email had been sent. ' \ | |
115 | 'Please check your mailbox for further instructions.' |
|
115 | 'Please check your mailbox for further instructions.' | |
116 | request.session.flash(_(msg)) |
|
116 | request.session.flash(_(msg)) | |
117 | return HTTPFound(location=request.route_url('lost_password')) |
|
117 | return HTTPFound(location=request.route_url('lost_password')) | |
118 | return {"form": form} |
|
118 | return {"form": form} | |
119 |
|
119 | |||
120 |
|
120 | |||
121 | @view_config(route_name='lost_password_generate', |
|
121 | @view_config(route_name='lost_password_generate', | |
122 | permission=NO_PERMISSION_REQUIRED, |
|
122 | permission=NO_PERMISSION_REQUIRED, | |
123 | renderer='appenlight:templates/user/lost_password_generate.jinja2') |
|
123 | renderer='appenlight:templates/user/lost_password_generate.jinja2') | |
124 | def lost_password_generate(request): |
|
124 | def lost_password_generate(request): | |
125 | """ |
|
125 | """ | |
126 | Shows new password form - perform time check and set new password for user |
|
126 | Shows new password form - perform time check and set new password for user | |
127 | """ |
|
127 | """ | |
128 | user = User.by_user_name_and_security_code( |
|
128 | user = User.by_user_name_and_security_code( | |
129 | request.GET.get('user_name'), request.GET.get('security_code')) |
|
129 | request.GET.get('user_name'), request.GET.get('security_code')) | |
130 | if user: |
|
130 | if user: | |
131 | delta = datetime.datetime.utcnow() - user.security_code_date |
|
131 | delta = datetime.datetime.utcnow() - user.security_code_date | |
132 |
|
132 | |||
133 | if user and delta.total_seconds() < 600: |
|
133 | if user and delta.total_seconds() < 600: | |
134 | form = forms.NewPasswordForm(request.POST, csrf_context=request) |
|
134 | form = forms.NewPasswordForm(request.POST, csrf_context=request) | |
135 | if request.method == "POST" and form.validate(): |
|
135 | if request.method == "POST" and form.validate(): | |
136 | user.set_password(form.new_password.data) |
|
136 | user.set_password(form.new_password.data) | |
137 | request.session.flash(_('You can sign in with your new password.')) |
|
137 | request.session.flash(_('You can sign in with your new password.')) | |
138 | return HTTPFound(location=request.route_url('register')) |
|
138 | return HTTPFound(location=request.route_url('register')) | |
139 | else: |
|
139 | else: | |
140 | return {"form": form} |
|
140 | return {"form": form} | |
141 | else: |
|
141 | else: | |
142 | return Response('Security code expired') |
|
142 | return Response('Security code expired') | |
143 |
|
143 | |||
144 |
|
144 | |||
145 | @view_config(route_name='register', |
|
145 | @view_config(route_name='register', | |
146 | renderer='appenlight:templates/user/register.jinja2', |
|
146 | renderer='appenlight:templates/user/register.jinja2', | |
147 | permission=NO_PERMISSION_REQUIRED) |
|
147 | permission=NO_PERMISSION_REQUIRED) | |
148 | def register(request): |
|
148 | def register(request): | |
149 | """ |
|
149 | """ | |
150 | Render register page with form |
|
150 | Render register page with form | |
151 | Also handles oAuth flow for registration |
|
151 | Also handles oAuth flow for registration | |
152 | """ |
|
152 | """ | |
153 | login_url = request.route_url('ziggurat.routes.sign_in') |
|
153 | login_url = request.route_url('ziggurat.routes.sign_in') | |
154 | if request.query_string: |
|
154 | if request.query_string: | |
155 | query_string = '?%s' % request.query_string |
|
155 | query_string = '?%s' % request.query_string | |
156 | else: |
|
156 | else: | |
157 | query_string = '' |
|
157 | query_string = '' | |
158 | referrer = '%s%s' % (request.path, query_string) |
|
158 | referrer = '%s%s' % (request.path, query_string) | |
159 |
|
159 | |||
160 | if referrer in [login_url, '/register', '/register?sign_in=1']: |
|
160 | if referrer in [login_url, '/register', '/register?sign_in=1']: | |
161 | referrer = '/' # never use the login form itself as came_from |
|
161 | referrer = '/' # never use the login form itself as came_from | |
162 | sign_in_form = forms.SignInForm( |
|
162 | sign_in_form = forms.SignInForm( | |
163 | came_from=request.params.get('came_from', referrer), |
|
163 | came_from=request.params.get('came_from', referrer), | |
164 | csrf_context=request) |
|
164 | csrf_context=request) | |
165 |
|
165 | |||
166 | # populate form from oAuth session data returned by authomatic |
|
166 | # populate form from oAuth session data returned by authomatic | |
167 | social_data = request.session.get('zigg.social_auth') |
|
167 | social_data = request.session.get('zigg.social_auth') | |
168 | if request.method != 'POST' and social_data: |
|
168 | if request.method != 'POST' and social_data: | |
169 | log.debug(social_data) |
|
169 | log.debug(social_data) | |
170 | user_name = social_data['user'].get('user_name', '').split('@')[0] |
|
170 | user_name = social_data['user'].get('user_name', '').split('@')[0] | |
171 | form_data = { |
|
171 | form_data = { | |
172 | 'user_name': user_name, |
|
172 | 'user_name': user_name, | |
173 | 'email': social_data['user'].get('email') |
|
173 | 'email': social_data['user'].get('email') | |
174 | } |
|
174 | } | |
175 | form_data['user_password'] = str(uuid.uuid4()) |
|
175 | form_data['user_password'] = str(uuid.uuid4()) | |
176 | form = forms.UserRegisterForm(MultiDict(form_data), |
|
176 | form = forms.UserRegisterForm(MultiDict(form_data), | |
177 | csrf_context=request) |
|
177 | csrf_context=request) | |
178 | form.user_password.widget.hide_value = False |
|
178 | form.user_password.widget.hide_value = False | |
179 | else: |
|
179 | else: | |
180 | form = forms.UserRegisterForm(request.POST, csrf_context=request) |
|
180 | form = forms.UserRegisterForm(request.POST, csrf_context=request) | |
181 | if request.method == 'POST' and form.validate(): |
|
181 | if request.method == 'POST' and form.validate(): | |
182 | log.info('registering user') |
|
182 | log.info('registering user') | |
183 | # insert new user here |
|
183 | # insert new user here | |
184 | new_user = User() |
|
184 | new_user = User() | |
185 | DBSession.add(new_user) |
|
185 | DBSession.add(new_user) | |
186 | form.populate_obj(new_user) |
|
186 | form.populate_obj(new_user) | |
187 | new_user.regenerate_security_code() |
|
187 | new_user.regenerate_security_code() | |
188 | new_user.status = 1 |
|
188 | new_user.status = 1 | |
189 | new_user.set_password(new_user.user_password) |
|
189 | new_user.set_password(new_user.user_password) | |
190 | new_user.registration_ip = request.environ.get('REMOTE_ADDR') |
|
190 | new_user.registration_ip = request.environ.get('REMOTE_ADDR') | |
191 |
|
191 | |||
192 | if social_data: |
|
192 | if social_data: | |
193 | handle_social_data(request, new_user, social_data) |
|
193 | handle_social_data(request, new_user, social_data) | |
194 |
|
194 | |||
195 | email_vars = {'user': new_user, |
|
195 | email_vars = {'user': new_user, | |
196 | 'request': request, |
|
196 | 'request': request, | |
197 | 'email_title': "App Enlight :: Start information"} |
|
197 | 'email_title': "App Enlight :: Start information"} | |
198 | UserService.send_email( |
|
198 | UserService.send_email( | |
199 | request, recipients=[new_user.email], variables=email_vars, |
|
199 | request, recipients=[new_user.email], variables=email_vars, | |
200 | template='/email_templates/registered.jinja2') |
|
200 | template='/email_templates/registered.jinja2') | |
201 | request.session.flash(_('You have successfully registered.')) |
|
201 | request.session.flash(_('You have successfully registered.')) | |
202 | DBSession.flush() |
|
202 | DBSession.flush() | |
203 | headers = security.remember(request, new_user.id) |
|
203 | headers = security.remember(request, new_user.id) | |
204 | return HTTPFound(location=request.route_url('/'), |
|
204 | return HTTPFound(location=request.route_url('/'), | |
205 | headers=headers) |
|
205 | headers=headers) | |
206 | settings = request.registry.settings |
|
206 | settings = request.registry.settings | |
207 | social_plugins = {} |
|
207 | social_plugins = {} | |
208 | if settings.get('authomatic.pr.twitter.key', ''): |
|
208 | if settings.get('authomatic.pr.twitter.key', ''): | |
209 | social_plugins['twitter'] = True |
|
209 | social_plugins['twitter'] = True | |
210 | if settings.get('authomatic.pr.google.key', ''): |
|
210 | if settings.get('authomatic.pr.google.key', ''): | |
211 | social_plugins['google'] = True |
|
211 | social_plugins['google'] = True | |
212 | if settings.get('authomatic.pr.github.key', ''): |
|
212 | if settings.get('authomatic.pr.github.key', ''): | |
213 | social_plugins['github'] = True |
|
213 | social_plugins['github'] = True | |
214 | if settings.get('authomatic.pr.bitbucket.key', ''): |
|
214 | if settings.get('authomatic.pr.bitbucket.key', ''): | |
215 | social_plugins['bitbucket'] = True |
|
215 | social_plugins['bitbucket'] = True | |
216 |
|
216 | |||
217 | return { |
|
217 | return { | |
218 | "form": form, |
|
218 | "form": form, | |
219 | "sign_in_form": sign_in_form, |
|
219 | "sign_in_form": sign_in_form, | |
220 | "social_plugins": social_plugins |
|
220 | "social_plugins": social_plugins | |
221 | } |
|
221 | } | |
222 |
|
222 | |||
223 |
|
223 | |||
224 | @view_config(route_name='/', |
|
224 | @view_config(route_name='/', | |
225 | renderer='appenlight:templates/dashboard/index.jinja2', |
|
225 | renderer='appenlight:templates/dashboard/index.jinja2', | |
226 | permission=NO_PERMISSION_REQUIRED) |
|
226 | permission=NO_PERMISSION_REQUIRED) | |
227 | @view_config(route_name='angular_app_ui', |
|
227 | @view_config(route_name='angular_app_ui', | |
228 | renderer='appenlight:templates/dashboard/index.jinja2', |
|
228 | renderer='appenlight:templates/dashboard/index.jinja2', | |
229 | permission=NO_PERMISSION_REQUIRED) |
|
229 | permission=NO_PERMISSION_REQUIRED) | |
230 | @view_config(route_name='angular_app_ui_ix', |
|
230 | @view_config(route_name='angular_app_ui_ix', | |
231 | renderer='appenlight:templates/dashboard/index.jinja2', |
|
231 | renderer='appenlight:templates/dashboard/index.jinja2', | |
232 | permission=NO_PERMISSION_REQUIRED) |
|
232 | permission=NO_PERMISSION_REQUIRED) | |
233 | def app_main_index(request): |
|
233 | def app_main_index(request): | |
234 | """ |
|
234 | """ | |
235 | Render dashoard/report browser page page along with: |
|
235 | Render dashoard/report browser page page along with: | |
236 | - flash messages |
|
236 | - flash messages | |
237 | - application list |
|
237 | - application list | |
238 | - assigned reports |
|
238 | - assigned reports | |
239 | - latest events |
|
239 | - latest events | |
240 | (those last two come from subscribers.py that sets global renderer variables) |
|
240 | (those last two come from subscribers.py that sets global renderer variables) | |
241 | """ |
|
241 | """ | |
242 |
|
242 | return {} | ||
243 | if request.user: |
|
|||
244 | request.user.last_login_date = datetime.datetime.utcnow() |
|
|||
245 | applications = request.user.resources_with_perms( |
|
|||
246 | ['view'], resource_types=['application']) |
|
|||
247 | # convert for angular |
|
|||
248 | applications = dict( |
|
|||
249 | [(a.resource_id, a.resource_name) for a in applications.all()] |
|
|||
250 | ) |
|
|||
251 | else: |
|
|||
252 | applications = {} |
|
|||
253 | return { |
|
|||
254 | 'applications': applications |
|
|||
255 | } |
|
General Comments 0
You need to be logged in to leave comments.
Login now