##// END OF EJS Templates
Added rest controllers for repos and users,...
Marcin Kuzminski -
r47:f6ac7918 default
parent child Browse files
Show More
@@ -0,0 +1,57 b''
1 import logging
2
3 from pylons import request, response, session, tmpl_context as c, url, app_globals as g
4 from pylons.controllers.util import abort, redirect
5 from pylons_app.lib import auth
6 from pylons_app.lib.base import BaseController, render
7
8 log = logging.getLogger(__name__)
9
10 class ReposController(BaseController):
11 """REST Controller styled on the Atom Publishing Protocol"""
12 # To properly map this controller, ensure your config/routing.py
13 # file has a resource setup:
14 # map.resource('repo', 'repos')
15 def __before__(self):
16 c.staticurl = g.statics
17 c.admin_user = session.get('admin_user')
18 c.admin_username = session.get('admin_username')
19
20 def index(self, format='html'):
21 """GET /repos: All items in the collection"""
22 # url('repos')
23 return render('/repos_manage.html')
24
25 def create(self):
26 """POST /repos: Create a new item"""
27 # url('repos')
28
29 def new(self, format='html'):
30 """GET /repos/new: Form to create a new item"""
31 # url('new_repo')
32
33 def update(self, id):
34 """PUT /repos/id: Update an existing item"""
35 # Forms posted to this method should contain a hidden field:
36 # <input type="hidden" name="_method" value="PUT" />
37 # Or using helpers:
38 # h.form(url('repo', id=ID),
39 # method='put')
40 # url('repo', id=ID)
41
42 def delete(self, id):
43 """DELETE /repos/id: Delete an existing item"""
44 # Forms posted to this method should contain a hidden field:
45 # <input type="hidden" name="_method" value="DELETE" />
46 # Or using helpers:
47 # h.form(url('repo', id=ID),
48 # method='delete')
49 # url('repo', id=ID)
50
51 def show(self, id, format='html'):
52 """GET /repos/id: Show a specific item"""
53 # url('repo', id=ID)
54
55 def edit(self, id, format='html'):
56 """GET /repos/id/edit: Form to edit an existing item"""
57 # url('edit_repo', id=ID)
@@ -0,0 +1,60 b''
1 import logging
2
3 from pylons import request, response, session, tmpl_context as c, url, app_globals as g
4 from pylons.controllers.util import abort, redirect
5
6 from pylons_app.lib.base import BaseController, render
7 from pylons_app.lib import auth
8 log = logging.getLogger(__name__)
9
10 class UsersController(BaseController):
11 """REST Controller styled on the Atom Publishing Protocol"""
12 # To properly map this controller, ensure your config/routing.py
13 # file has a resource setup:
14 # map.resource('user', 'users')
15 def __before__(self):
16 c.staticurl = g.statics
17 c.admin_user = session.get('admin_user')
18 c.admin_username = session.get('admin_username')
19
20 def index(self, format='html'):
21 """GET /users: All items in the collection"""
22 # url('users')
23 conn, cur = auth.get_sqlite_conn_cur()
24 cur.execute('SELECT * FROM users')
25 c.users_list = cur.fetchall()
26 return render('/users_manage.html')
27
28 def create(self):
29 """POST /users: Create a new item"""
30 # url('users')
31
32 def new(self, format='html'):
33 """GET /users/new: Form to create a new item"""
34 # url('new_user')
35
36 def update(self, id):
37 """PUT /users/id: Update an existing item"""
38 # Forms posted to this method should contain a hidden field:
39 # <input type="hidden" name="_method" value="PUT" />
40 # Or using helpers:
41 # h.form(url('user', id=ID),
42 # method='put')
43 # url('user', id=ID)
44
45 def delete(self, id):
46 """DELETE /users/id: Delete an existing item"""
47 # Forms posted to this method should contain a hidden field:
48 # <input type="hidden" name="_method" value="DELETE" />
49 # Or using helpers:
50 # h.form(url('user', id=ID),
51 # method='delete')
52 # url('user', id=ID)
53
54 def show(self, id, format='html'):
55 """GET /users/id: Show a specific item"""
56 # url('user', id=ID)
57
58 def edit(self, id, format='html'):
59 """GET /users/id/edit: Form to edit an existing item"""
60 # url('edit_user', id=ID)
@@ -0,0 +1,43 b''
1 from pylons_app.tests import *
2
3 class TestReposController(TestController):
4
5 def test_index(self):
6 response = self.app.get(url('repos'))
7 # Test response...
8
9 def test_index_as_xml(self):
10 response = self.app.get(url('formatted_repos', format='xml'))
11
12 def test_create(self):
13 response = self.app.post(url('repos'))
14
15 def test_new(self):
16 response = self.app.get(url('new_repo'))
17
18 def test_new_as_xml(self):
19 response = self.app.get(url('formatted_new_repo', format='xml'))
20
21 def test_update(self):
22 response = self.app.put(url('repo', id=1))
23
24 def test_update_browser_fakeout(self):
25 response = self.app.post(url('repo', id=1), params=dict(_method='put'))
26
27 def test_delete(self):
28 response = self.app.delete(url('repo', id=1))
29
30 def test_delete_browser_fakeout(self):
31 response = self.app.post(url('repo', id=1), params=dict(_method='delete'))
32
33 def test_show(self):
34 response = self.app.get(url('repo', id=1))
35
36 def test_show_as_xml(self):
37 response = self.app.get(url('formatted_repo', id=1, format='xml'))
38
39 def test_edit(self):
40 response = self.app.get(url('edit_repo', id=1))
41
42 def test_edit_as_xml(self):
43 response = self.app.get(url('formatted_edit_repo', id=1, format='xml'))
@@ -0,0 +1,43 b''
1 from pylons_app.tests import *
2
3 class TestUsersController(TestController):
4
5 def test_index(self):
6 response = self.app.get(url('users'))
7 # Test response...
8
9 def test_index_as_xml(self):
10 response = self.app.get(url('formatted_users', format='xml'))
11
12 def test_create(self):
13 response = self.app.post(url('users'))
14
15 def test_new(self):
16 response = self.app.get(url('new_user'))
17
18 def test_new_as_xml(self):
19 response = self.app.get(url('formatted_new_user', format='xml'))
20
21 def test_update(self):
22 response = self.app.put(url('user', id=1))
23
24 def test_update_browser_fakeout(self):
25 response = self.app.post(url('user', id=1), params=dict(_method='put'))
26
27 def test_delete(self):
28 response = self.app.delete(url('user', id=1))
29
30 def test_delete_browser_fakeout(self):
31 response = self.app.post(url('user', id=1), params=dict(_method='delete'))
32
33 def test_show(self):
34 response = self.app.get(url('user', id=1))
35
36 def test_show_as_xml(self):
37 response = self.app.get(url('formatted_user', id=1, format='xml'))
38
39 def test_edit(self):
40 response = self.app.get(url('edit_user', id=1))
41
42 def test_edit_as_xml(self):
43 response = self.app.get(url('formatted_edit_user', id=1, format='xml'))
@@ -1,31 +1,32 b''
1 """Routes configuration
1 """Routes configuration
2
2
3 The more specific and detailed routes should be defined first so they
3 The more specific and detailed routes should be defined first so they
4 may take precedent over the more generic routes. For more information
4 may take precedent over the more generic routes. For more information
5 refer to the routes manual at http://routes.groovie.org/docs/
5 refer to the routes manual at http://routes.groovie.org/docs/
6 """
6 """
7 from routes import Mapper
7 from routes import Mapper
8
8
9 def make_map(config):
9 def make_map(config):
10 """Create, configure and return the routes Mapper"""
10 """Create, configure and return the routes Mapper"""
11 map = Mapper(directory=config['pylons.paths']['controllers'],
11 map = Mapper(directory=config['pylons.paths']['controllers'],
12 always_scan=config['debug'])
12 always_scan=config['debug'])
13 map.minimization = False
13 map.minimization = False
14 map.explicit = False
14 map.explicit = False
15
15
16 # The ErrorController route (handles 404/500 error pages); it should
16 # The ErrorController route (handles 404/500 error pages); it should
17 # likely stay at the top, ensuring it can always be resolved
17 # likely stay at the top, ensuring it can always be resolved
18 map.connect('/error/{action}', controller='error')
18 map.connect('/error/{action}', controller='error')
19 map.connect('/error/{action}/{id}', controller='error')
19 map.connect('/error/{action}/{id}', controller='error')
20
20
21 # CUSTOM ROUTES HERE
21 # CUSTOM ROUTES HERE
22 with map.submapper(path_prefix='/_admin', controller='admin') as m:
22 with map.submapper(path_prefix='/_admin', controller='admin') as m:
23 m.connect('admin_home', '/', action='index')#main page
23 m.connect('admin_home', '/', action='index')#main page
24 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}', action='add_repo')
24 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}', action='add_repo')
25 m.connect('admin_users_manage', '/repos_manage', action='users_manage')
25
26 m.connect('admin_repos_manage', '/users_manage', action='repos_manage')
26 map.resource('repo', 'repos', path_prefix='/_admin')
27 map.resource('user', 'users', path_prefix='/_admin')
27
28
28 map.connect('hg', '/{path_info:.*}', controller='hg',
29 map.connect('hg', '/{path_info:.*}', controller='hg',
29 action="view", path_info='/')
30 action="view", path_info='/')
30
31
31 return map
32 return map
@@ -1,127 +1,115 b''
1 import logging
1 import logging
2
2
3 from pylons import request, response, session, tmpl_context as c, url, app_globals as g
3 from pylons import request, response, session, tmpl_context as c, url, app_globals as g
4 from pylons.controllers.util import abort, redirect
4 from pylons.controllers.util import abort, redirect
5
5
6 from pylons_app.lib.base import BaseController, render
6 from pylons_app.lib.base import BaseController, render
7 import os
7 import os
8 from mercurial import ui, hg
8 from mercurial import ui, hg
9 from mercurial.error import RepoError
9 from mercurial.error import RepoError
10 from ConfigParser import ConfigParser
10 from ConfigParser import ConfigParser
11 from pylons_app.lib import auth
11 from pylons_app.lib import auth
12 from pylons_app.model.forms import LoginForm
12 from pylons_app.model.forms import LoginForm
13 import formencode
13 import formencode
14 import formencode.htmlfill as htmlfill
14 import formencode.htmlfill as htmlfill
15 log = logging.getLogger(__name__)
15 log = logging.getLogger(__name__)
16
16
17 class AdminController(BaseController):
17 class AdminController(BaseController):
18
18
19
19
20 def __before__(self):
20 def __before__(self):
21 c.staticurl = g.statics
21 c.staticurl = g.statics
22 c.admin_user = session.get('admin_user')
22 c.admin_user = session.get('admin_user')
23 c.admin_username = session.get('admin_username')
23 c.admin_username = session.get('admin_username')
24
24
25 def index(self):
25 def index(self):
26 # Return a rendered template
26 # Return a rendered template
27 if request.POST:
27 if request.POST:
28 #import Login Form validator class
28 #import Login Form validator class
29 login_form = LoginForm()
29 login_form = LoginForm()
30
30
31 try:
31 try:
32 c.form_result = login_form.to_python(dict(request.params))
32 c.form_result = login_form.to_python(dict(request.params))
33 if auth.admin_auth(c.form_result['username'], c.form_result['password']):
33 if auth.admin_auth(c.form_result['username'], c.form_result['password']):
34 session['admin_user'] = True
34 session['admin_user'] = True
35 session['admin_username'] = c.form_result['username']
35 session['admin_username'] = c.form_result['username']
36 session.save()
36 session.save()
37 return redirect(url('admin_home'))
37 return redirect(url('admin_home'))
38 else:
38 else:
39 raise formencode.Invalid('Login Error', None, None,
39 raise formencode.Invalid('Login Error', None, None,
40 error_dict={'username':'invalid login',
40 error_dict={'username':'invalid login',
41 'password':'invalid password'})
41 'password':'invalid password'})
42
42
43 except formencode.Invalid, error:
43 except formencode.Invalid, error:
44 c.form_result = error.value
44 c.form_result = error.value
45 c.form_errors = error.error_dict or {}
45 c.form_errors = error.error_dict or {}
46 html = render('/admin.html')
46 html = render('/admin.html')
47
47
48 return htmlfill.render(
48 return htmlfill.render(
49 html,
49 html,
50 defaults=c.form_result,
50 defaults=c.form_result,
51 encoding="UTF-8"
51 encoding="UTF-8"
52 )
52 )
53 return render('/admin.html')
53 return render('/admin.html')
54
54
55 def repos_manage(self):
56 return render('/repos_manage.html')
57
58 def users_manage(self):
59 conn, cur = auth.get_sqlite_conn_cur()
60 cur.execute('SELECT * FROM users')
61 c.users_list = cur.fetchall()
62 return render('/users_manage.html')
63
64 def manage_hgrc(self):
65 pass
66
67 def hgrc(self, dirname):
55 def hgrc(self, dirname):
68 filename = os.path.join(dirname, '.hg', 'hgrc')
56 filename = os.path.join(dirname, '.hg', 'hgrc')
69 return filename
57 return filename
70
58
71 def add_repo(self, new_repo):
59 def add_repo(self, new_repo):
72
60
73
61
74 #extra check it can be add since it's the command
62 #extra check it can be add since it's the command
75 if new_repo == '_admin':
63 if new_repo == '_admin':
76 c.msg = 'DENIED'
64 c.msg = 'DENIED'
77 c.new_repo = ''
65 c.new_repo = ''
78 return render('add.html')
66 return render('add.html')
79
67
80 new_repo = new_repo.replace(" ", "_")
68 new_repo = new_repo.replace(" ", "_")
81 new_repo = new_repo.replace("-", "_")
69 new_repo = new_repo.replace("-", "_")
82
70
83 try:
71 try:
84 self._create_repo(new_repo)
72 self._create_repo(new_repo)
85 c.new_repo = new_repo
73 c.new_repo = new_repo
86 c.msg = 'added repo'
74 c.msg = 'added repo'
87 except Exception as e:
75 except Exception as e:
88 c.new_repo = 'Exception when adding: %s' % new_repo
76 c.new_repo = 'Exception when adding: %s' % new_repo
89 c.msg = str(e)
77 c.msg = str(e)
90
78
91 return render('add.html')
79 return render('add.html')
92
80
93 def _check_repo(self, repo_name):
81 def _check_repo(self, repo_name):
94 p = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
82 p = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
95 config_path = os.path.join(p, 'hgwebdir.config')
83 config_path = os.path.join(p, 'hgwebdir.config')
96
84
97 cp = ConfigParser()
85 cp = ConfigParser()
98
86
99 cp.read(config_path)
87 cp.read(config_path)
100 repos_path = cp.get('paths', '/').replace("**", '')
88 repos_path = cp.get('paths', '/').replace("**", '')
101
89
102 if not repos_path:
90 if not repos_path:
103 raise Exception('Could not read config !')
91 raise Exception('Could not read config !')
104
92
105 self.repo_path = os.path.join(repos_path, repo_name)
93 self.repo_path = os.path.join(repos_path, repo_name)
106
94
107 try:
95 try:
108 r = hg.repository(ui.ui(), self.repo_path)
96 r = hg.repository(ui.ui(), self.repo_path)
109 hg.verify(r)
97 hg.verify(r)
110 #here we hnow that repo exists it was verified
98 #here we hnow that repo exists it was verified
111 log.info('%s repo is already created', repo_name)
99 log.info('%s repo is already created', repo_name)
112 raise Exception('Repo exists')
100 raise Exception('Repo exists')
113 except RepoError:
101 except RepoError:
114 log.info('%s repo is free for creation', repo_name)
102 log.info('%s repo is free for creation', repo_name)
115 #it means that there is no valid repo there...
103 #it means that there is no valid repo there...
116 return True
104 return True
117
105
118
106
119 def _create_repo(self, repo_name):
107 def _create_repo(self, repo_name):
120 if repo_name in [None, '', 'add']:
108 if repo_name in [None, '', 'add']:
121 raise Exception('undefined repo_name of repo')
109 raise Exception('undefined repo_name of repo')
122
110
123 if self._check_repo(repo_name):
111 if self._check_repo(repo_name):
124 log.info('creating repo %s in %s', repo_name, self.repo_path)
112 log.info('creating repo %s in %s', repo_name, self.repo_path)
125 cmd = """mkdir %s && hg init %s""" \
113 cmd = """mkdir %s && hg init %s""" \
126 % (self.repo_path, self.repo_path)
114 % (self.repo_path, self.repo_path)
127 os.popen(cmd)
115 os.popen(cmd)
@@ -1,500 +1,502 b''
1 /*** Initial Settings ***/
1 /*** Initial Settings ***/
2 * {
2 * {
3 margin: 0;
3 margin: 0;
4 padding: 0;
4 padding: 0;
5 font-weight: normal;
5 font-weight: normal;
6 font-style: normal;
6 font-style: normal;
7 }
7 }
8
8
9 html {
9 html {
10 font-size: 100%;
10 font-size: 100%;
11 font-family: sans-serif;
11 font-family: sans-serif;
12 }
12 }
13
13
14 body {
14 body {
15 font-size: 77%;
15 font-size: 77%;
16 margin: 15px 50px;
16 margin: 15px 50px;
17 background: #4B4B4C;
17 background: #4B4B4C;
18 }
18 }
19
19
20 a {
20 a {
21 color:#0000cc;
21 color:#0000cc;
22 text-decoration: none;
22 text-decoration: none;
23 }
23 }
24 /*** end of Initial Settings ***/
24 /*** end of Initial Settings ***/
25
25
26
26
27 /** common settings **/
27 /** common settings **/
28 div#container {
28 div#container {
29 background: #FFFFFF;
29 background: #FFFFFF;
30 position: relative;
30 position: relative;
31 color: #666;
31 color: #666;
32 }
32 }
33
33
34 div.page-header {
34 div.page-header {
35 padding: 50px 20px 0;
35 padding: 50px 20px 0;
36 background: #006699 top left repeat-x;
36 background: #006699 top left repeat-x;
37 position: relative;
37 position: relative;
38 }
38 }
39 div.page-header h1 {
39 div.page-header h1 {
40 margin: 10px 0 30px;
40 margin: 10px 0 30px;
41 font-size: 1.8em;
41 font-size: 1.8em;
42 font-weight: bold;
42 font-weight: bold;
43 font-family: osaka,'MS P Gothic', Georgia, serif;
43 font-family: osaka,'MS P Gothic', Georgia, serif;
44 letter-spacing: 1px;
44 letter-spacing: 1px;
45 color: #DDD;
45 color: #DDD;
46 }
46 }
47 div.page-header h1 a {
47 div.page-header h1 a {
48 font-weight: bold;
48 font-weight: bold;
49 color: #FFF;
49 color: #FFF;
50 }
50 }
51 div.page-header a {
51 div.page-header a {
52 text-decoration: none;
52 text-decoration: none;
53 }
53 }
54 div.rss_logo {
54 div.rss_logo {
55 float: right; white-space: nowrap;
55 float: right; white-space: nowrap;
56 }
56 }
57 div.rss_logo a {
57 div.rss_logo a {
58 padding:3px 6px; line-height:10px;
58 padding:3px 6px; line-height:10px;
59 border:1px solid; border-color:#fcc7a5 #7d3302 #3e1a01 #ff954e;
59 border:1px solid; border-color:#fcc7a5 #7d3302 #3e1a01 #ff954e;
60 color:#ffffff; background-color:#ff6600;
60 color:#ffffff; background-color:#ff6600;
61 font-weight:bold; font-family:sans-serif; font-size:10px;
61 font-weight:bold; font-family:sans-serif; font-size:10px;
62 text-align:center; text-decoration:none;
62 text-align:center; text-decoration:none;
63 }
63 }
64 div.rss_logo a:hover {
64 div.rss_logo a:hover {
65 background-color:#ee5500;
65 background-color:#ee5500;
66 }
66 }
67
67
68 td.indexlinks {
68 td.indexlinks {
69 white-space: nowrap;
69 white-space: nowrap;
70 }
70 }
71 td.indexlinks a {
71 td.indexlinks a {
72 padding: 2px 5px; line-height: 10px;
72 padding: 2px 5px; line-height: 10px;
73 border: 1px solid;
73 border: 1px solid;
74 color: #ffffff; background-color: #7777bb;
74 color: #ffffff; background-color: #7777bb;
75 border-color: #aaaadd #333366 #333366 #aaaadd;
75 border-color: #aaaadd #333366 #333366 #aaaadd;
76 font-weight: bold; text-align: center; text-decoration: none;
76 font-weight: bold; text-align: center; text-decoration: none;
77 font-size: 10px;
77 font-size: 10px;
78 }
78 }
79 td.indexlinks a:hover {
79 td.indexlinks a:hover {
80 background-color: #6666aa;
80 background-color: #6666aa;
81 }
81 }
82
82
83 div.page-header form {
83 div.page-header form {
84 position: absolute;
84 position: absolute;
85 margin-bottom: 2px;
85 margin-bottom: 2px;
86 bottom: 0;
86 bottom: 0;
87 right: 20px;
87 right: 20px;
88 }
88 }
89 div.page-header form label {
89 div.page-header form label {
90 color: #DDD;
90 color: #DDD;
91 }
91 }
92 div.page-header form input {
92 div.page-header form input {
93 padding: 2px;
93 padding: 2px;
94 border: solid 1px #DDD;
94 border: solid 1px #DDD;
95 }
95 }
96 div.page-header form dl {
96 div.page-header form dl {
97 overflow: hidden;
97 overflow: hidden;
98 }
98 }
99 div.page-header form dl dt {
99 div.page-header form dl dt {
100 font-size: 1.2em;
100 font-size: 1.2em;
101 }
101 }
102 div.page-header form dl dt,
102 div.page-header form dl dt,
103 div.page-header form dl dd {
103 div.page-header form dl dd {
104 margin: 0 0 0 5px;
104 margin: 0 0 0 5px;
105 float: left;
105 float: left;
106 height: 24px;
106 height: 24px;
107 line-height: 20px;
107 line-height: 20px;
108 }
108 }
109
109
110 ul.page-nav {
110 ul.page-nav {
111 margin: 10px 0 0 0;
111 margin: 10px 0 0 0;
112 list-style-type: none;
112 list-style-type: none;
113 overflow: hidden;
113 overflow: hidden;
114 width: 800px;
114 width: 800px;
115 }
115 }
116 ul.page-nav li {
116 ul.page-nav li {
117 margin: 0 2px 0 0;
117 margin: 0 2px 0 0;
118 float: left;
118 float: left;
119 width: 80px;
119 width: 80px;
120 height: 24px;
120 height: 24px;
121 font-size: 1.1em;
121 font-size: 1.1em;
122 line-height: 24px;
122 line-height: 24px;
123 text-align: center;
123 text-align: center;
124 }
124 }
125 ul.page-nav li.current {
125 ul.page-nav li.current {
126 background: #FFF;
126 background: #FFF;
127 }
127 }
128 ul.page-nav li a {
128 ul.page-nav li a {
129 height: 24px;
129 height: 24px;
130 color: #666;
130 color: #666;
131 background: #DDD;
131 background: #DDD;
132 display: block;
132 display: block;
133 text-decoration: none;
133 text-decoration: none;
134 }
134 }
135 ul.page-nav li a:hover {
135 ul.page-nav li a:hover {
136 color:#333;
136 color:#333;
137 background: #FFF;
137 background: #FFF;
138 }
138 }
139
139
140 ul.submenu {
140 ul.submenu {
141 margin: 10px 0 -10px 20px;
141 margin: 10px 0 -10px 20px;
142 list-style-type: none;
142 list-style-type: none;
143 }
143 }
144 ul.submenu li {
144 ul.submenu li {
145 margin: 0 10px 0 0;
145 margin: 0 10px 0 0;
146 font-size: 1.2em;
146 font-size: 1.2em;
147 display: inline;
147 display: inline;
148 }
148 }
149
149 ul.submenu li.current_submenu {
150 border-bottom: 2px solid #006699;
151 }
150 h2 {
152 h2 {
151 margin: 20px 0 10px;
153 margin: 20px 0 10px;
152 height: 30px;
154 height: 30px;
153 line-height: 30px;
155 line-height: 30px;
154 text-indent: 20px;
156 text-indent: 20px;
155 background: #FFF;
157 background: #FFF;
156 font-size: 1.2em;
158 font-size: 1.2em;
157 border-top: dotted 1px #D5E1E6;
159 border-top: dotted 1px #D5E1E6;
158 font-weight: bold;
160 font-weight: bold;
159 }
161 }
160 h2.no-link {
162 h2.no-link {
161 color:#006699;
163 color:#006699;
162 }
164 }
163 h2.no-border {
165 h2.no-border {
164 color: #FFF;
166 color: #FFF;
165 background: #006699;
167 background: #006699;
166 border: 0;
168 border: 0;
167 }
169 }
168 h2 a {
170 h2 a {
169 font-weight:bold;
171 font-weight:bold;
170 color:#006699;
172 color:#006699;
171 }
173 }
172
174
173 div.page-path {
175 div.page-path {
174 text-align: right;
176 text-align: right;
175 padding: 20px 30px 10px 0;
177 padding: 20px 30px 10px 0;
176 border:solid #d9d8d1;
178 border:solid #d9d8d1;
177 border-width:0px 0px 1px;
179 border-width:0px 0px 1px;
178 font-size: 1.2em;
180 font-size: 1.2em;
179 }
181 }
180
182
181 div.page-footer {
183 div.page-footer {
182 margin: 50px 0 0;
184 margin: 50px 0 0;
183 position: relative;
185 position: relative;
184 }
186 }
185 div.page-footer p {
187 div.page-footer p {
186 position: relative;
188 position: relative;
187 left: 20px;
189 left: 20px;
188 bottom: 5px;
190 bottom: 5px;
189 font-size: 1.2em;
191 font-size: 1.2em;
190 }
192 }
191
193
192 ul.rss-logo {
194 ul.rss-logo {
193 position: absolute;
195 position: absolute;
194 top: -10px;
196 top: -10px;
195 right: 20px;
197 right: 20px;
196 height: 20px;
198 height: 20px;
197 list-style-type: none;
199 list-style-type: none;
198 }
200 }
199 ul.rss-logo li {
201 ul.rss-logo li {
200 display: inline;
202 display: inline;
201 }
203 }
202 ul.rss-logo li a {
204 ul.rss-logo li a {
203 padding: 3px 6px;
205 padding: 3px 6px;
204 line-height: 10px;
206 line-height: 10px;
205 border:1px solid;
207 border:1px solid;
206 border-color:#fcc7a5 #7d3302 #3e1a01 #ff954e;
208 border-color:#fcc7a5 #7d3302 #3e1a01 #ff954e;
207 color:#ffffff;
209 color:#ffffff;
208 background-color:#ff6600;
210 background-color:#ff6600;
209 font-weight:bold;
211 font-weight:bold;
210 font-family:sans-serif;
212 font-family:sans-serif;
211 font-size:10px;
213 font-size:10px;
212 text-align:center;
214 text-align:center;
213 text-decoration:none;
215 text-decoration:none;
214 }
216 }
215 div.rss-logo li a:hover {
217 div.rss-logo li a:hover {
216 background-color:#ee5500;
218 background-color:#ee5500;
217 }
219 }
218
220
219 p.normal {
221 p.normal {
220 margin: 20px 0 20px 30px;
222 margin: 20px 0 20px 30px;
221 font-size: 1.2em;
223 font-size: 1.2em;
222 }
224 }
223
225
224 table {
226 table {
225 margin: 10px 0 0 20px;
227 margin: 10px 0 0 20px;
226 width: auto;
228 width: auto;
227 border-collapse: collapse;
229 border-collapse: collapse;
228 }
230 }
229 table tr td {
231 table tr td {
230 font-size: 1.1em;
232 font-size: 1.1em;
231 }
233 }
232 table tr td.nowrap {
234 table tr td.nowrap {
233 white-space: nowrap;
235 white-space: nowrap;
234 }
236 }
235 /*
237 /*
236 table tr.parity0:hover,
238 table tr.parity0:hover,
237 table tr.parity1:hover {
239 table tr.parity1:hover {
238 background: #D5E1E6;
240 background: #D5E1E6;
239 }
241 }
240 */
242 */
241 table tr.parity0 {
243 table tr.parity0 {
242 background: #F1F6F7;
244 background: #F1F6F7;
243 }
245 }
244 table tr.parity1 {
246 table tr.parity1 {
245 background: #FFFFFF;
247 background: #FFFFFF;
246 }
248 }
247 table tr td {
249 table tr td {
248 padding: 5px 5px;
250 padding: 5px 5px;
249 }
251 }
250 table.annotated tr td {
252 table.annotated tr td {
251 padding: 0px 5px;
253 padding: 0px 5px;
252 }
254 }
253
255
254 span.logtags span {
256 span.logtags span {
255 padding: 2px 6px;
257 padding: 2px 6px;
256 font-weight: normal;
258 font-weight: normal;
257 font-size: 11px;
259 font-size: 11px;
258 border: 1px solid;
260 border: 1px solid;
259 background-color: #ffaaff;
261 background-color: #ffaaff;
260 border-color: #ffccff #ff00ee #ff00ee #ffccff;
262 border-color: #ffccff #ff00ee #ff00ee #ffccff;
261 }
263 }
262 span.logtags span.tagtag {
264 span.logtags span.tagtag {
263 background-color: #ffffaa;
265 background-color: #ffffaa;
264 border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
266 border-color: #ffffcc #ffee00 #ffee00 #ffffcc;
265 }
267 }
266 span.logtags span.branchtag {
268 span.logtags span.branchtag {
267 background-color: #aaffaa;
269 background-color: #aaffaa;
268 border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
270 border-color: #ccffcc #00cc33 #00cc33 #ccffcc;
269 }
271 }
270 span.logtags span.inbranchtag {
272 span.logtags span.inbranchtag {
271 background-color: #d5dde6;
273 background-color: #d5dde6;
272 border-color: #e3ecf4 #9398f4 #9398f4 #e3ecf4;
274 border-color: #e3ecf4 #9398f4 #9398f4 #e3ecf4;
273 }
275 }
274
276
275 div.diff pre {
277 div.diff pre {
276 margin: 10px 0 0 0;
278 margin: 10px 0 0 0;
277 }
279 }
278 div.diff pre span {
280 div.diff pre span {
279 font-family: monospace;
281 font-family: monospace;
280 white-space: pre;
282 white-space: pre;
281 font-size: 1.2em;
283 font-size: 1.2em;
282 padding: 3px 0;
284 padding: 3px 0;
283 }
285 }
284 td.source {
286 td.source {
285 white-space: pre;
287 white-space: pre;
286 font-family: monospace;
288 font-family: monospace;
287 margin: 10px 30px 0;
289 margin: 10px 30px 0;
288 font-size: 1.2em;
290 font-size: 1.2em;
289 font-family: monospace;
291 font-family: monospace;
290 }
292 }
291 div.source div.parity0,
293 div.source div.parity0,
292 div.source div.parity1 {
294 div.source div.parity1 {
293 padding: 1px;
295 padding: 1px;
294 font-size: 1.2em;
296 font-size: 1.2em;
295 }
297 }
296 div.source div.parity0 {
298 div.source div.parity0 {
297 background: #F1F6F7;
299 background: #F1F6F7;
298 }
300 }
299 div.source div.parity1 {
301 div.source div.parity1 {
300 background: #FFFFFF;
302 background: #FFFFFF;
301 }
303 }
302 div.parity0:hover,
304 div.parity0:hover,
303 div.parity1:hover {
305 div.parity1:hover {
304 background: #D5E1E6;
306 background: #D5E1E6;
305 }
307 }
306 .linenr {
308 .linenr {
307 color: #999;
309 color: #999;
308 text-align: right;
310 text-align: right;
309 }
311 }
310 .lineno {
312 .lineno {
311 text-align: right;
313 text-align: right;
312 }
314 }
313 .lineno a {
315 .lineno a {
314 color: #999;
316 color: #999;
315 }
317 }
316 td.linenr {
318 td.linenr {
317 width: 60px;
319 width: 60px;
318 }
320 }
319
321
320 div#powered-by {
322 div#powered-by {
321 position: absolute;
323 position: absolute;
322 width: 75px;
324 width: 75px;
323 top: 15px;
325 top: 15px;
324 right: 20px;
326 right: 20px;
325 font-size: 1.2em;
327 font-size: 1.2em;
326 }
328 }
327 div#powered-by a {
329 div#powered-by a {
328 color: #EEE;
330 color: #EEE;
329 text-decoration: none;
331 text-decoration: none;
330 }
332 }
331 div#powered-by a:hover {
333 div#powered-by a:hover {
332 text-decoration: underline;
334 text-decoration: underline;
333 }
335 }
334 /*
336 /*
335 div#monoblue-corner-top-left {
337 div#monoblue-corner-top-left {
336 position: absolute;
338 position: absolute;
337 top: 0;
339 top: 0;
338 left: 0;
340 left: 0;
339 width: 10px;
341 width: 10px;
340 height: 10px;
342 height: 10px;
341 background: url(./monoblue-corner.png) top left no-repeat !important;
343 background: url(./monoblue-corner.png) top left no-repeat !important;
342 background: none;
344 background: none;
343 }
345 }
344 div#monoblue-corner-top-right {
346 div#monoblue-corner-top-right {
345 position: absolute;
347 position: absolute;
346 top: 0;
348 top: 0;
347 right: 0;
349 right: 0;
348 width: 10px;
350 width: 10px;
349 height: 10px;
351 height: 10px;
350 background: url(./monoblue-corner.png) top right no-repeat !important;
352 background: url(./monoblue-corner.png) top right no-repeat !important;
351 background: none;
353 background: none;
352 }
354 }
353 div#monoblue-corner-bottom-left {
355 div#monoblue-corner-bottom-left {
354 position: absolute;
356 position: absolute;
355 bottom: 0;
357 bottom: 0;
356 left: 0;
358 left: 0;
357 width: 10px;
359 width: 10px;
358 height: 10px;
360 height: 10px;
359 background: url(./monoblue-corner.png) bottom left no-repeat !important;
361 background: url(./monoblue-corner.png) bottom left no-repeat !important;
360 background: none;
362 background: none;
361 }
363 }
362 div#monoblue-corner-bottom-right {
364 div#monoblue-corner-bottom-right {
363 position: absolute;
365 position: absolute;
364 bottom: 0;
366 bottom: 0;
365 right: 0;
367 right: 0;
366 width: 10px;
368 width: 10px;
367 height: 10px;
369 height: 10px;
368 background: url(./monoblue-corner.png) bottom right no-repeat !important;
370 background: url(./monoblue-corner.png) bottom right no-repeat !important;
369 background: none;
371 background: none;
370 }
372 }
371 */
373 */
372 /** end of common settings **/
374 /** end of common settings **/
373
375
374 /** summary **/
376 /** summary **/
375 dl.overview {
377 dl.overview {
376 margin: 0 0 0 30px;
378 margin: 0 0 0 30px;
377 font-size: 1.1em;
379 font-size: 1.1em;
378 overflow: hidden;
380 overflow: hidden;
379 }
381 }
380 dl.overview dt,
382 dl.overview dt,
381 dl.overview dd {
383 dl.overview dd {
382 margin: 5px 0;
384 margin: 5px 0;
383 float: left;
385 float: left;
384 }
386 }
385 dl.overview dt {
387 dl.overview dt {
386 clear: left;
388 clear: left;
387 font-weight: bold;
389 font-weight: bold;
388 width: 150px;
390 width: 150px;
389 }
391 }
390 /** end of summary **/
392 /** end of summary **/
391
393
392 /** chagelog **/
394 /** chagelog **/
393 h3.changelog {
395 h3.changelog {
394 margin: 20px 0 5px 30px;
396 margin: 20px 0 5px 30px;
395 padding: 0 0 2px;
397 padding: 0 0 2px;
396 font-size: 1.4em;
398 font-size: 1.4em;
397 border-bottom: dotted 1px #D5E1E6;
399 border-bottom: dotted 1px #D5E1E6;
398 }
400 }
399 ul.changelog-entry {
401 ul.changelog-entry {
400 margin: 0 0 10px 30px;
402 margin: 0 0 10px 30px;
401 list-style-type: none;
403 list-style-type: none;
402 position: relative;
404 position: relative;
403 }
405 }
404 ul.changelog-entry li span.revdate {
406 ul.changelog-entry li span.revdate {
405 font-size: 1.1em;
407 font-size: 1.1em;
406 }
408 }
407 ul.changelog-entry li.age {
409 ul.changelog-entry li.age {
408 position: absolute;
410 position: absolute;
409 top: -25px;
411 top: -25px;
410 right: 10px;
412 right: 10px;
411 font-size: 1.4em;
413 font-size: 1.4em;
412 color: #CCC;
414 color: #CCC;
413 font-weight: bold;
415 font-weight: bold;
414 font-style: italic;
416 font-style: italic;
415 }
417 }
416 ul.changelog-entry li span.name {
418 ul.changelog-entry li span.name {
417 font-size: 1.2em;
419 font-size: 1.2em;
418 font-weight: bold;
420 font-weight: bold;
419 }
421 }
420 ul.changelog-entry li.description {
422 ul.changelog-entry li.description {
421 margin: 10px 0 0;
423 margin: 10px 0 0;
422 font-size: 1.1em;
424 font-size: 1.1em;
423 }
425 }
424 /** end of changelog **/
426 /** end of changelog **/
425
427
426 /** file **/
428 /** file **/
427 p.files {
429 p.files {
428 margin: 0 0 0 20px;
430 margin: 0 0 0 20px;
429 font-size: 2.0em;
431 font-size: 2.0em;
430 font-weight: bold;
432 font-weight: bold;
431 }
433 }
432 /** end of file **/
434 /** end of file **/
433
435
434 /** changeset **/
436 /** changeset **/
435 h3.changeset {
437 h3.changeset {
436 margin: 20px 0 5px 20px;
438 margin: 20px 0 5px 20px;
437 padding: 0 0 2px;
439 padding: 0 0 2px;
438 font-size: 1.6em;
440 font-size: 1.6em;
439 border-bottom: dotted 1px #D5E1E6;
441 border-bottom: dotted 1px #D5E1E6;
440 }
442 }
441 p.changeset-age {
443 p.changeset-age {
442 position: relative;
444 position: relative;
443 }
445 }
444 p.changeset-age span {
446 p.changeset-age span {
445 position: absolute;
447 position: absolute;
446 top: -25px;
448 top: -25px;
447 right: 10px;
449 right: 10px;
448 font-size: 1.4em;
450 font-size: 1.4em;
449 color: #CCC;
451 color: #CCC;
450 font-weight: bold;
452 font-weight: bold;
451 font-style: italic;
453 font-style: italic;
452 }
454 }
453 p.description {
455 p.description {
454 margin: 10px 30px 0 30px;
456 margin: 10px 30px 0 30px;
455 padding: 10px;
457 padding: 10px;
456 border: solid 1px #CCC;
458 border: solid 1px #CCC;
457 font-size: 1.2em;
459 font-size: 1.2em;
458 }
460 }
459 /** end of changeset **/
461 /** end of changeset **/
460
462
461 /** canvas **/
463 /** canvas **/
462 div#wrapper {
464 div#wrapper {
463 position: relative;
465 position: relative;
464 font-size: 1.2em;
466 font-size: 1.2em;
465 }
467 }
466
468
467 canvas {
469 canvas {
468 position: absolute;
470 position: absolute;
469 z-index: 5;
471 z-index: 5;
470 top: -0.7em;
472 top: -0.7em;
471 }
473 }
472
474
473 ul#nodebgs li.parity0 {
475 ul#nodebgs li.parity0 {
474 background: #F1F6F7;
476 background: #F1F6F7;
475 }
477 }
476
478
477 ul#nodebgs li.parity1 {
479 ul#nodebgs li.parity1 {
478 background: #FFFFFF;
480 background: #FFFFFF;
479 }
481 }
480
482
481 ul#graphnodes {
483 ul#graphnodes {
482 position: absolute;
484 position: absolute;
483 z-index: 10;
485 z-index: 10;
484 top: 7px;
486 top: 7px;
485 list-style: none inside none;
487 list-style: none inside none;
486 }
488 }
487
489
488 ul#nodebgs {
490 ul#nodebgs {
489 list-style: none inside none;
491 list-style: none inside none;
490 }
492 }
491
493
492 ul#graphnodes li, ul#nodebgs li {
494 ul#graphnodes li, ul#nodebgs li {
493 height: 39px;
495 height: 39px;
494 }
496 }
495
497
496 ul#graphnodes li .info {
498 ul#graphnodes li .info {
497 display: block;
499 display: block;
498 position: relative;
500 position: relative;
499 }
501 }
500 /** end of canvas **/
502 /** end of canvas **/
@@ -1,64 +1,64 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/base.html"/>
2 <%inherit file="base/base.html"/>
3 <%def name="get_form_error(element)">
3 <%def name="get_form_error(element)">
4 %if type(c.form_errors) == dict:
4 %if type(c.form_errors) == dict:
5 %if c.form_errors.get(element,False):
5 %if c.form_errors.get(element,False):
6 <span class="error-message">
6 <span class="error-message">
7 ${c.form_errors.get(element,'')}
7 ${c.form_errors.get(element,'')}
8 </span>
8 </span>
9 %endif
9 %endif
10 %endif
10 %endif
11 </%def>
11 </%def>
12 <%def name="title()">
12 <%def name="title()">
13 ${_('Repository managment')}
13 ${_('Repository managment')}
14 </%def>
14 </%def>
15 <%def name="breadcrumbs()">
15 <%def name="breadcrumbs()">
16 ${h.link_to(u'Home',h.url('/'))}
16 ${h.link_to(u'Home',h.url('/'))}
17 /
17 /
18 ${h.link_to(u'Admin',h.url('admin_home'))}
18 ${h.link_to(u'Admin',h.url('admin_home'))}
19 </%def>
19 </%def>
20 <%def name="page_nav()">
20 <%def name="page_nav()">
21 <li>${h.link_to(u'Home',h.url('/'))}</li>
21 <li>${h.link_to(u'Home',h.url('/'))}</li>
22 <li class="current">${_('Admin')}</li>
22 <li class="current">${_('Admin')}</li>
23 </%def>
23 </%def>
24 <%def name="main()">
24 <%def name="main()">
25 %if c.admin_user:
25 %if c.admin_user:
26 <ul class="submenu">
26 <ul class="submenu">
27 <li>
27 <li>
28 ${h.link_to(u'Repos managment',h.url('admin_repos_manage'))}
28 ${h.link_to(u'Repos',h.url('repos'))}
29 </li>
29 </li>
30 <li>
30 <li>
31 ${h.link_to(u'Users managment',h.url('admin_users_manage'))}
31 ${h.link_to(u'Users',h.url('users'))}
32 </li>
32 </li>
33 </ul>
33 </ul>
34 <br/>
34 <br/>
35 <div>
35 <div>
36
36
37 <h2>Hi !</h2>
37 <h2>Hi !</h2>
38 </div>
38 </div>
39 %else:
39 %else:
40 <div>
40 <div>
41 <br />
41 <br />
42 <h2>${_('Login')}</h2>
42 <h2>${_('Login')}</h2>
43 ${h.form(h.url.current())}
43 ${h.form(h.url.current())}
44 <table>
44 <table>
45 <tr>
45 <tr>
46 <td>${_('Username')}</td>
46 <td>${_('Username')}</td>
47 <td>${h.text('username')}</td>
47 <td>${h.text('username')}</td>
48 <td>${get_form_error('username')} </td>
48 <td>${get_form_error('username')} </td>
49 </tr>
49 </tr>
50 <tr>
50 <tr>
51 <td>${_('Password')}</td>
51 <td>${_('Password')}</td>
52 <td>${h.password('password')}</td>
52 <td>${h.password('password')}</td>
53 <td>${get_form_error('password')}</td>
53 <td>${get_form_error('password')}</td>
54 </tr>
54 </tr>
55 <tr>
55 <tr>
56 <td></td>
56 <td></td>
57 <td>${h.submit('login','login')}</td>
57 <td>${h.submit('login','login')}</td>
58 </tr>
58 </tr>
59 </table>
59 </table>
60 ${h.end_form()}
60 ${h.end_form()}
61 </div>
61 </div>
62 %endif
62 %endif
63
63
64 </%def> No newline at end of file
64 </%def>
@@ -1,40 +1,28 b''
1 <%inherit file="base/base.html"/>
1 <%inherit file="base/base.html"/>
2 <%def name="title()">
2 <%def name="title()">
3 ${_('Repository managment')}
3 ${_('Repository managment')}
4 </%def>
4 </%def>
5 <%def name="breadcrumbs()">
5 <%def name="breadcrumbs()">
6 ${h.link_to(u'Home',h.url('/'))}
6 ${h.link_to(u'Home',h.url('/'))}
7 /
7 /
8 ${h.link_to(u'Admin',h.url('admin_home'))}
8 ${h.link_to(u'Admin',h.url('admin_home'))}
9 /
9 /
10 ${h.link_to(u'Repos managment',h.url('admin_repos_manage'))}
10 ${h.link_to(u'Repos managment',h.url('repos'))}
11 </%def>
11 </%def>
12 <%def name="page_nav()">
12 <%def name="page_nav()">
13 <li>${h.link_to(u'Home',h.url('/'))}</li>
13 <li>${h.link_to(u'Home',h.url('/'))}</li>
14 <li class="current">${_('Admin')}</li>
14 <li class="current">${_('Admin')}</li>
15 </%def>
15 </%def>
16 <%def name="main()">
16 <%def name="main()">
17
17 <ul class="submenu">
18
18 <li class="current_submenu">
19 <div class="twocol-form">
19 ${h.link_to(u'Repos',h.url('repos'))}
20 <h2>Create new repository</h2>
20 </li>
21 <form method="post" action="/repo/create/">
21 <li>
22 <table>
22 ${h.link_to(u'Users',h.url('users'))}
23 <tbody><tr><th><label for="id_name">Name:</label></th><td><input type="text" maxlength="255" name="name" id="id_name"></td></tr>
23 </li>
24 <tr><th><label for="id_description">Description:</label></th><td><textarea name="description" cols="40" rows="10" id="id_description"></textarea></td></tr>
24 </ul>
25 <tr><th><label for="id_website">Website:</label></th><td><input type="text" maxlength="128" name="website" id="id_website"></td></tr>
25 <div>
26 <tr><th><label for="id_is_private">Private:</label></th><td><input type="checkbox" id="id_is_private" name="is_private"></td></tr>
26 <h2>${_('Mercurial repos')}</h2>
27 <tr><th><label for="id_has_issues">Issue tracking:</label></th><td><input type="checkbox" id="id_has_issues" name="has_issues" checked="checked"></td></tr>
28 <tr><th><label for="id_has_wiki">Wiki:</label></th><td><input type="checkbox" id="id_has_wiki" name="has_wiki" checked="checked"></td></tr>
29
30
31 <tr><td colspan="2">&nbsp;</td></tr>
32 <tr>
33 <td colspan="2">
34 <input type="submit" class="primary-button" value="Create repository"> <input type="reset" onclick="document.location='http://bitbucket.org/';" class="secondary-button secondary-button-darkbg" value="Cancel">
35 </td>
36 </tr>
37 </tbody></table>
38 </form>
39 </div>
27 </div>
40 </%def> No newline at end of file
28 </%def>
@@ -1,34 +1,47 b''
1 <%inherit file="base/base.html"/>
1 <%inherit file="base/base.html"/>
2 <%def name="title()">
2 <%def name="title()">
3 ${_('Repository managment')}
3 ${_('Repository managment')}
4 </%def>
4 </%def>
5 <%def name="breadcrumbs()">
5 <%def name="breadcrumbs()">
6 ${h.link_to(u'Home',h.url('/'))}
6 ${h.link_to(u'Home',h.url('/'))}
7 /
7 /
8 ${h.link_to(u'Admin',h.url('admin_home'))}
8 ${h.link_to(u'Admin',h.url('admin_home'))}
9 /
9 /
10 ${h.link_to(u'Users managment',h.url('admin_users_manage'))}
10 ${h.link_to(u'Users managment',h.url('users'))}
11 </%def>
11 </%def>
12 <%def name="page_nav()">
12 <%def name="page_nav()">
13 <li>${h.link_to(u'Home',h.url('/'))}</li>
13 <li>${h.link_to(u'Home',h.url('/'))}</li>
14 <li class="current">${_('Admin')}</li>
14 <li class="current">${_('Admin')}</li>
15 </%def>
15 </%def>
16 <%def name="main()">
16 <%def name="main()">
17
17 <ul class="submenu">
18 <li>
19 ${h.link_to(u'Repos',h.url('repos'))}
20 </li>
21 <li class="current_submenu">
22 ${h.link_to(u'Users',h.url('users'))}
23 </li>
24 </ul>
25 <div>
26 <h2>${_('Mercurial users')}</h2>
18 <table cellspacing="0">
27 <table cellspacing="0">
19 <tr>
28 <tr>
20 <th>Id</th>
29 <th>Id</th>
21 <th>Username</th>
30 <th>Username</th>
22 <th>Password</th>
31 <th>Password</th>
23 <th>Active</th>
32 <th>Active</th>
33 <th>Admin</th>
24 </tr>
34 </tr>
25 %for i in c.users_list:
35 %for i in c.users_list:
26 <tr>
36 <tr>
27 <td>${i[0]}</td>
37 <td>${i[0]}</td>
28 <td>${i[1]}</td>
38 <td>${i[1]}</td>
29 <td>${i[2]}</td>
39 <td>${i[2]}</td>
30 <td>${i[3]}</td>
40 <td>${i[3]}</td>
41 <td>${i[4]}</td>
31 </tr>
42 </tr>
32 %endfor
43 %endfor
33 </table>
44 </table>
45 </div>
46
34 </%def> No newline at end of file
47 </%def>
General Comments 0
You need to be logged in to leave comments. Login now