Show More
@@ -0,0 +1,37 b'' | |||||
|
1 | import logging | |||
|
2 | from formencode import htmlfill | |||
|
3 | from pylons import request, response, session, tmpl_context as c, url | |||
|
4 | from pylons.controllers.util import abort, redirect | |||
|
5 | from pylons_app.lib.base import BaseController, render | |||
|
6 | import formencode | |||
|
7 | from pylons_app.model.forms import LoginForm | |||
|
8 | from pylons_app.lib.auth import AuthUser | |||
|
9 | ||||
|
10 | log = logging.getLogger(__name__) | |||
|
11 | ||||
|
12 | class LoginController(BaseController): | |||
|
13 | ||||
|
14 | def index(self): | |||
|
15 | if session.get('hg_app_user', AuthUser()).is_authenticated: | |||
|
16 | return redirect(url('hg_home')) | |||
|
17 | ||||
|
18 | if request.POST: | |||
|
19 | #import Login Form validator class | |||
|
20 | login_form = LoginForm() | |||
|
21 | try: | |||
|
22 | c.form_result = login_form.to_python(dict(request.POST)) | |||
|
23 | return redirect(url('hg_home')) | |||
|
24 | ||||
|
25 | except formencode.Invalid as errors: | |||
|
26 | c.form_errors = errors.error_dict | |||
|
27 | return htmlfill.render( | |||
|
28 | render('/login.html'), | |||
|
29 | defaults=errors.value, | |||
|
30 | encoding="UTF-8") | |||
|
31 | ||||
|
32 | return render('/login.html') | |||
|
33 | ||||
|
34 | def logout(self): | |||
|
35 | session['hg_app_user'] = AuthUser() | |||
|
36 | session.save() | |||
|
37 | redirect(url('hg_home')) |
@@ -0,0 +1,42 b'' | |||||
|
1 | ## -*- coding: utf-8 -*- | |||
|
2 | <%! | |||
|
3 | from pylons_app.lib import filters | |||
|
4 | %> | |||
|
5 | <%inherit file="base/base.html"/> | |||
|
6 | <%def name="title()"> | |||
|
7 | ${c.repos_prefix} Mercurial Repositories | |||
|
8 | </%def> | |||
|
9 | <%def name="breadcrumbs()"> | |||
|
10 | ${c.repos_prefix} Mercurial Repositories | |||
|
11 | </%def> | |||
|
12 | <%def name="page_nav()"> | |||
|
13 | ${self.menu('home')} | |||
|
14 | </%def> | |||
|
15 | <%def name="main()"> | |||
|
16 | <div> | |||
|
17 | <br /> | |||
|
18 | <h2>${_('Login')}</h2> | |||
|
19 | ${h.form(h.url.current())} | |||
|
20 | <table> | |||
|
21 | <tr> | |||
|
22 | <td>${_('Username')}</td> | |||
|
23 | <td>${h.text('username')}</td> | |||
|
24 | <td>${self.get_form_error('username')} | |||
|
25 | ||||
|
26 | </td> | |||
|
27 | </tr> | |||
|
28 | <tr> | |||
|
29 | <td>${_('Password')}</td> | |||
|
30 | <td>${h.password('password')}</td> | |||
|
31 | <td>${self.get_form_error('password')}</td> | |||
|
32 | </tr> | |||
|
33 | <tr> | |||
|
34 | <td></td> | |||
|
35 | <td>${h.submit('login','login')}</td> | |||
|
36 | </tr> | |||
|
37 | </table> | |||
|
38 | ${h.end_form()} | |||
|
39 | </div> | |||
|
40 | </%def> | |||
|
41 | ||||
|
42 |
@@ -1,58 +1,126 b'' | |||||
1 | """ this is forms validation classes |
|
1 | """ this is forms validation classes | |
2 | http://formencode.org/module-formencode.validators.html |
|
2 | http://formencode.org/module-formencode.validators.html | |
3 | for list off all availible validators |
|
3 | for list off all availible validators | |
4 |
|
4 | |||
5 | we can create our own validators |
|
5 | we can create our own validators | |
6 |
|
6 | |||
7 | The table below outlines the options which can be used in a schema in addition to the validators themselves |
|
7 | The table below outlines the options which can be used in a schema in addition to the validators themselves | |
8 | pre_validators [] These validators will be applied before the schema |
|
8 | pre_validators [] These validators will be applied before the schema | |
9 | chained_validators [] These validators will be applied after the schema |
|
9 | chained_validators [] These validators will be applied after the schema | |
10 | allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present |
|
10 | allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present | |
11 | filter_extra_fields False If True, then keys that aren't associated with a validator are removed |
|
11 | filter_extra_fields False If True, then keys that aren't associated with a validator are removed | |
12 | if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value. |
|
12 | if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value. | |
13 | ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already |
|
13 | ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already | |
14 |
|
14 | |||
15 |
|
15 | |||
16 | <name> = formencode.validators.<name of validator> |
|
16 | <name> = formencode.validators.<name of validator> | |
17 | <name> must equal form name |
|
17 | <name> must equal form name | |
18 | list=[1,2,3,4,5] |
|
18 | list=[1,2,3,4,5] | |
19 |
for |
|
19 | for SELECT use formencode.All(OneOf(list), Int()) | |
20 |
|
20 | |||
21 | """ |
|
21 | """ | |
22 |
|
22 | from formencode.validators import UnicodeString, OneOf, Int, Number, Regex | ||
|
23 | from pylons import session | |||
|
24 | from pylons.i18n.translation import _ | |||
|
25 | from pylons_app.lib.auth import get_crypt_password | |||
|
26 | from pylons_app.model import meta | |||
|
27 | from pylons_app.model.db import Users | |||
|
28 | from sqlalchemy.exc import OperationalError | |||
|
29 | from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound | |||
|
30 | from webhelpers.pylonslib.secure_form import authentication_token | |||
23 | import formencode |
|
31 | import formencode | |
24 | from formencode.validators import UnicodeString, OneOf, Int, Number, Regex |
|
32 | import logging | |
25 | from pylons.i18n.translation import _ |
|
33 | log = logging.getLogger(__name__) | |
26 | from webhelpers.pylonslib.secure_form import authentication_token |
|
34 | ||
27 |
|
35 | |||
|
36 | #this is needed to translate the messages using _() in validators | |||
|
37 | class State_obj(object): | |||
|
38 | _ = staticmethod(_) | |||
|
39 | ||||
|
40 | #=============================================================================== | |||
|
41 | # VALIDATORS | |||
|
42 | #=============================================================================== | |||
28 | class ValidAuthToken(formencode.validators.FancyValidator): |
|
43 | class ValidAuthToken(formencode.validators.FancyValidator): | |
29 | messages = {'invalid_token':_('Token mismatch')} |
|
44 | messages = {'invalid_token':_('Token mismatch')} | |
30 |
|
45 | |||
31 | def validate_python(self, value, state): |
|
46 | def validate_python(self, value, state): | |
32 |
|
47 | |||
33 | if value != authentication_token(): |
|
48 | if value != authentication_token(): | |
34 |
raise formencode.Invalid(self.message('invalid_token', state, |
|
49 | raise formencode.Invalid(self.message('invalid_token', state, | |
|
50 | search_number=value), value, state) | |||
|
51 | ||||
|
52 | class ValidAuth(formencode.validators.FancyValidator): | |||
|
53 | messages = { | |||
|
54 | 'invalid_password':_('invalid password'), | |||
|
55 | 'invalid_login':_('invalid user name'), | |||
|
56 | 'disabled_account':_('Your acccount is disabled') | |||
|
57 | ||||
|
58 | } | |||
|
59 | #error mapping | |||
|
60 | e_dict = {'username':messages['invalid_login'], | |||
|
61 | 'password':messages['invalid_password']} | |||
|
62 | ||||
|
63 | def validate_python(self, value, state): | |||
|
64 | sa = meta.Session | |||
|
65 | crypted_passwd = get_crypt_password(value['password']) | |||
|
66 | username = value['username'] | |||
|
67 | try: | |||
|
68 | user = sa.query(Users).filter(Users.username == username).one() | |||
|
69 | except (NoResultFound, MultipleResultsFound, OperationalError) as e: | |||
|
70 | log.error(e) | |||
|
71 | user = None | |||
|
72 | print value | |||
|
73 | if user: | |||
|
74 | if user.active: | |||
|
75 | if user.username == username and user.password == crypted_passwd: | |||
|
76 | log.info('user %s authenticated correctly', username) | |||
|
77 | from pylons_app.lib.auth import AuthUser | |||
|
78 | auth_user = AuthUser() | |||
|
79 | auth_user.username = username | |||
|
80 | auth_user.is_authenticated = True | |||
|
81 | auth_user.is_admin = user.admin | |||
|
82 | session['hg_app_user'] = auth_user | |||
|
83 | session.save() | |||
|
84 | return value | |||
|
85 | else: | |||
|
86 | log.warning('user %s not authenticated', username) | |||
|
87 | raise formencode.Invalid(self.message('invalid_password', | |||
|
88 | state=State_obj), value, state, | |||
|
89 | error_dict=self.e_dict) | |||
|
90 | else: | |||
|
91 | log.warning('user %s is disabled', username) | |||
|
92 | raise formencode.Invalid(self.message('disabled_account', | |||
|
93 | state=State_obj), | |||
|
94 | value, state, error_dict=self.e_dict) | |||
35 |
|
95 | |||
36 |
|
96 | |||
|
97 | ||||
|
98 | #=============================================================================== | |||
|
99 | # FORMS | |||
|
100 | #=============================================================================== | |||
37 | class LoginForm(formencode.Schema): |
|
101 | class LoginForm(formencode.Schema): | |
38 | allow_extra_fields = True |
|
102 | allow_extra_fields = True | |
39 | filter_extra_fields = True |
|
103 | filter_extra_fields = True | |
40 | username = UnicodeString( |
|
104 | username = UnicodeString( | |
41 | strip=True, |
|
105 | strip=True, | |
42 | min=3, |
|
106 | min=3, | |
43 | not_empty=True, |
|
107 | not_empty=True, | |
44 | messages={ |
|
108 | messages={ | |
45 | 'empty':_('Please enter a login'), |
|
109 | 'empty':_('Please enter a login'), | |
46 | 'tooShort':_('Enter a value %(min)i characters long or more')} |
|
110 | 'tooShort':_('Enter a value %(min)i characters long or more')} | |
47 | ) |
|
111 | ) | |
48 |
|
112 | |||
49 | password = UnicodeString( |
|
113 | password = UnicodeString( | |
50 | strip=True, |
|
114 | strip=True, | |
51 | min=3, |
|
115 | min=3, | |
52 | not_empty=True, |
|
116 | not_empty=True, | |
53 | messages={ |
|
117 | messages={ | |
54 | 'empty':_('Please enter a password'), |
|
118 | 'empty':_('Please enter a password'), | |
55 | 'tooShort':_('Enter a value %(min)i characters long or more')} |
|
119 | 'tooShort':_('Enter a value %(min)i characters long or more')} | |
56 | ) |
|
120 | ) | |
57 |
|
121 | |||
58 |
|
122 | |||
|
123 | #chained validators have access to all data | |||
|
124 | chained_validators = [ValidAuth] | |||
|
125 | ||||
|
126 |
@@ -1,63 +1,60 b'' | |||||
1 | ## -*- coding: utf-8 -*- |
|
1 | ## -*- coding: utf-8 -*- | |
2 | <%! |
|
2 | <%! | |
3 | from pylons_app.lib import filters |
|
3 | from pylons_app.lib import filters | |
4 | %> |
|
4 | %> | |
5 | <%inherit file="base/base.html"/> |
|
5 | <%inherit file="base/base.html"/> | |
6 | <%def name="title()"> |
|
6 | <%def name="title()"> | |
7 | ${c.repos_prefix} Mercurial Repositories |
|
7 | ${c.repos_prefix} Mercurial Repositories | |
8 | </%def> |
|
8 | </%def> | |
9 | <%def name="breadcrumbs()"> |
|
9 | <%def name="breadcrumbs()"> | |
10 | ${c.repos_prefix} Mercurial Repositories |
|
10 | ${c.repos_prefix} Mercurial Repositories | |
11 | </%def> |
|
11 | </%def> | |
12 | <%def name="page_nav()"> |
|
12 | <%def name="page_nav()"> | |
13 | <ul class="page-nav"> |
|
13 | ${self.menu('home')} | |
14 | <li class="current">${_('Home')}</li> |
|
|||
15 | <li>${h.link_to(u'Admin',h.url('admin_home'))}</li> |
|
|||
16 | </ul> |
|
|||
17 | </%def> |
|
14 | </%def> | |
18 | <%def name="main()"> |
|
15 | <%def name="main()"> | |
19 | <%def name="get_sort(name)"> |
|
16 | <%def name="get_sort(name)"> | |
20 | <%name_slug = name.lower().replace(' ','_') %> |
|
17 | <%name_slug = name.lower().replace(' ','_') %> | |
21 | %if name_slug == c.cs_slug: |
|
18 | %if name_slug == c.cs_slug: | |
22 | <span style="font-weight: bold;color:#006699">${name}</span> |
|
19 | <span style="font-weight: bold;color:#006699">${name}</span> | |
23 | %else: |
|
20 | %else: | |
24 | <span style="font-weight: bold">${name}</span> |
|
21 | <span style="font-weight: bold">${name}</span> | |
25 | %endif |
|
22 | %endif | |
26 |
|
23 | |||
27 | <a href="?sort=${name_slug}">↓</a> |
|
24 | <a href="?sort=${name_slug}">↓</a> | |
28 | <a href="?sort=-${name_slug}">↑</a> |
|
25 | <a href="?sort=-${name_slug}">↑</a> | |
29 |
|
26 | |||
30 | </%def> |
|
27 | </%def> | |
31 | <table> |
|
28 | <table> | |
32 | <tr> |
|
29 | <tr> | |
33 | <td>${get_sort(_('Name'))}</td> |
|
30 | <td>${get_sort(_('Name'))}</td> | |
34 | <td>${get_sort(_('Description'))}</td> |
|
31 | <td>${get_sort(_('Description'))}</td> | |
35 | <td>${get_sort(_('Last change'))}</td> |
|
32 | <td>${get_sort(_('Last change'))}</td> | |
36 | <td>${get_sort(_('Tip'))}</td> |
|
33 | <td>${get_sort(_('Tip'))}</td> | |
37 | <td>${get_sort(_('Contact'))}</td> |
|
34 | <td>${get_sort(_('Contact'))}</td> | |
38 | <td></td> |
|
35 | <td></td> | |
39 | <td></td> |
|
36 | <td></td> | |
40 | <td></td> |
|
37 | <td></td> | |
41 | </tr> |
|
38 | </tr> | |
42 | %for cnt,repo in enumerate(c.repos_list): |
|
39 | %for cnt,repo in enumerate(c.repos_list): | |
43 | <tr class="parity${cnt%2}"> |
|
40 | <tr class="parity${cnt%2}"> | |
44 | <td>${h.link(repo['name'],h.url('summary_home',repo_name=repo['name']))}</td> |
|
41 | <td>${h.link(repo['name'],h.url('summary_home',repo_name=repo['name']))}</td> | |
45 | <td>${repo['description']}</td> |
|
42 | <td>${repo['description']}</td> | |
46 | <td>${repo['last_change']|n,filters.age}</td> |
|
43 | <td>${repo['last_change']|n,filters.age}</td> | |
47 | <td>r${repo['rev']}:<a href="/${repo['name']}/rev/${repo['tip']}/">${repo['tip']}</a></td> |
|
44 | <td>r${repo['rev']}:<a href="/${repo['name']}/rev/${repo['tip']}/">${repo['tip']}</a></td> | |
48 | <td>${repo['contact']}</td> |
|
45 | <td>${repo['contact']}</td> | |
49 | <td class="indexlinks"> |
|
46 | <td class="indexlinks"> | |
50 | %for archive in repo['repo_archives']: |
|
47 | %for archive in repo['repo_archives']: | |
51 | <a href="/${repo['name']}/archive/${archive['node']}${archive['extension']}">${archive['type']}</a> |
|
48 | <a href="/${repo['name']}/archive/${archive['node']}${archive['extension']}">${archive['type']}</a> | |
52 | %endfor |
|
49 | %endfor | |
53 | </td> |
|
50 | </td> | |
54 | <td> |
|
51 | <td> | |
55 | <a class="rss_logo" href="/${repo['name']}/rss-log">RSS</a> |
|
52 | <a class="rss_logo" href="/${repo['name']}/rss-log">RSS</a> | |
56 | </td> |
|
53 | </td> | |
57 | <td> |
|
54 | <td> | |
58 | <a class="atom_logo" href="/${repo['name']}/atom-log">Atom</a> |
|
55 | <a class="atom_logo" href="/${repo['name']}/atom-log">Atom</a> | |
59 | </td> |
|
56 | </td> | |
60 | </tr> |
|
57 | </tr> | |
61 | %endfor |
|
58 | %endfor | |
62 | </table> |
|
59 | </table> | |
63 | </%def> |
|
60 | </%def> |
General Comments 0
You need to be logged in to leave comments.
Login now