##// END OF EJS Templates
Implemented basic repository managment. Implemented repo2db mappings, model, helpers updates and code cleanups
marcink -
r265:0e5455fd default
parent child Browse files
Show More
@@ -0,0 +1,106 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # model for handling repositories actions
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
8 # of the License or (at your opinion) any later version of the license.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
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
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA 02110-1301, USA.
19
20 """
21 Created on Jun 5, 2010
22 model for handling repositories actions
23 @author: marcink
24 """
25 from pylons_app.model.meta import Session
26 from pylons_app.model.db import Repository
27 import shutil
28 import os
29 from datetime import datetime
30 from pylons_app.lib.utils import check_repo
31 from pylons import app_globals as g
32 import logging
33 log = logging.getLogger(__name__)
34
35 class RepoModel(object):
36
37 def __init__(self):
38 self.sa = Session()
39
40 def get(self, id):
41 return self.sa.query(Repository).get(id)
42
43
44 def update(self, id, form_data):
45 try:
46 if id != form_data['repo_name']:
47 self.__rename_repo(id, form_data['repo_name'])
48 cur_repo = self.sa.query(Repository).get(id)
49 for k, v in form_data.items():
50 if k == 'user':
51 cur_repo.user_id = v
52 else:
53 setattr(cur_repo, k, v)
54
55 self.sa.add(cur_repo)
56 self.sa.commit()
57 except Exception as e:
58 log.error(e)
59 self.sa.rollback()
60 raise
61
62 def create(self, form_data, cur_user):
63 try:
64 new_repo = Repository()
65 for k, v in form_data.items():
66 setattr(new_repo, k, v)
67
68 new_repo.user_id = cur_user.user_id
69 self.sa.add(new_repo)
70 self.sa.commit()
71 self.__create_repo(form_data['repo_name'])
72 except Exception as e:
73 log.error(e)
74 self.sa.rollback()
75 raise
76
77 def delete(self, repo):
78 try:
79 self.sa.delete(repo)
80 self.sa.commit()
81 self.__delete_repo(repo.repo_name)
82 except Exception as e:
83 log.error(e)
84 self.sa.rollback()
85 raise
86
87 def __create_repo(self, repo_name):
88 repo_path = os.path.join(g.base_path, repo_name)
89 if check_repo(repo_name, g.base_path):
90 log.info('creating repo %s in %s', repo_name, repo_path)
91 from vcs.backends.hg import MercurialRepository
92 MercurialRepository(repo_path, create=True)
93
94 def __rename_repo(self, old, new):
95 log.info('renaming repoo from %s to %s', old, new)
96 old_path = os.path.join(g.base_path, old)
97 new_path = os.path.join(g.base_path, new)
98 shutil.move(old_path, new_path)
99
100 def __delete_repo(self, name):
101 rm_path = os.path.join(g.base_path, name)
102 log.info("Removing %s", rm_path)
103 #disable hg
104 shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
105 #disable repo
106 shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s-%s' % (datetime.today(), id)))
@@ -6,6 +6,7 b' from pylons_app.config.routing import ma'
6 from pylons_app.lib.auth import set_available_permissions
6 from pylons_app.lib.auth import set_available_permissions
7 from pylons_app.lib.utils import repo2db_mapper
7 from pylons_app.lib.utils import repo2db_mapper
8 from pylons_app.model import init_model
8 from pylons_app.model import init_model
9 from pylons_app.model.hg_model import _get_repos_cached_initial
9 from sqlalchemy import engine_from_config
10 from sqlalchemy import engine_from_config
10 import logging
11 import logging
11 import os
12 import os
@@ -60,7 +61,7 b' def load_environment(global_conf, app_co'
60 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.')
61 sa_engine_db1 = engine_from_config(config, 'sqlalchemy.db1.')
61
62
62 init_model(sa_engine_db1)
63 init_model(sa_engine_db1)
63 repo2db_mapper()
64 repo2db_mapper(_get_repos_cached_initial(config['pylons.app_globals']))
64 set_available_permissions(config)
65 set_available_permissions(config)
65 # CONFIGURATION OPTIONS HERE (note: all config options will override
66 # CONFIGURATION OPTIONS HERE (note: all config options will override
66 # any Pylons config options)
67 # any Pylons config options)
@@ -2,7 +2,6 b''
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
6 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
@@ -22,20 +21,25 b' Created on April 7, 2010'
22 admin controller for pylons
21 admin controller for pylons
23 @author: marcink
22 @author: marcink
24 """
23 """
25 import logging
24 from operator import itemgetter
26 from pylons import request, response, session, tmpl_context as c, url, \
25 from pylons import request, response, session, tmpl_context as c, url, \
27 app_globals as g
26 app_globals as g
28 from pylons.controllers.util import abort, redirect
27 from pylons.controllers.util import abort, redirect
29 from pylons_app.lib.auth import LoginRequired
30 from pylons.i18n.translation import _
28 from pylons.i18n.translation import _
31 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
32 from pylons_app.lib.base import BaseController, render
31 from pylons_app.lib.base import BaseController, render
33 from pylons_app.lib.filters import clean_repo
32 from pylons_app.lib.utils import invalidate_cache
34 from pylons_app.lib.utils import check_repo, invalidate_cache
33 from pylons_app.model.repo_model import RepoModel
35 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
36 from pylons_app.model.meta import Session
37 from datetime import datetime
38 import formencode
39 from formencode import htmlfill
40 import logging
36 import os
41 import os
37 import shutil
42 import shutil
38 from operator import itemgetter
39 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
40
44
41 class ReposController(BaseController):
45 class ReposController(BaseController):
@@ -59,30 +63,33 b' class ReposController(BaseController):'
59 def create(self):
63 def create(self):
60 """POST /repos: Create a new item"""
64 """POST /repos: Create a new item"""
61 # url('repos')
65 # url('repos')
62 name = request.POST.get('name')
66 repo_model = RepoModel()
63
67 _form = RepoForm()()
64 try:
68 try:
65 self._create_repo(name)
69 form_result = _form.to_python(dict(request.POST))
66 #clear our cached list for refresh with new repo
70 repo_model.create(form_result, c.hg_app_user)
67 invalidate_cache('cached_repo_list')
71 invalidate_cache('cached_repo_list')
68 h.flash(_('created repository %s') % name, category='success')
72 h.flash(_('created repository %s') % form_result['repo_name'],
69 except Exception as e:
73 category='success')
70 log.error(e)
74
71
75 except formencode.Invalid as errors:
76 c.form_errors = errors.error_dict
77 c.new_repo = errors.value['repo_name']
78 return htmlfill.render(
79 render('admin/repos/repo_add.html'),
80 defaults=errors.value,
81 encoding="UTF-8")
82
83 except Exception:
84 h.flash(_('error occured during creation of repository %s') \
85 % form_result['repo_name'], category='error')
86
72 return redirect('repos')
87 return redirect('repos')
73
74 def _create_repo(self, repo_name):
75 repo_path = os.path.join(g.base_path, repo_name)
76 if check_repo(repo_name, g.base_path):
77 log.info('creating repo %s in %s', repo_name, repo_path)
78 from vcs.backends.hg import MercurialRepository
79 MercurialRepository(repo_path, create=True)
80
81
88
82 def new(self, format='html'):
89 def new(self, format='html'):
83 """GET /repos/new: Form to create a new item"""
90 """GET /repos/new: Form to create a new item"""
84 new_repo = request.GET.get('repo', '')
91 new_repo = request.GET.get('repo', '')
85 c.new_repo = clean_repo(new_repo)
92 c.new_repo = h.repo_name_slug(new_repo)
86
93
87 return render('admin/repos/repo_add.html')
94 return render('admin/repos/repo_add.html')
88
95
@@ -94,7 +101,26 b' class ReposController(BaseController):'
94 # h.form(url('repo', id=ID),
101 # h.form(url('repo', id=ID),
95 # method='put')
102 # method='put')
96 # url('repo', id=ID)
103 # url('repo', id=ID)
97
104 repo_model = RepoModel()
105 _form = RepoForm(edit=True)()
106 try:
107 form_result = _form.to_python(dict(request.POST))
108 repo_model.update(id, form_result)
109 invalidate_cache('cached_repo_list')
110 h.flash(_('Repository updated succesfully'), category='success')
111
112 except formencode.Invalid as errors:
113 c.repo_info = repo_model.get(id)
114 c.form_errors = errors.error_dict
115 return htmlfill.render(
116 render('admin/repos/repo_edit.html'),
117 defaults=errors.value,
118 encoding="UTF-8")
119 except Exception:
120 h.flash(_('error occured during update of repository %s') \
121 % form_result['repo_name'], category='error')
122 return redirect(url('repos'))
123
98 def delete(self, id):
124 def delete(self, id):
99 """DELETE /repos/id: Delete an existing item"""
125 """DELETE /repos/id: Delete an existing item"""
100 # Forms posted to this method should contain a hidden field:
126 # Forms posted to this method should contain a hidden field:
@@ -103,19 +129,25 b' class ReposController(BaseController):'
103 # h.form(url('repo', id=ID),
129 # h.form(url('repo', id=ID),
104 # method='delete')
130 # method='delete')
105 # url('repo', id=ID)
131 # url('repo', id=ID)
106 from datetime import datetime
132
107 path = g.paths[0][1].replace('*', '')
133 repo_model = RepoModel()
108 rm_path = os.path.join(path, id)
134 repo = repo_model.get(id)
109 log.info("Removing %s", rm_path)
135 if not repo:
110 shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
136 h.flash(_('%s repository is not mapped to db perhaps'
111 shutil.move(rm_path, os.path.join(path, 'rm__%s-%s' % (datetime.today(), id)))
137 ' it was moved or renamed please run the application again'
138 ' in order to rescan repositories') % id, category='error')
112
139
113 #clear our cached list for refresh with new repo
140 return redirect(url('repos'))
114 invalidate_cache('cached_repo_list')
141 try:
115 h.flash(_('deleted repository %s') % rm_path, category='success')
142 repo_model.delete(repo)
143 invalidate_cache('cached_repo_list')
144 h.flash(_('deleted repository %s') % id, category='success')
145 except Exception:
146 h.flash(_('An error occured during deletion of %s') % id,
147 category='error')
148
116 return redirect(url('repos'))
149 return redirect(url('repos'))
117
150
118
119 def show(self, id, format='html'):
151 def show(self, id, format='html'):
120 """GET /repos/id: Show a specific item"""
152 """GET /repos/id: Show a specific item"""
121 # url('repo', id=ID)
153 # url('repo', id=ID)
@@ -123,5 +155,13 b' class ReposController(BaseController):'
123 def edit(self, id, format='html'):
155 def edit(self, id, format='html'):
124 """GET /repos/id/edit: Form to edit an existing item"""
156 """GET /repos/id/edit: Form to edit an existing item"""
125 # url('edit_repo', id=ID)
157 # url('edit_repo', id=ID)
126 c.new_repo = id
158 repo_model = RepoModel()
127 return render('admin/repos/repo_edit.html')
159 c.repo_info = repo_model.get(id)
160 defaults = c.repo_info.__dict__
161 defaults.update({'user':c.repo_info.user.username})
162 return htmlfill.render(
163 render('admin/repos/repo_edit.html'),
164 defaults=defaults,
165 encoding="UTF-8",
166 force_defaults=False
167 )
@@ -23,7 +23,6 b' users controller for pylons'
23 @author: marcink
23 @author: marcink
24 """
24 """
25 import logging
25 import logging
26 from formencode import htmlfill
27 from pylons import request, session, tmpl_context as c, url
26 from pylons import request, session, tmpl_context as c, url
28 from pylons.controllers.util import abort, redirect
27 from pylons.controllers.util import abort, redirect
29 from pylons.i18n.translation import _
28 from pylons.i18n.translation import _
@@ -34,6 +33,7 b' from pylons_app.model.db import User, Us'
34 from pylons_app.model.forms import UserForm
33 from pylons_app.model.forms import UserForm
35 from pylons_app.model.user_model import UserModel
34 from pylons_app.model.user_model import UserModel
36 import formencode
35 import formencode
36 from formencode import htmlfill
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
@@ -65,15 +65,18 b' class UsersController(BaseController):'
65 try:
65 try:
66 form_result = login_form.to_python(dict(request.POST))
66 form_result = login_form.to_python(dict(request.POST))
67 user_model.create(form_result)
67 user_model.create(form_result)
68 h.flash(_('created user %s') % form_result['username'], category='success')
68 h.flash(_('created user %s') % form_result['username'],
69 return redirect(url('users'))
69 category='success')
70
71 except formencode.Invalid as errors:
70 except formencode.Invalid as errors:
72 c.form_errors = errors.error_dict
71 c.form_errors = errors.error_dict
73 return htmlfill.render(
72 return htmlfill.render(
74 render('admin/users/user_add.html'),
73 render('admin/users/user_add.html'),
75 defaults=errors.value,
74 defaults=errors.value,
76 encoding="UTF-8")
75 encoding="UTF-8")
76 except Exception:
77 h.flash(_('error occured during creation of user %s') \
78 % form_result['username'], category='error')
79 return redirect(url('users'))
77
80
78 def new(self, format='html'):
81 def new(self, format='html'):
79 """GET /users/new: Form to create a new item"""
82 """GET /users/new: Form to create a new item"""
@@ -89,12 +92,11 b' class UsersController(BaseController):'
89 # method='put')
92 # method='put')
90 # url('user', id=ID)
93 # url('user', id=ID)
91 user_model = UserModel()
94 user_model = UserModel()
92 login_form = UserForm(edit=True)()
95 _form = UserForm(edit=True)()
93 try:
96 try:
94 form_result = login_form.to_python(dict(request.POST))
97 form_result = _form.to_python(dict(request.POST))
95 user_model.update(id, form_result)
98 user_model.update(id, form_result)
96 h.flash(_('User updated succesfully'), category='success')
99 h.flash(_('User updated succesfully'), category='success')
97 return redirect(url('users'))
98
100
99 except formencode.Invalid as errors:
101 except formencode.Invalid as errors:
100 c.user = user_model.get_user(id)
102 c.user = user_model.get_user(id)
@@ -103,7 +105,12 b' class UsersController(BaseController):'
103 render('admin/users/user_edit.html'),
105 render('admin/users/user_edit.html'),
104 defaults=errors.value,
106 defaults=errors.value,
105 encoding="UTF-8")
107 encoding="UTF-8")
106
108 except Exception:
109 h.flash(_('error occured during update of user %s') \
110 % form_result['username'], category='error')
111
112 return redirect(url('users'))
113
107 def delete(self, id):
114 def delete(self, id):
108 """DELETE /users/id: Delete an existing item"""
115 """DELETE /users/id: Delete an existing item"""
109 # Forms posted to this method should contain a hidden field:
116 # Forms posted to this method should contain a hidden field:
@@ -112,13 +119,14 b' class UsersController(BaseController):'
112 # h.form(url('user', id=ID),
119 # h.form(url('user', id=ID),
113 # method='delete')
120 # method='delete')
114 # url('user', id=ID)
121 # url('user', id=ID)
122 user_model = UserModel()
115 try:
123 try:
116 self.sa.delete(self.sa.query(User).get(id))
124 user_model.delete(id)
117 self.sa.commit()
118 h.flash(_('sucessfully deleted user'), category='success')
125 h.flash(_('sucessfully deleted user'), category='success')
119 except:
126 except Exception:
120 self.sa.rollback()
127 h.flash(_('An error occured during deletion of user'),
121 raise
128 category='error')
129
122 return redirect(url('users'))
130 return redirect(url('users'))
123
131
124 def show(self, id, format='html'):
132 def show(self, id, format='html'):
@@ -65,6 +65,7 b' class AuthUser(object):'
65 A simple object that handles a mercurial username for authentication
65 A simple object that handles a mercurial username for authentication
66 """
66 """
67 username = 'None'
67 username = 'None'
68 user_id = None
68 is_authenticated = False
69 is_authenticated = False
69 is_admin = False
70 is_admin = False
70 permissions = set()
71 permissions = set()
@@ -114,11 +114,9 b' def repo_name_slug(value):'
114 Return slug of name of repository
114 Return slug of name of repository
115 """
115 """
116 slug = urlify(value)
116 slug = urlify(value)
117 for c in """=[]\;',/~!@#$%^&*()+{}|:""":
117 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|:""":
118 slug = slug.replace(c, '-')
118 slug = slug.replace(c, '-')
119 print slug
120 slug = recursive_replace(slug, '-')
119 slug = recursive_replace(slug, '-')
121 print slug
122 return slug
120 return slug
123
121
124 files_breadcrumbs = _FilesBreadCrumbs()
122 files_breadcrumbs = _FilesBreadCrumbs()
@@ -28,6 +28,7 b' import os'
28 import logging
28 import logging
29 from mercurial import ui, config, hg
29 from mercurial import ui, config, hg
30 from mercurial.error import RepoError
30 from mercurial.error import RepoError
31 from pylons_app.model.db import Repository, User
31 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
32
33
33
34
@@ -152,9 +153,28 b' class EmptyChangeset(BaseChangeset):'
152 return '0' * 12
153 return '0' * 12
153
154
154
155
155 def repo2db_mapper():
156 def repo2db_mapper(initial_repo_list):
157 """
158 maps all found repositories into db
156 """
159 """
157 scann all dirs for .hgdbid
160 from pylons_app.model.meta import Session
158 if some dir doesn't have one generate one.
161 sa = Session()
159 """
162 user = sa.query(User).filter(User.admin == True).first()
160 pass
163 for name, repo in initial_repo_list.items():
164 if not sa.query(Repository).get(name):
165 log.info('%s not found creating default', name)
166 try:
167
168 new_repo = Repository()
169 new_repo.repo_name = name
170 desc = repo.description if repo.description != 'unknown' else \
171 'auto description for %s' % name
172 new_repo.description = desc
173 new_repo.user_id = user.user_id
174 new_repo.private = False
175 sa.add(new_repo)
176 sa.commit()
177 except:
178 sa.rollback()
179 raise
180
@@ -1,11 +1,12 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
5
5 class User(Base):
6 class User(Base):
6 __tablename__ = 'users'
7 __tablename__ = 'users'
7 __table_args__ = {'useexisting':True}
8 __table_args__ = {'useexisting':True}
8 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
9 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
9 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)
10 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)
11 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
12 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
@@ -17,6 +18,10 b' class User(Base):'
17
18
18 user_log = relation('UserLog')
19 user_log = relation('UserLog')
19
20
21 @LazyProperty
22 def full_contact(self):
23 return '%s %s <%s>' % (self.name, self.lastname, self.email)
24
20 def __repr__(self):
25 def __repr__(self):
21 return "<User('%s:%s')>" % (self.user_id, self.username)
26 return "<User('%s:%s')>" % (self.user_id, self.username)
22
27
@@ -24,7 +29,7 b' class UserLog(Base):'
24 __tablename__ = 'user_logs'
29 __tablename__ = 'user_logs'
25 __table_args__ = {'useexisting':True}
30 __table_args__ = {'useexisting':True}
26 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=1)
27 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
32 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
28 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
33 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
29 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
34 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
30 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
35 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
@@ -33,14 +38,12 b' class UserLog(Base):'
33
38
34 class Repository(Base):
39 class Repository(Base):
35 __tablename__ = 'repositories'
40 __tablename__ = 'repositories'
36 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
41 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None, primary_key=True)
37 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
42 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
38 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
39 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
43 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
40
44 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
41 user = relation('User')
45 user = relation('User')
42
46
43
44 class Permission(Base):
47 class Permission(Base):
45 __tablename__ = 'permissions'
48 __tablename__ = 'permissions'
46 __table_args__ = {'useexisting':True}
49 __table_args__ = {'useexisting':True}
@@ -25,8 +25,9 b' from formencode.validators import Unicod'
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 from pylons_app.model import meta
29 from pylons_app.model import meta
29 from pylons_app.model.db import User
30 from pylons_app.model.db import User, Repository
30 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
@@ -93,6 +94,7 b' class ValidAuth(formencode.validators.Fa'
93 auth_user.username = username
94 auth_user.username = username
94 auth_user.is_authenticated = True
95 auth_user.is_authenticated = True
95 auth_user.is_admin = user.admin
96 auth_user.is_admin = user.admin
97 auth_user.user_id = user.user_id
96 session['hg_app_user'] = auth_user
98 session['hg_app_user'] = auth_user
97 session.save()
99 session.save()
98 log.info('user %s is now authenticated', username)
100 log.info('user %s is now authenticated', username)
@@ -119,7 +121,30 b' class ValidAuth(formencode.validators.Fa'
119 error_dict=self.e_dict_disable)
121 error_dict=self.e_dict_disable)
120
122
121
123
122
124 class ValidRepoUser(formencode.validators.FancyValidator):
125
126 def to_python(self, value, state):
127 sa = meta.Session
128 try:
129 self.user_db = sa.query(User).filter(User.username == value).one()
130 except Exception:
131 raise formencode.Invalid(_('This username is not valid'),
132 value, state)
133 return self.user_db.user_id
134
135 def ValidRepoName(edit=False):
136 class _ValidRepoName(formencode.validators.FancyValidator):
137
138 def to_python(self, value, state):
139 slug = h.repo_name_slug(value)
140
141 sa = meta.Session
142 if sa.query(Repository).get(slug) and not edit:
143 raise formencode.Invalid(_('This repository already exists'),
144 value, state)
145
146 return slug
147 return _ValidRepoName
123 #===============================================================================
148 #===============================================================================
124 # FORMS
149 # FORMS
125 #===============================================================================
150 #===============================================================================
@@ -163,3 +188,16 b' def UserForm(edit=False):'
163 email = Email(not_empty=True)
188 email = Email(not_empty=True)
164
189
165 return _UserForm
190 return _UserForm
191
192 def RepoForm(edit=False):
193 class _RepoForm(formencode.Schema):
194 allow_extra_fields = True
195 filter_extra_fields = True
196 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit))
197 description = UnicodeString(strip=True, min=3, not_empty=True)
198 private = StringBoolean(if_missing=False)
199
200 if edit:
201 user = All(Int(not_empty=True), ValidRepoUser)
202
203 return _RepoForm
@@ -27,8 +27,9 b' Model for hg app'
27 from beaker.cache import cache_region
27 from beaker.cache import cache_region
28 from mercurial import ui
28 from mercurial import ui
29 from mercurial.hgweb.hgwebdir_mod import findrepos
29 from mercurial.hgweb.hgwebdir_mod import findrepos
30 from pylons import app_globals as g
31 from vcs.exceptions import RepositoryError, VCSError
30 from vcs.exceptions import RepositoryError, VCSError
31 from pylons_app.model.meta import Session
32 from pylons_app.model.db import Repository
32 import logging
33 import logging
33 import os
34 import os
34 import sys
35 import sys
@@ -40,12 +41,19 b' except ImportError:'
40 sys.stderr.write('You have to import vcs module')
41 sys.stderr.write('You have to import vcs module')
41 raise Exception('Unable to import vcs')
42 raise Exception('Unable to import vcs')
42
43
44 def _get_repos_cached_initial(app_globals):
45 """
46 return cached dict with repos
47 """
48 g = app_globals
49 return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
43
50
44 @cache_region('long_term', 'cached_repo_list')
51 @cache_region('long_term', 'cached_repo_list')
45 def _get_repos_cached():
52 def _get_repos_cached():
46 """
53 """
47 return cached dict with repos
54 return cached dict with repos
48 """
55 """
56 from pylons import app_globals as g
49 return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
57 return HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
50
58
51 @cache_region('long_term', 'full_changelog')
59 @cache_region('long_term', 'full_changelog')
@@ -62,7 +70,6 b' class HgModel(object):'
62 """
70 """
63 Constructor
71 Constructor
64 """
72 """
65 pass
66
73
67 @staticmethod
74 @staticmethod
68 def repo_scan(repos_prefix, repos_path, baseui):
75 def repo_scan(repos_prefix, repos_path, baseui):
@@ -72,6 +79,7 b' class HgModel(object):'
72 :param repos_path: path to directory it could take syntax with
79 :param repos_path: path to directory it could take syntax with
73 * or ** for deep recursive displaying repositories
80 * or ** for deep recursive displaying repositories
74 """
81 """
82 sa = Session()
75 def check_repo_dir(path):
83 def check_repo_dir(path):
76 """
84 """
77 Checks the repository
85 Checks the repository
@@ -102,8 +110,13 b' class HgModel(object):'
102 raise RepositoryError('Duplicate repository name %s found in'
110 raise RepositoryError('Duplicate repository name %s found in'
103 ' %s' % (name, path))
111 ' %s' % (name, path))
104 else:
112 else:
113
105 repos_list[name] = MercurialRepository(path, baseui=baseui)
114 repos_list[name] = MercurialRepository(path, baseui=baseui)
106 repos_list[name].name = name
115 repos_list[name].name = name
116 dbrepo = sa.query(Repository).get(name)
117 if dbrepo:
118 repos_list[name].description = dbrepo.description
119 repos_list[name].contact = dbrepo.user.full_contact
107 except OSError:
120 except OSError:
108 continue
121 continue
109 return repos_list
122 return repos_list
@@ -26,6 +26,8 b' Model for users'
26
26
27 from pylons_app.model.db import User
27 from pylons_app.model.db import User
28 from pylons_app.model.meta import Session
28 from pylons_app.model.meta import Session
29 import logging
30 log = logging.getLogger(__name__)
29
31
30 class UserModel(object):
32 class UserModel(object):
31
33
@@ -43,7 +45,8 b' class UserModel(object):'
43
45
44 self.sa.add(new_user)
46 self.sa.add(new_user)
45 self.sa.commit()
47 self.sa.commit()
46 except:
48 except Exception as e:
49 log.error(e)
47 self.sa.rollback()
50 self.sa.rollback()
48 raise
51 raise
49
52
@@ -59,6 +62,16 b' class UserModel(object):'
59
62
60 self.sa.add(new_user)
63 self.sa.add(new_user)
61 self.sa.commit()
64 self.sa.commit()
62 except:
65 except Exception as e:
66 log.error(e)
63 self.sa.rollback()
67 self.sa.rollback()
64 raise
68 raise
69
70 def delete(self, id):
71 try:
72 self.sa.delete(self.sa.query(User).get(id))
73 self.sa.commit()
74 except Exception as e:
75 log.error(e)
76 self.sa.rollback()
77 raise
@@ -20,15 +20,18 b''
20 <table>
20 <table>
21 <tr>
21 <tr>
22 <td>${_('Name')}</td>
22 <td>${_('Name')}</td>
23 <td>${h.text('name',c.new_repo)}</td>
23 <td>${h.text('repo_name',c.new_repo)}</td>
24 <td>${self.get_form_error('repo_name')}</td>
24 </tr>
25 </tr>
25 <tr>
26 <tr>
26 <td>${_('Description')}</td>
27 <td>${_('Description')}</td>
27 <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>
28 </tr>
30 </tr>
29 <tr>
31 <tr>
30 <td>${_('Private')}</td>
32 <td>${_('Private')}</td>
31 <td>${h.checkbox('private')}</td>
33 <td>${h.checkbox('private')}</td>
34 <td>${self.get_form_error('private')}</td>
32 </tr>
35 </tr>
33 <tr>
36 <tr>
34 <td></td>
37 <td></td>
@@ -16,19 +16,27 b''
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.new_repo),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('name',c.new_repo)}</td>
23 <td>${h.text('repo_name')}</td>
24 <td>${self.get_form_error('repo_name')}</td>
24 </tr>
25 </tr>
25 <tr>
26 <tr>
26 <td>${_('Description')}</td>
27 <td>${_('Description')}</td>
27 <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>
28 </tr>
30 </tr>
29 <tr>
31 <tr>
30 <td>${_('Private')}</td>
32 <td>${_('Private')}</td>
31 <td>${h.checkbox('private')}</td>
33 <td>${h.checkbox('private')}</td>
34 <td>${self.get_form_error('private')}</td>
35 </tr>
36 <tr>
37 <td>${_('Owner')}</td>
38 <td>${h.text('user')}</td>
39 <td>${self.get_form_error('user')}</td>
32 </tr>
40 </tr>
33 <tr>
41 <tr>
34 <td></td>
42 <td></td>
@@ -70,7 +70,7 b' E.onDOMReady(function(e){'
70 <td>${cs.author|n,filters.person}</td>
70 <td>${cs.author|n,filters.person}</td>
71 <td>r${cs.revision}</td>
71 <td>r${cs.revision}</td>
72 <td>
72 <td>
73 ${h.link_to(truncate(cs.message,60),
73 ${h.link_to(h.truncate(cs.message,60),
74 h.url('changeset_home',repo_name=c.repo_name,revision=cs._short),
74 h.url('changeset_home',repo_name=c.repo_name,revision=cs._short),
75 title=cs.message)}
75 title=cs.message)}
76 </td>
76 </td>
General Comments 0
You need to be logged in to leave comments. Login now