##// END OF EJS Templates
fixed menu in home page, and added login html with forms that validates username and password.
marcink -
r186:556473ba default
parent child Browse files
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 select use formencode.All(OneOf(list), Int())
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, search_number=value), value, 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}">&darr;</a>
24 <a href="?sort=${name_slug}">&darr;</a>
28 <a href="?sort=-${name_slug}">&uarr;</a>
25 <a href="?sort=-${name_slug}">&uarr;</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