##// END OF EJS Templates
first permissions commit: added permission managment on repository edit. Changed db rmissions, validators.
marcink -
r296:29370bb7 default
parent child Browse files
Show More
@@ -1,175 +1,181 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # repos controller for pylons
3 # repos controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
8 # of the License or (at your opinion) any later version of the license.
8 # of the License or (at your opinion) any later version of the license.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA 02110-1301, USA.
18 # MA 02110-1301, USA.
19 """
19 """
20 Created on April 7, 2010
20 Created on April 7, 2010
21 admin controller for pylons
21 admin controller for pylons
22 @author: marcink
22 @author: marcink
23 """
23 """
24 from operator import itemgetter
24 from operator import itemgetter
25 from pylons import request, response, session, tmpl_context as c, url, \
25 from pylons import request, response, session, tmpl_context as c, url, \
26 app_globals as g
26 app_globals as g
27 from pylons.controllers.util import abort, redirect
27 from pylons.controllers.util import abort, redirect
28 from pylons.i18n.translation import _
28 from pylons.i18n.translation import _
29 from pylons_app.lib import helpers as h
29 from pylons_app.lib import helpers as h
30 from pylons_app.lib.auth import LoginRequired
30 from pylons_app.lib.auth import LoginRequired
31 from pylons_app.lib.base import BaseController, render
31 from pylons_app.lib.base import BaseController, render
32 from pylons_app.lib.utils import invalidate_cache
32 from pylons_app.lib.utils import invalidate_cache
33 from pylons_app.model.repo_model import RepoModel
33 from pylons_app.model.repo_model import RepoModel
34 from pylons_app.model.hg_model import HgModel
34 from pylons_app.model.hg_model import HgModel
35 from pylons_app.model.forms import RepoForm
35 from pylons_app.model.forms import RepoForm
36 from pylons_app.model.meta import Session
36 from pylons_app.model.meta import Session
37 from datetime import datetime
37 from datetime import datetime
38 import formencode
38 import formencode
39 from formencode import htmlfill
39 from formencode import htmlfill
40 import logging
40 import logging
41 import os
41 import os
42 import shutil
42 import shutil
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45 class ReposController(BaseController):
45 class ReposController(BaseController):
46 """REST Controller styled on the Atom Publishing Protocol"""
46 """REST Controller styled on the Atom Publishing Protocol"""
47 # To properly map this controller, ensure your config/routing.py
47 # To properly map this controller, ensure your config/routing.py
48 # file has a resource setup:
48 # file has a resource setup:
49 # map.resource('repo', 'repos')
49 # map.resource('repo', 'repos')
50 @LoginRequired()
50 @LoginRequired()
51 def __before__(self):
51 def __before__(self):
52 c.admin_user = session.get('admin_user')
52 c.admin_user = session.get('admin_user')
53 c.admin_username = session.get('admin_username')
53 c.admin_username = session.get('admin_username')
54 super(ReposController, self).__before__()
54 super(ReposController, self).__before__()
55
55
56 def index(self, format='html'):
56 def index(self, format='html'):
57 """GET /repos: All items in the collection"""
57 """GET /repos: All items in the collection"""
58 # url('repos')
58 # url('repos')
59 cached_repo_list = HgModel().get_repos()
59 cached_repo_list = HgModel().get_repos()
60 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
60 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
61 return render('admin/repos/repos.html')
61 return render('admin/repos/repos.html')
62
62
63 def create(self):
63 def create(self):
64 """POST /repos: Create a new item"""
64 """POST /repos: Create a new item"""
65 # url('repos')
65 # url('repos')
66 repo_model = RepoModel()
66 repo_model = RepoModel()
67 _form = RepoForm()()
67 _form = RepoForm()()
68 try:
68 try:
69 form_result = _form.to_python(dict(request.POST))
69 form_result = _form.to_python(dict(request.POST))
70 repo_model.create(form_result, c.hg_app_user)
70 repo_model.create(form_result, c.hg_app_user)
71 invalidate_cache('cached_repo_list')
71 invalidate_cache('cached_repo_list')
72 h.flash(_('created repository %s') % form_result['repo_name'],
72 h.flash(_('created repository %s') % form_result['repo_name'],
73 category='success')
73 category='success')
74
74
75 except formencode.Invalid as errors:
75 except formencode.Invalid as errors:
76 c.form_errors = errors.error_dict
76 c.form_errors = errors.error_dict
77 c.new_repo = errors.value['repo_name']
77 c.new_repo = errors.value['repo_name']
78 return htmlfill.render(
78 return htmlfill.render(
79 render('admin/repos/repo_add.html'),
79 render('admin/repos/repo_add.html'),
80 defaults=errors.value,
80 defaults=errors.value,
81 encoding="UTF-8")
81 encoding="UTF-8")
82
82
83 except Exception:
83 except Exception:
84 h.flash(_('error occured during creation of repository %s') \
84 h.flash(_('error occured during creation of repository %s') \
85 % form_result['repo_name'], category='error')
85 % form_result['repo_name'], category='error')
86
86
87 return redirect('repos')
87 return redirect('repos')
88
88
89 def new(self, format='html'):
89 def new(self, format='html'):
90 """GET /repos/new: Form to create a new item"""
90 """GET /repos/new: Form to create a new item"""
91 new_repo = request.GET.get('repo', '')
91 new_repo = request.GET.get('repo', '')
92 c.new_repo = h.repo_name_slug(new_repo)
92 c.new_repo = h.repo_name_slug(new_repo)
93
93
94 return render('admin/repos/repo_add.html')
94 return render('admin/repos/repo_add.html')
95
95
96 def update(self, id):
96 def update(self, id):
97 """PUT /repos/id: Update an existing item"""
97 """PUT /repos/id: Update an existing item"""
98 # Forms posted to this method should contain a hidden field:
98 # Forms posted to this method should contain a hidden field:
99 # <input type="hidden" name="_method" value="PUT" />
99 # <input type="hidden" name="_method" value="PUT" />
100 # Or using helpers:
100 # Or using helpers:
101 # h.form(url('repo', id=ID),
101 # h.form(url('repo', id=ID),
102 # method='put')
102 # method='put')
103 # url('repo', id=ID)
103 # url('repo', id=ID)
104 repo_model = RepoModel()
104 repo_model = RepoModel()
105 _form = RepoForm(edit=True)()
105 _form = RepoForm(edit=True)()
106 try:
106 try:
107 form_result = _form.to_python(dict(request.POST))
107 form_result = _form.to_python(dict(request.POST))
108 repo_model.update(id, form_result)
108 repo_model.update(id, form_result)
109 invalidate_cache('cached_repo_list')
109 invalidate_cache('cached_repo_list')
110 h.flash(_('Repository updated succesfully'), category='success')
110 h.flash(_('Repository %s updated succesfully' % id), category='success')
111
111
112 except formencode.Invalid as errors:
112 except formencode.Invalid as errors:
113 c.repo_info = repo_model.get(id)
113 c.repo_info = repo_model.get(id)
114 errors.value.update({'user':c.repo_info.user.username})
114 c.form_errors = errors.error_dict
115 c.form_errors = errors.error_dict
115 return htmlfill.render(
116 return htmlfill.render(
116 render('admin/repos/repo_edit.html'),
117 render('admin/repos/repo_edit.html'),
117 defaults=errors.value,
118 defaults=errors.value,
118 encoding="UTF-8")
119 encoding="UTF-8")
119 except Exception:
120 except Exception:
120 h.flash(_('error occured during update of repository %s') \
121 h.flash(_('error occured during update of repository %s') \
121 % form_result['repo_name'], category='error')
122 % form_result['repo_name'], category='error')
122 return redirect(url('repos'))
123 return redirect(url('repos'))
123
124
124 def delete(self, id):
125 def delete(self, id):
125 """DELETE /repos/id: Delete an existing item"""
126 """DELETE /repos/id: Delete an existing item"""
126 # Forms posted to this method should contain a hidden field:
127 # Forms posted to this method should contain a hidden field:
127 # <input type="hidden" name="_method" value="DELETE" />
128 # <input type="hidden" name="_method" value="DELETE" />
128 # Or using helpers:
129 # Or using helpers:
129 # h.form(url('repo', id=ID),
130 # h.form(url('repo', id=ID),
130 # method='delete')
131 # method='delete')
131 # url('repo', id=ID)
132 # url('repo', id=ID)
132
133
133 repo_model = RepoModel()
134 repo_model = RepoModel()
134 repo = repo_model.get(id)
135 repo = repo_model.get(id)
135 if not repo:
136 if not repo:
136 h.flash(_('%s repository is not mapped to db perhaps'
137 h.flash(_('%s repository is not mapped to db perhaps'
137 ' it was moved or renamed from the filesystem'
138 ' it was moved or renamed from the filesystem'
138 ' please run the application again'
139 ' please run the application again'
139 ' in order to rescan repositories') % id, category='error')
140 ' in order to rescan repositories') % id, category='error')
140
141
141 return redirect(url('repos'))
142 return redirect(url('repos'))
142 try:
143 try:
143 repo_model.delete(repo)
144 repo_model.delete(repo)
144 invalidate_cache('cached_repo_list')
145 invalidate_cache('cached_repo_list')
145 h.flash(_('deleted repository %s') % id, category='success')
146 h.flash(_('deleted repository %s') % id, category='success')
146 except Exception:
147 except Exception:
147 h.flash(_('An error occured during deletion of %s') % id,
148 h.flash(_('An error occured during deletion of %s') % id,
148 category='error')
149 category='error')
149
150
150 return redirect(url('repos'))
151 return redirect(url('repos'))
151
152
152 def show(self, id, format='html'):
153 def show(self, id, format='html'):
153 """GET /repos/id: Show a specific item"""
154 """GET /repos/id: Show a specific item"""
154 # url('repo', id=ID)
155 # url('repo', id=ID)
155
156
156 def edit(self, id, format='html'):
157 def edit(self, id, format='html'):
157 """GET /repos/id/edit: Form to edit an existing item"""
158 """GET /repos/id/edit: Form to edit an existing item"""
158 # url('edit_repo', id=ID)
159 # url('edit_repo', id=ID)
159 repo_model = RepoModel()
160 repo_model = RepoModel()
160 c.repo_info = repo = repo_model.get(id)
161 c.repo_info = repo = repo_model.get(id)
161 if not repo:
162 if not repo:
162 h.flash(_('%s repository is not mapped to db perhaps'
163 h.flash(_('%s repository is not mapped to db perhaps'
163 ' it was created or renamed from the filesystem'
164 ' it was created or renamed from the filesystem'
164 ' please run the application again'
165 ' please run the application again'
165 ' in order to rescan repositories') % id, category='error')
166 ' in order to rescan repositories') % id, category='error')
166
167
167 return redirect(url('repos'))
168 return redirect(url('repos'))
168 defaults = c.repo_info.__dict__
169 defaults = c.repo_info.__dict__
169 defaults.update({'user':c.repo_info.user.username})
170 defaults.update({'user':c.repo_info.user.username})
171
172 for p in c.repo_info.repo2perm:
173 defaults.update({'perm_%s' % p.user.username:
174 p.permission.permission_name})
175
170 return htmlfill.render(
176 return htmlfill.render(
171 render('admin/repos/repo_edit.html'),
177 render('admin/repos/repo_edit.html'),
172 defaults=defaults,
178 defaults=defaults,
173 encoding="UTF-8",
179 encoding="UTF-8",
174 force_defaults=False
180 force_defaults=False
175 )
181 )
@@ -1,126 +1,142 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # database managment for hg app
3 # database managment for hg app
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5
5
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20
20
21 """
21 """
22 Created on April 10, 2010
22 Created on April 10, 2010
23 database managment and creation for hg app
23 database managment and creation for hg app
24 @author: marcink
24 @author: marcink
25 """
25 """
26
26
27 from os.path import dirname as dn, join as jn
27 from os.path import dirname as dn, join as jn
28 import os
28 import os
29 import sys
29 import sys
30 ROOT = dn(dn(dn(os.path.realpath(__file__))))
30 ROOT = dn(dn(dn(os.path.realpath(__file__))))
31 sys.path.append(ROOT)
31 sys.path.append(ROOT)
32
32
33 from pylons_app.lib.auth import get_crypt_password
33 from pylons_app.lib.auth import get_crypt_password
34 from pylons_app.model import init_model
34 from pylons_app.model import init_model
35 from pylons_app.model.db import User, Permission
35 from pylons_app.model.db import User, Permission
36 from pylons_app.model.meta import Session, Base
36 from pylons_app.model.meta import Session, Base
37 from sqlalchemy.engine import create_engine
37 from sqlalchemy.engine import create_engine
38 import logging
38 import logging
39
39
40 log = logging.getLogger('db manage')
40 log = logging.getLogger('db manage')
41 log.setLevel(logging.DEBUG)
41 log.setLevel(logging.DEBUG)
42 console_handler = logging.StreamHandler()
42 console_handler = logging.StreamHandler()
43 console_handler.setFormatter(logging.Formatter("%(asctime)s.%(msecs)03d"
43 console_handler.setFormatter(logging.Formatter("%(asctime)s.%(msecs)03d"
44 " %(levelname)-5.5s [%(name)s] %(message)s"))
44 " %(levelname)-5.5s [%(name)s] %(message)s"))
45 log.addHandler(console_handler)
45 log.addHandler(console_handler)
46
46
47 class DbManage(object):
47 class DbManage(object):
48 def __init__(self, log_sql):
48 def __init__(self, log_sql):
49 self.dbname = 'hg_app.db'
49 self.dbname = 'hg_app.db'
50 dburi = 'sqlite:////%s' % jn(ROOT, self.dbname)
50 dburi = 'sqlite:////%s' % jn(ROOT, self.dbname)
51 engine = create_engine(dburi, echo=log_sql)
51 engine = create_engine(dburi, echo=log_sql)
52 init_model(engine)
52 init_model(engine)
53 self.sa = Session()
53 self.sa = Session()
54 self.db_exists = False
54 self.db_exists = False
55
55
56 def check_for_db(self, override):
56 def check_for_db(self, override):
57 log.info('checking for exisiting db')
57 log.info('checking for exisiting db')
58 if os.path.isfile(jn(ROOT, self.dbname)):
58 if os.path.isfile(jn(ROOT, self.dbname)):
59 self.db_exists = True
59 self.db_exists = True
60 log.info('database exisist')
60 log.info('database exisist')
61 if not override:
61 if not override:
62 raise Exception('database already exists')
62 raise Exception('database already exists')
63
63
64 def create_tables(self, override=False):
64 def create_tables(self, override=False):
65 """
65 """
66 Create a auth database
66 Create a auth database
67 """
67 """
68 self.check_for_db(override)
68 self.check_for_db(override)
69 if override:
69 if override:
70 log.info("database exisist and it's going to be destroyed")
70 log.info("database exisist and it's going to be destroyed")
71 if self.db_exists:
71 if self.db_exists:
72 os.remove(jn(ROOT, self.dbname))
72 os.remove(jn(ROOT, self.dbname))
73 Base.metadata.create_all(checkfirst=override)
73 Base.metadata.create_all(checkfirst=override)
74 log.info('Created tables for %s', self.dbname)
74 log.info('Created tables for %s', self.dbname)
75
75
76 def admin_prompt(self):
76 def admin_prompt(self):
77 import getpass
77 import getpass
78 username = raw_input('Specify admin username:')
78 username = raw_input('Specify admin username:')
79 password = getpass.getpass('Specify admin password:')
79 password = getpass.getpass('Specify admin password:')
80 self.create_user(username, password, True)
80 self.create_user(username, password, True)
81
81
82 def create_user(self, username, password, admin=False):
82 def create_user(self, username, password, admin=False):
83
84 log.info('creating default user')
85 #create default user for handling default permissions.
86 def_user = User()
87 def_user.username = 'default'
88 def_user.password = 'default'
89 def_user.name = 'default'
90 def_user.lastname = 'default'
91 def_user.email = 'default@default'
92 def_user.admin = False
93 def_user.active = False
94
95 self.sa.add(def_user)
96
83 log.info('creating administrator user %s', username)
97 log.info('creating administrator user %s', username)
84
85 new_user = User()
98 new_user = User()
86 new_user.username = username
99 new_user.username = username
87 new_user.password = get_crypt_password(password)
100 new_user.password = get_crypt_password(password)
88 new_user.name = 'Admin'
101 new_user.name = 'Hg'
89 new_user.lastname = 'Admin'
102 new_user.lastname = 'Admin'
90 new_user.email = 'admin@localhost'
103 new_user.email = 'admin@localhost'
91 new_user.admin = admin
104 new_user.admin = admin
92 new_user.active = True
105 new_user.active = True
93
106
94 try:
107 try:
95 self.sa.add(new_user)
108 self.sa.add(new_user)
96 self.sa.commit()
109 self.sa.commit()
97 except:
110 except:
98 self.sa.rollback()
111 self.sa.rollback()
99 raise
112 raise
100
113
101 def create_permissions(self):
114 def create_permissions(self):
102 #module.(access|create|change|delete)_[name]
115 #module.(access|create|change|delete)_[name]
103 perms = [('admin.access_home', 'Access to admin user view'),
116 #module.(read|write|owner)
104
117 perms = [('repository.none', 'Repository no access'),
118 ('repository.read', 'Repository read access'),
119 ('repository.write', 'Repository write access'),
120 ('repository.admin', 'Repository admin access'),
105 ]
121 ]
106
122
107 for p in perms:
123 for p in perms:
108 new_perm = Permission()
124 new_perm = Permission()
109 new_perm.permission_name = p[0]
125 new_perm.permission_name = p[0]
110 new_perm.permission_longname = p[1]
126 new_perm.permission_longname = p[1]
111 try:
127 try:
112 self.sa.add(new_perm)
128 self.sa.add(new_perm)
113 self.sa.commit()
129 self.sa.commit()
114 except:
130 except:
115 self.sa.rollback()
131 self.sa.rollback()
116 raise
132 raise
117
133
118
134
119
135
120 if __name__ == '__main__':
136 if __name__ == '__main__':
121 dbmanage = DbManage(log_sql=True)
137 dbmanage = DbManage(log_sql=True)
122 dbmanage.create_tables(override=True)
138 dbmanage.create_tables(override=True)
123 dbmanage.admin_prompt()
139 dbmanage.admin_prompt()
124 dbmanage.create_permissions()
140 dbmanage.create_permissions()
125
141
126
142
@@ -1,55 +1,71 b''
1 from pylons_app.model.meta import Base
1 from pylons_app.model.meta import Base
2 from sqlalchemy.orm import relation, backref
2 from sqlalchemy.orm import relation, backref
3 from sqlalchemy import *
3 from sqlalchemy import *
4 from vcs.utils.lazy import LazyProperty
4 from vcs.utils.lazy import LazyProperty
5
5
6 class User(Base):
6 class User(Base):
7 __tablename__ = 'users'
7 __tablename__ = 'users'
8 __table_args__ = {'useexisting':True}
8 __table_args__ = {'useexisting':True}
9 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
9 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
10 username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
10 username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
11 password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
11 password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
12 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
12 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
13 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=None)
13 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=None)
14 name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
14 name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
15 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
15 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
16 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
16 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
17 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
17 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
18
18
19 user_log = relation('UserLog')
19 user_log = relation('UserLog')
20
20
21 @LazyProperty
21 @LazyProperty
22 def full_contact(self):
22 def full_contact(self):
23 return '%s %s <%s>' % (self.name, self.lastname, self.email)
23 return '%s %s <%s>' % (self.name, self.lastname, self.email)
24
24
25 def __repr__(self):
25 def __repr__(self):
26 return "<User('%s:%s')>" % (self.user_id, self.username)
26 return "<User('%s:%s')>" % (self.user_id, self.username)
27
27
28 class UserLog(Base):
28 class UserLog(Base):
29 __tablename__ = 'user_logs'
29 __tablename__ = 'user_logs'
30 __table_args__ = {'useexisting':True}
30 __table_args__ = {'useexisting':True}
31 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
31 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
32 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
32 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
33 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
33 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
34 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_name'), nullable=False, unique=None, default=None)
34 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
35 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
35 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
36 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
36
37
37 user = relation('User')
38 user = relation('User')
38
39
39 class Repository(Base):
40 class Repository(Base):
40 __tablename__ = 'repositories'
41 __tablename__ = 'repositories'
42 __table_args__ = {'useexisting':True}
41 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None, primary_key=True)
43 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None, primary_key=True)
42 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
44 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
43 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
45 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
44 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
46 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
47
45 user = relation('User')
48 user = relation('User')
49 repo2perm = relation('Repo2Perm', cascade='all')
46
50
47 class Permission(Base):
51 class Permission(Base):
48 __tablename__ = 'permissions'
52 __tablename__ = 'permissions'
49 __table_args__ = {'useexisting':True}
53 __table_args__ = {'useexisting':True}
50 permission_id = Column("id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
54 permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
51 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
55 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
52 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
56 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
53
57
54 def __repr__(self):
58 def __repr__(self):
55 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
59 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
60
61 class Repo2Perm(Base):
62 __tablename__ = 'repo_to_perm'
63 __table_args__ = (UniqueConstraint('user_id', 'permission_id', 'repository'), {'useexisting':True})
64 repo2perm_id = Column("repo2perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
65 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
66 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
67 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_name'), nullable=False, unique=None, default=None)
68
69 user = relation('User')
70 permission = relation('Permission')
71
@@ -1,203 +1,238 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 from formencode import All
22 from formencode import All
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
24 Email, Bool, StringBoolean
24 Email, Bool, StringBoolean
25 from pylons import session
25 from pylons import session
26 from pylons.i18n.translation import _
26 from pylons.i18n.translation import _
27 from pylons_app.lib.auth import get_crypt_password
27 from pylons_app.lib.auth import get_crypt_password
28 import pylons_app.lib.helpers as h
28 import pylons_app.lib.helpers as h
29 from pylons_app.model import meta
29 from pylons_app.model import meta
30 from pylons_app.model.db import User, Repository
30 from pylons_app.model.db import User, Repository
31 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.exc import OperationalError
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34 import datetime
34 import datetime
35 import formencode
35 import formencode
36 import logging
36 import logging
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 #this is needed to translate the messages using _() in validators
40 #this is needed to translate the messages using _() in validators
41 class State_obj(object):
41 class State_obj(object):
42 _ = staticmethod(_)
42 _ = staticmethod(_)
43
43
44 #===============================================================================
44 #===============================================================================
45 # VALIDATORS
45 # VALIDATORS
46 #===============================================================================
46 #===============================================================================
47 class ValidAuthToken(formencode.validators.FancyValidator):
47 class ValidAuthToken(formencode.validators.FancyValidator):
48 messages = {'invalid_token':_('Token mismatch')}
48 messages = {'invalid_token':_('Token mismatch')}
49
49
50 def validate_python(self, value, state):
50 def validate_python(self, value, state):
51
51
52 if value != authentication_token():
52 if value != authentication_token():
53 raise formencode.Invalid(self.message('invalid_token', state,
53 raise formencode.Invalid(self.message('invalid_token', state,
54 search_number=value), value, state)
54 search_number=value), value, state)
55 class ValidUsername(formencode.validators.FancyValidator):
55 class ValidUsername(formencode.validators.FancyValidator):
56
56
57 def validate_python(self, value, state):
57 def validate_python(self, value, state):
58 pass
58 if value in ['default', 'new_user']:
59 raise formencode.Invalid(_('Invalid username'), value, state)
59
60
60 class ValidPassword(formencode.validators.FancyValidator):
61 class ValidPassword(formencode.validators.FancyValidator):
61
62
62 def to_python(self, value, state):
63 def to_python(self, value, state):
63 return get_crypt_password(value)
64 return get_crypt_password(value)
64
65
65 class ValidAuth(formencode.validators.FancyValidator):
66 class ValidAuth(formencode.validators.FancyValidator):
66 messages = {
67 messages = {
67 'invalid_password':_('invalid password'),
68 'invalid_password':_('invalid password'),
68 'invalid_login':_('invalid user name'),
69 'invalid_login':_('invalid user name'),
69 'disabled_account':_('Your acccount is disabled')
70 'disabled_account':_('Your acccount is disabled')
70
71
71 }
72 }
72 #error mapping
73 #error mapping
73 e_dict = {'username':messages['invalid_login'],
74 e_dict = {'username':messages['invalid_login'],
74 'password':messages['invalid_password']}
75 'password':messages['invalid_password']}
75 e_dict_disable = {'username':messages['disabled_account']}
76 e_dict_disable = {'username':messages['disabled_account']}
76
77
77 def validate_python(self, value, state):
78 def validate_python(self, value, state):
78 sa = meta.Session
79 sa = meta.Session
79 crypted_passwd = get_crypt_password(value['password'])
80 crypted_passwd = get_crypt_password(value['password'])
80 username = value['username']
81 username = value['username']
81 try:
82 try:
82 user = sa.query(User).filter(User.username == username).one()
83 user = sa.query(User).filter(User.username == username).one()
83 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
84 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
84 log.error(e)
85 log.error(e)
85 user = None
86 user = None
86 raise formencode.Invalid(self.message('invalid_password',
87 raise formencode.Invalid(self.message('invalid_password',
87 state=State_obj), value, state,
88 state=State_obj), value, state,
88 error_dict=self.e_dict)
89 error_dict=self.e_dict)
89 if user:
90 if user:
90 if user.active:
91 if user.active:
91 if user.username == username and user.password == crypted_passwd:
92 if user.username == username and user.password == crypted_passwd:
92 from pylons_app.lib.auth import AuthUser
93 from pylons_app.lib.auth import AuthUser
93 auth_user = AuthUser()
94 auth_user = AuthUser()
94 auth_user.username = username
95 auth_user.username = username
95 auth_user.is_authenticated = True
96 auth_user.is_authenticated = True
96 auth_user.is_admin = user.admin
97 auth_user.is_admin = user.admin
97 auth_user.user_id = user.user_id
98 auth_user.user_id = user.user_id
98 session['hg_app_user'] = auth_user
99 session['hg_app_user'] = auth_user
99 session.save()
100 session.save()
100 log.info('user %s is now authenticated', username)
101 log.info('user %s is now authenticated', username)
101
102
102 try:
103 try:
103 user.last_login = datetime.datetime.now()
104 user.last_login = datetime.datetime.now()
104 sa.add(user)
105 sa.add(user)
105 sa.commit()
106 sa.commit()
106 except (OperationalError) as e:
107 except (OperationalError) as e:
107 log.error(e)
108 log.error(e)
108 sa.rollback()
109 sa.rollback()
109
110
110 return value
111 return value
111 else:
112 else:
112 log.warning('user %s not authenticated', username)
113 log.warning('user %s not authenticated', username)
113 raise formencode.Invalid(self.message('invalid_password',
114 raise formencode.Invalid(self.message('invalid_password',
114 state=State_obj), value, state,
115 state=State_obj), value, state,
115 error_dict=self.e_dict)
116 error_dict=self.e_dict)
116 else:
117 else:
117 log.warning('user %s is disabled', username)
118 log.warning('user %s is disabled', username)
118 raise formencode.Invalid(self.message('disabled_account',
119 raise formencode.Invalid(self.message('disabled_account',
119 state=State_obj),
120 state=State_obj),
120 value, state,
121 value, state,
121 error_dict=self.e_dict_disable)
122 error_dict=self.e_dict_disable)
122
123
123
124
124 class ValidRepoUser(formencode.validators.FancyValidator):
125 class ValidRepoUser(formencode.validators.FancyValidator):
125
126
126 def to_python(self, value, state):
127 def to_python(self, value, state):
127 sa = meta.Session
128 sa = meta.Session
128 try:
129 try:
129 self.user_db = sa.query(User).filter(User.username == value).one()
130 self.user_db = sa.query(User).filter(User.username == value).one()
130 except Exception:
131 except Exception:
131 raise formencode.Invalid(_('This username is not valid'),
132 raise formencode.Invalid(_('This username is not valid'),
132 value, state)
133 value, state)
133 return self.user_db.user_id
134 return self.user_db.user_id
134
135
135 def ValidRepoName(edit=False):
136 def ValidRepoName(edit=False):
136 class _ValidRepoName(formencode.validators.FancyValidator):
137 class _ValidRepoName(formencode.validators.FancyValidator):
137
138
138 def to_python(self, value, state):
139 def to_python(self, value, state):
139 slug = h.repo_name_slug(value)
140 slug = h.repo_name_slug(value)
140
141
141 sa = meta.Session
142 sa = meta.Session
142 if sa.query(Repository).get(slug) and not edit:
143 if sa.query(Repository).get(slug) and not edit:
143 raise formencode.Invalid(_('This repository already exists'),
144 raise formencode.Invalid(_('This repository already exists'),
144 value, state)
145 value, state)
145
146
146 return slug
147 return slug
147 return _ValidRepoName
148 return _ValidRepoName
149
150 class ValidPerms(formencode.validators.FancyValidator):
151 messages = {'perm_new_user_name':_('This username is not valid')}
152
153 def to_python(self, value, state):
154 perms_update = []
155 perms_new = []
156 #build a list of permission to update and new permission to create
157 for k, v in value.items():
158 print k, v
159 if k.startswith('perm_'):
160 if k.startswith('perm_new_user'):
161 new_perm = value.get('perm_new_user', False)
162 new_user = value.get('perm_new_user_name', False)
163 if new_user and new_perm:
164 if (new_user, new_perm) not in perms_new:
165 perms_new.append((new_user, new_perm))
166 else:
167 perms_update.append((k[5:], v))
168 #clear from form list
169 #del value[k]
170 value['perms_updates'] = perms_update
171 value['perms_new'] = perms_new
172 sa = meta.Session
173 for k, v in perms_new:
174 try:
175 self.user_db = sa.query(User).filter(User.username == k).one()
176 except Exception:
177 msg = self.message('perm_new_user_name',
178 state=State_obj)
179 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
180 return value
181
148 #===============================================================================
182 #===============================================================================
149 # FORMS
183 # FORMS
150 #===============================================================================
184 #===============================================================================
151 class LoginForm(formencode.Schema):
185 class LoginForm(formencode.Schema):
152 allow_extra_fields = True
186 allow_extra_fields = True
153 filter_extra_fields = True
187 filter_extra_fields = True
154 username = UnicodeString(
188 username = UnicodeString(
155 strip=True,
189 strip=True,
156 min=3,
190 min=3,
157 not_empty=True,
191 not_empty=True,
158 messages={
192 messages={
159 'empty':_('Please enter a login'),
193 'empty':_('Please enter a login'),
160 'tooShort':_('Enter a value %(min)i characters long or more')}
194 'tooShort':_('Enter a value %(min)i characters long or more')}
161 )
195 )
162
196
163 password = UnicodeString(
197 password = UnicodeString(
164 strip=True,
198 strip=True,
165 min=3,
199 min=3,
166 not_empty=True,
200 not_empty=True,
167 messages={
201 messages={
168 'empty':_('Please enter a password'),
202 'empty':_('Please enter a password'),
169 'tooShort':_('Enter a value %(min)i characters long or more')}
203 'tooShort':_('Enter a value %(min)i characters long or more')}
170 )
204 )
171
205
172
206
173 #chained validators have access to all data
207 #chained validators have access to all data
174 chained_validators = [ValidAuth]
208 chained_validators = [ValidAuth]
175
209
176 def UserForm(edit=False):
210 def UserForm(edit=False):
177 class _UserForm(formencode.Schema):
211 class _UserForm(formencode.Schema):
178 allow_extra_fields = True
212 allow_extra_fields = True
179 filter_extra_fields = True
213 filter_extra_fields = True
180 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername)
214 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername)
181 if edit:
215 if edit:
182 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
216 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
183 else:
217 else:
184 password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
218 password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
185 active = StringBoolean(if_missing=False)
219 active = StringBoolean(if_missing=False)
186 name = UnicodeString(strip=True, min=3, not_empty=True)
220 name = UnicodeString(strip=True, min=3, not_empty=True)
187 lastname = UnicodeString(strip=True, min=3, not_empty=True)
221 lastname = UnicodeString(strip=True, min=3, not_empty=True)
188 email = Email(not_empty=True)
222 email = Email(not_empty=True)
189
223
190 return _UserForm
224 return _UserForm
191
225
192 def RepoForm(edit=False):
226 def RepoForm(edit=False):
193 class _RepoForm(formencode.Schema):
227 class _RepoForm(formencode.Schema):
194 allow_extra_fields = True
228 allow_extra_fields = True
195 filter_extra_fields = True
229 filter_extra_fields = False
196 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit))
230 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit))
197 description = UnicodeString(strip=True, min=3, not_empty=True)
231 description = UnicodeString(strip=True, min=3, not_empty=True)
198 private = StringBoolean(if_missing=False)
232 private = StringBoolean(if_missing=False)
199
233
200 if edit:
234 if edit:
201 user = All(Int(not_empty=True), ValidRepoUser)
235 user = All(Int(not_empty=True), ValidRepoUser)
202
236
237 chained_validators = [ValidPerms]
203 return _RepoForm
238 return _RepoForm
@@ -1,106 +1,145 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # model for handling repositories actions
3 # model for handling repositories actions
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
8 # of the License or (at your opinion) any later version of the license.
8 # of the License or (at your opinion) any later version of the license.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA 02110-1301, USA.
18 # MA 02110-1301, USA.
19
19
20 """
20 """
21 Created on Jun 5, 2010
21 Created on Jun 5, 2010
22 model for handling repositories actions
22 model for handling repositories actions
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from pylons_app.model.meta import Session
25 from pylons_app.model.meta import Session
26 from pylons_app.model.db import Repository
26 from pylons_app.model.db import Repository, Repo2Perm, User, Permission
27 import shutil
27 import shutil
28 import os
28 import os
29 from datetime import datetime
29 from datetime import datetime
30 from pylons_app.lib.utils import check_repo
30 from pylons_app.lib.utils import check_repo
31 from pylons import app_globals as g
31 from pylons import app_globals as g
32 import traceback
32 import logging
33 import logging
33 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
34
35
35 class RepoModel(object):
36 class RepoModel(object):
36
37
37 def __init__(self):
38 def __init__(self):
38 self.sa = Session()
39 self.sa = Session()
39
40
40 def get(self, id):
41 def get(self, id):
41 return self.sa.query(Repository).get(id)
42 return self.sa.query(Repository).get(id)
42
43
43
44
44 def update(self, id, form_data):
45 def update(self, repo_id, form_data):
45 try:
46 try:
46 if id != form_data['repo_name']:
47 if repo_id != form_data['repo_name']:
47 self.__rename_repo(id, form_data['repo_name'])
48 self.__rename_repo(repo_id, form_data['repo_name'])
48 cur_repo = self.sa.query(Repository).get(id)
49 cur_repo = self.sa.query(Repository).get(repo_id)
49 for k, v in form_data.items():
50 for k, v in form_data.items():
50 if k == 'user':
51 if k == 'user':
51 cur_repo.user_id = v
52 cur_repo.user_id = v
52 else:
53 else:
53 setattr(cur_repo, k, v)
54 setattr(cur_repo, k, v)
55
56 #update permissions
57 for username, perm in form_data['perms_updates']:
58 r2p = self.sa.query(Repo2Perm)\
59 .filter(Repo2Perm.user == self.sa.query(User)\
60 .filter(User.username == username).one())\
61 .filter(Repo2Perm.repository == repo_id).one()
54
62
63 r2p.permission_id = self.sa.query(Permission).filter(
64 Permission.permission_name ==
65 perm).one().permission_id
66 self.sa.add(r2p)
67
68 for username, perm in form_data['perms_new']:
69 r2p = Repo2Perm()
70 r2p.repository = repo_id
71 r2p.user = self.sa.query(User)\
72 .filter(User.username == username).one()
73
74 r2p.permission_id = self.sa.query(Permission).filter(
75 Permission.permission_name ==
76 perm).one().permission_id
77 self.sa.add(r2p)
78
55 self.sa.add(cur_repo)
79 self.sa.add(cur_repo)
56 self.sa.commit()
80 self.sa.commit()
57 except Exception as e:
81 except:
58 log.error(e)
82 log.error(traceback.format_exc())
59 self.sa.rollback()
83 self.sa.rollback()
60 raise
84 raise
61
85
62 def create(self, form_data, cur_user):
86 def create(self, form_data, cur_user, just_db=False):
63 try:
87 try:
88 repo_name = form_data['repo_name']
64 new_repo = Repository()
89 new_repo = Repository()
65 for k, v in form_data.items():
90 for k, v in form_data.items():
66 setattr(new_repo, k, v)
91 setattr(new_repo, k, v)
67
92
68 new_repo.user_id = cur_user.user_id
93 new_repo.user_id = cur_user.user_id
69 self.sa.add(new_repo)
94 self.sa.add(new_repo)
95
96 #create default permission
97 repo2perm = Repo2Perm()
98 repo2perm.permission_id = self.sa.query(Permission)\
99 .filter(Permission.permission_name == 'repository.read')\
100 .one().permission_id
101
102 repo2perm.repository = repo_name
103 repo2perm.user_id = self.sa.query(User)\
104 .filter(User.username == 'default').one().user_id
105
106 self.sa.add(repo2perm)
70 self.sa.commit()
107 self.sa.commit()
71 self.__create_repo(form_data['repo_name'])
108 if not just_db:
72 except Exception as e:
109 self.__create_repo(repo_name)
73 log.error(e)
110 except:
111 log.error(traceback.format_exc())
74 self.sa.rollback()
112 self.sa.rollback()
75 raise
113 raise
76
114
77 def delete(self, repo):
115 def delete(self, repo):
78 try:
116 try:
79 self.sa.delete(repo)
117 self.sa.delete(repo)
80 self.sa.commit()
118 self.sa.commit()
81 self.__delete_repo(repo.repo_name)
119 self.__delete_repo(repo.repo_name)
82 except Exception as e:
120 except:
83 log.error(e)
121 log.error(traceback.format_exc())
84 self.sa.rollback()
122 self.sa.rollback()
85 raise
123 raise
86
124
87 def __create_repo(self, repo_name):
125 def __create_repo(self, repo_name):
88 repo_path = os.path.join(g.base_path, repo_name)
126 repo_path = os.path.join(g.base_path, repo_name)
89 if check_repo(repo_name, g.base_path):
127 if check_repo(repo_name, g.base_path):
90 log.info('creating repo %s in %s', repo_name, repo_path)
128 log.info('creating repo %s in %s', repo_name, repo_path)
91 from vcs.backends.hg import MercurialRepository
129 from vcs.backends.hg import MercurialRepository
92 MercurialRepository(repo_path, create=True)
130 MercurialRepository(repo_path, create=True)
93
131
94 def __rename_repo(self, old, new):
132 def __rename_repo(self, old, new):
95 log.info('renaming repoo from %s to %s', old, new)
133 log.info('renaming repoo from %s to %s', old, new)
96 old_path = os.path.join(g.base_path, old)
134 old_path = os.path.join(g.base_path, old)
97 new_path = os.path.join(g.base_path, new)
135 new_path = os.path.join(g.base_path, new)
98 shutil.move(old_path, new_path)
136 shutil.move(old_path, new_path)
99
137
100 def __delete_repo(self, name):
138 def __delete_repo(self, name):
101 rm_path = os.path.join(g.base_path, name)
139 rm_path = os.path.join(g.base_path, name)
102 log.info("Removing %s", rm_path)
140 log.info("Removing %s", rm_path)
103 #disable hg
141 #disable hg
104 shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
142 shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
105 #disable repo
143 #disable repo
106 shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s-%s' % (datetime.today(), id)))
144 shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
145 % (datetime.today(), name)))
@@ -1,49 +1,109 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Repositories administration')}
5 ${_('Repositories administration')}
6 </%def>
6 </%def>
7 <%def name="breadcrumbs()">
7 <%def name="breadcrumbs()">
8 ${h.link_to(u'Admin',h.url('admin_home'))}
8 ${h.link_to(u'Admin',h.url('admin_home'))}
9 /
9 /
10 ${_('Repos')}
10 ${_('Repos')}
11 </%def>
11 </%def>
12 <%def name="page_nav()">
12 <%def name="page_nav()">
13 ${self.menu('admin')}
13 ${self.menu('admin')}
14 ${self.submenu('repos')}
14 ${self.submenu('repos')}
15 </%def>
15 </%def>
16 <%def name="main()">
16 <%def name="main()">
17 <div>
17 <div>
18 <h2>${_('Repositories')} - ${_('edit')}</h2>
18 <h2>${_('Repositories')} - ${_('edit')}</h2>
19 ${h.form(url('repo', id=c.repo_info.repo_name),method='put')}
19 ${h.form(url('repo', id=c.repo_info.repo_name),method='put')}
20 <table>
20 <table>
21 <tr>
21 <tr>
22 <td>${_('Name')}</td>
22 <td>${_('Name')}</td>
23 <td>${h.text('repo_name')}</td>
23 <td>${h.text('repo_name')}</td>
24 <td>${self.get_form_error('repo_name')}</td>
24 <td>${self.get_form_error('repo_name')}</td>
25 </tr>
25 </tr>
26 <tr>
26 <tr>
27 <td>${_('Description')}</td>
27 <td>${_('Description')}</td>
28 <td>${h.textarea('description',cols=23,rows=5)}</td>
28 <td>${h.textarea('description',cols=23,rows=5)}</td>
29 <td>${self.get_form_error('description')}</td>
29 <td>${self.get_form_error('description')}</td>
30 </tr>
30 </tr>
31 <tr>
31 <tr>
32 <td>${_('Private')}</td>
32 <td>${_('Private')}</td>
33 <td>${h.checkbox('private')}</td>
33 <td>${h.checkbox('private')}</td>
34 <td>${self.get_form_error('private')}</td>
34 <td>${self.get_form_error('private')}</td>
35 </tr>
35 </tr>
36 <tr>
36 <tr>
37 <td>${_('Owner')}</td>
37 <td>${_('Owner')}</td>
38 <td>${h.text('user')}</td>
38 <td>${h.text('user')}</td>
39 <td>${self.get_form_error('user')}</td>
39 <td>${self.get_form_error('user')}</td>
40 </tr>
40 </tr>
41 <tr>
41 <tr>
42 <td>${_('Permissions')}</td>
43 <td>
44 <table>
45 <tr>
46 <td>${_('none')}</td>
47 <td>${_('read')}</td>
48 <td>${_('write')}</td>
49 <td>${_('admin')}</td>
50 <td>${_('user')}</td>
51 </tr>
52
53 %for r2p in c.repo_info.repo2perm:
54 <tr>
55 <td>${h.radio('perm_%s' % r2p.user.username,'repository.none')}</td>
56 <td>${h.radio('perm_%s' % r2p.user.username,'repository.read')}</td>
57 <td>${h.radio('perm_%s' % r2p.user.username,'repository.write')}</td>
58 <td>${h.radio('perm_%s' % r2p.user.username,'repository.admin')}</td>
59 <td>${r2p.user.username}</td>
60 </tr>
61 %endfor
62
63
64 <%
65
66 if not hasattr(c,'form_errors'):
67 d = 'display:none;'
68 else:
69 d=''
70 %>
71
72 <tr id="add_perm_input" style="${d}">
73 <td>${h.radio('perm_new_user','repository.none')}</td>
74 <td>${h.radio('perm_new_user','repository.read')}</td>
75 <td>${h.radio('perm_new_user','repository.write')}</td>
76 <td>${h.radio('perm_new_user','repository.admin')}</td>
77 <td>${h.text('perm_new_user_name',size=10)}</td>
78 <td>${self.get_form_error('perm_new_user_name')}</td>
79 </tr>
80 <tr>
81 <td colspan="4">
82 <span id="add_perm" class="add_icon" style="cursor: pointer;">
83 ${_('Add another user')}
84 </span>
85 </td>
86 </tr>
87 </table>
88 </td>
89
90 </tr>
91 <tr>
42 <td></td>
92 <td></td>
43 <td>${h.submit('update','update')}</td>
93 <td>${h.submit('update','update')}</td>
44 </tr>
94 </tr>
45
95
46 </table>
96 </table>
47 ${h.end_form()}
97 ${h.end_form()}
98 <script type="text/javascript">
99 YAHOO.util.Event.onDOMReady(function(){
100 var D = YAHOO.util.Dom;
101 YAHOO.util.Event.addListener('add_perm','click',function(){
102 D.setStyle('add_perm_input','display','');
103 D.setStyle('add_perm','opacity','0.6');
104 D.setStyle('add_perm','cursor','default');
105 });
106 });
107 </script>
48 </div>
108 </div>
49 </%def>
109 </%def>
General Comments 0
You need to be logged in to leave comments. Login now