##// END OF EJS Templates
#56 implemented users groups editing,...
marcink -
r972:2c8fd849 beta
parent child Browse files
Show More
@@ -1,124 +1,178 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.users_groups
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Users Groups crud controller for pylons
7 7
8 8 :created_on: Jan 25, 2011
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import logging
29 29 import traceback
30 30 import formencode
31 31
32 32 from formencode import htmlfill
33 33 from pylons import request, session, tmpl_context as c, url, config
34 34 from pylons.controllers.util import abort, redirect
35 35 from pylons.i18n.translation import _
36 36
37 37 from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 40 fill_perms
41 41 from rhodecode.lib.base import BaseController, render
42 42
43 43 from rhodecode.model.db import User, UsersGroup
44 44 from rhodecode.model.forms import UserForm, UsersGroupForm
45 45 from rhodecode.model.user import UserModel
46 46 from rhodecode.model.users_group import UsersGroupModel
47 47
48 48 log = logging.getLogger(__name__)
49 49
50 50 class UsersGroupsController(BaseController):
51 51 """REST Controller styled on the Atom Publishing Protocol"""
52 52 # To properly map this controller, ensure your config/routing.py
53 53 # file has a resource setup:
54 54 # map.resource('users_group', 'users_groups')
55 55
56 56 @LoginRequired()
57 57 @HasPermissionAllDecorator('hg.admin')
58 58 def __before__(self):
59 59 c.admin_user = session.get('admin_user')
60 60 c.admin_username = session.get('admin_username')
61 61 super(UsersGroupsController, self).__before__()
62 62 c.available_permissions = config['available_permissions']
63 63
64 64 def index(self, format='html'):
65 65 """GET /users_groups: All items in the collection"""
66 66 # url('users_groups')
67 67 c.users_groups_list = self.sa.query(UsersGroup).all()
68 68 return render('admin/users_groups/users_groups.html')
69 69
70 70 def create(self):
71 71 """POST /users_groups: Create a new item"""
72 72 # url('users_groups')
73 73 users_group_model = UsersGroupModel()
74 74 users_group_form = UsersGroupForm()()
75 75 try:
76 76 form_result = users_group_form.to_python(dict(request.POST))
77 77 users_group_model.create(form_result)
78 78 h.flash(_('created users group %s') % form_result['users_group_name'],
79 79 category='success')
80 80 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
81 81 except formencode.Invalid, errors:
82 82 return htmlfill.render(
83 83 render('admin/users_groups/users_group_add.html'),
84 84 defaults=errors.value,
85 85 errors=errors.error_dict or {},
86 86 prefix_error=False,
87 87 encoding="UTF-8")
88 88 except Exception:
89 89 log.error(traceback.format_exc())
90 90 h.flash(_('error occurred during creation of users group %s') \
91 91 % request.POST.get('users_group_name'), category='error')
92 92
93 93 return redirect(url('users_groups'))
94 94
95 95 def new(self, format='html'):
96 96 """GET /users_groups/new: Form to create a new item"""
97 97 # url('new_users_group')
98 98 return render('admin/users_groups/users_group_add.html')
99 99
100 100 def update(self, id):
101 101 """PUT /users_groups/id: Update an existing item"""
102 102 # Forms posted to this method should contain a hidden field:
103 103 # <input type="hidden" name="_method" value="PUT" />
104 104 # Or using helpers:
105 105 # h.form(url('users_group', id=ID),
106 106 # method='put')
107 107 # url('users_group', id=ID)
108 108
109
110 users_group_model = UsersGroupModel()
111 c.users_group = users_group_model.get(id)
112 c.group_members = [(x.user_id, x.user.username) for x in
113 c.users_group.members]
114
115 c.available_members = [(x.user_id, x.username) for x in
116 self.sa.query(User).all()]
117 users_group_form = UsersGroupForm(edit=True,
118 old_data=c.users_group.get_dict(),
119 available_members=[str(x[0]) for x
120 in c.available_members])()
121
122 try:
123 form_result = users_group_form.to_python(request.POST)
124 users_group_model.update(id, form_result)
125 h.flash(_('updated users group %s') % form_result['users_group_name'],
126 category='success')
127 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
128 except formencode.Invalid, errors:
129 return htmlfill.render(
130 render('admin/users_groups/users_group_edit.html'),
131 defaults=errors.value,
132 errors=errors.error_dict or {},
133 prefix_error=False,
134 encoding="UTF-8")
135 except Exception:
136 log.error(traceback.format_exc())
137 h.flash(_('error occurred during update of users group %s') \
138 % request.POST.get('users_group_name'), category='error')
139
140 return redirect(url('users_groups'))
141
142
143
109 144 def delete(self, id):
110 145 """DELETE /users_groups/id: Delete an existing item"""
111 146 # Forms posted to this method should contain a hidden field:
112 147 # <input type="hidden" name="_method" value="DELETE" />
113 148 # Or using helpers:
114 149 # h.form(url('users_group', id=ID),
115 150 # method='delete')
116 151 # url('users_group', id=ID)
117 152
118 153 def show(self, id, format='html'):
119 154 """GET /users_groups/id: Show a specific item"""
120 155 # url('users_group', id=ID)
121 156
122 157 def edit(self, id, format='html'):
123 158 """GET /users_groups/id/edit: Form to edit an existing item"""
124 159 # url('edit_users_group', id=ID)
160
161 c.users_group = self.sa.query(UsersGroup).get(id)
162 if not c.users_group:
163 return redirect(url('users_groups'))
164
165 c.users_group.permissions = {}
166 c.group_members = [(x.user_id, x.user.username) for x in
167 c.users_group.members]
168 print c.group_members, 'x' * 100
169 c.available_members = [(x.user_id, x.username) for x in
170 self.sa.query(User).all()]
171 defaults = c.users_group.get_dict()
172
173 return htmlfill.render(
174 render('admin/users_groups/users_group_edit.html'),
175 defaults=defaults,
176 encoding="UTF-8",
177 force_defaults=False
178 )
@@ -1,331 +1,335 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.db
4 4 ~~~~~~~~~~~~~~~~~~
5 5
6 6 Database Models for RhodeCode
7 7
8 8 :created_on: Apr 08, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27 import logging
28 28 import datetime
29 29
30 30 from sqlalchemy import *
31 31 from sqlalchemy.exc import DatabaseError
32 from sqlalchemy.orm import relation, backref, class_mapper
32 from sqlalchemy.orm import relationship, backref, class_mapper
33 33 from sqlalchemy.orm.session import Session
34 34
35 35 from rhodecode.model.meta import Base
36 36
37 37 log = logging.getLogger(__name__)
38 38
39 39 class BaseModel(object):
40 40
41 41 @classmethod
42 42 def _get_keys(cls):
43 43 """return column names for this model """
44 44 return class_mapper(cls).c.keys()
45 45
46 46 def get_dict(self):
47 47 """return dict with keys and values corresponding
48 48 to this model data """
49 49
50 50 d = {}
51 51 for k in self._get_keys():
52 52 d[k] = getattr(self, k)
53 53 return d
54 54
55 55 def get_appstruct(self):
56 56 """return list with keys and values tupples corresponding
57 57 to this model data """
58 58
59 59 l = []
60 60 for k in self._get_keys():
61 61 l.append((k, getattr(self, k),))
62 62 return l
63 63
64 64 def populate_obj(self, populate_dict):
65 65 """populate model with data from given populate_dict"""
66 66
67 67 for k in self._get_keys():
68 68 if k in populate_dict:
69 69 setattr(self, k, populate_dict[k])
70 70
71 71 class RhodeCodeSettings(Base, BaseModel):
72 72 __tablename__ = 'rhodecode_settings'
73 73 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
74 74 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
75 75 app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
76 76 app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
77 77
78 78 def __init__(self, k='', v=''):
79 79 self.app_settings_name = k
80 80 self.app_settings_value = v
81 81
82 82 def __repr__(self):
83 83 return "<%s('%s:%s')>" % (self.__class__.__name__,
84 84 self.app_settings_name, self.app_settings_value)
85 85
86 86 class RhodeCodeUi(Base, BaseModel):
87 87 __tablename__ = 'rhodecode_ui'
88 88 __table_args__ = {'useexisting':True}
89 89 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
90 90 ui_section = Column("ui_section", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
91 91 ui_key = Column("ui_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
92 92 ui_value = Column("ui_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
93 93 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
94 94
95 95
96 96 class User(Base, BaseModel):
97 97 __tablename__ = 'users'
98 98 __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True})
99 99 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
100 100 username = Column("username", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
101 101 password = Column("password", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
102 102 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
103 103 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
104 104 name = Column("name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
105 105 lastname = Column("lastname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
106 106 email = Column("email", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
107 107 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
108 108 is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False)
109 109
110 user_log = relation('UserLog', cascade='all')
111 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
110 user_log = relationship('UserLog', cascade='all')
111 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
112 112
113 repositories = relation('Repository')
114 user_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
113 repositories = relationship('Repository')
114 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
115 115
116 116 @property
117 117 def full_contact(self):
118 118 return '%s %s <%s>' % (self.name, self.lastname, self.email)
119 119
120 120
121 121 @property
122 122 def is_admin(self):
123 123 return self.admin
124 124
125 125 def __repr__(self):
126 126 return "<%s('id:%s:%s')>" % (self.__class__.__name__,
127 127 self.user_id, self.username)
128 128
129 129 def update_lastlogin(self):
130 130 """Update user lastlogin"""
131 131
132 132 try:
133 133 session = Session.object_session(self)
134 134 self.last_login = datetime.datetime.now()
135 135 session.add(self)
136 136 session.commit()
137 137 log.debug('updated user %s lastlogin', self.username)
138 138 except (DatabaseError,):
139 139 session.rollback()
140 140
141 141
142 142 class UserLog(Base, BaseModel):
143 143 __tablename__ = 'user_logs'
144 144 __table_args__ = {'useexisting':True}
145 145 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
146 146 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
147 147 repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
148 148 repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
149 149 user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
150 150 action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
151 151 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
152 152
153 user = relation('User')
154 repository = relation('Repository')
153 user = relationship('User')
154 repository = relationship('Repository')
155 155
156 156
157 157 class UsersGroup(Base, BaseModel):
158 158 __tablename__ = 'users_groups'
159 159 __table_args__ = {'useexisting':True}
160 160
161 161 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
162 162 users_group_name = Column("users_group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
163 163 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
164 164
165 members = relation('UsersGroupMember')
165 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan")
166 166
167 167 class UsersGroupMember(Base, BaseModel):
168 168 __tablename__ = 'users_groups_members'
169 169 __table_args__ = {'useexisting':True}
170 170
171 171 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
172 172 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
173 173 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
174 174
175 user = relation('User')
176 users_group = relation('UsersGroup')
175 user = relationship('User')
176 users_group = relationship('UsersGroup')
177
178 def __init__(self, gr_id, u_id):
179 self.users_group_id = gr_id
180 self.user_id = u_id
177 181
178 182 class Repository(Base, BaseModel):
179 183 __tablename__ = 'repositories'
180 184 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
181 185 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
182 186 repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
183 187 repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
184 188 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
185 189 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
186 190 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
187 191 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
188 192 description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
189 193 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
190 194 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
191 195
192 user = relation('User')
193 fork = relation('Repository', remote_side=repo_id)
194 group = relation('Group')
195 repo_to_perm = relation('RepoToPerm', cascade='all')
196 stats = relation('Statistics', cascade='all', uselist=False)
196 user = relationship('User')
197 fork = relationship('Repository', remote_side=repo_id)
198 group = relationship('Group')
199 repo_to_perm = relationship('RepoToPerm', cascade='all')
200 stats = relationship('Statistics', cascade='all', uselist=False)
197 201
198 repo_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
202 repo_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
199 203
200 204 def __repr__(self):
201 205 return "<%s('%s:%s')>" % (self.__class__.__name__,
202 206 self.repo_id, self.repo_name)
203 207
204 208 class Group(Base, BaseModel):
205 209 __tablename__ = 'groups'
206 210 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
207 211
208 212 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
209 213 group_name = Column("group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
210 214 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
211 215
212 parent_group = relation('Group', remote_side=group_id)
216 parent_group = relationship('Group', remote_side=group_id)
213 217
214 218
215 219 def __init__(self, group_name='', parent_group=None):
216 220 self.group_name = group_name
217 221 self.parent_group = parent_group
218 222
219 223 def __repr__(self):
220 224 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
221 225 self.group_name)
222 226
223 227 class Permission(Base, BaseModel):
224 228 __tablename__ = 'permissions'
225 229 __table_args__ = {'useexisting':True}
226 230 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
227 231 permission_name = Column("permission_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
228 232 permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
229 233
230 234 def __repr__(self):
231 235 return "<%s('%s:%s')>" % (self.__class__.__name__,
232 236 self.permission_id, self.permission_name)
233 237
234 238 class RepoToPerm(Base, BaseModel):
235 239 __tablename__ = 'repo_to_perm'
236 240 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
237 241 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
238 242 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
239 243 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
240 244 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
241 245
242 user = relation('User')
243 permission = relation('Permission')
244 repository = relation('Repository')
246 user = relationship('User')
247 permission = relationship('Permission')
248 repository = relationship('Repository')
245 249
246 250 class UserToPerm(Base, BaseModel):
247 251 __tablename__ = 'user_to_perm'
248 252 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
249 253 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
250 254 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
251 255 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
252 256
253 user = relation('User')
254 permission = relation('Permission')
257 user = relationship('User')
258 permission = relationship('Permission')
255 259
256 260 class UsersGroupToPerm(Base, BaseModel):
257 261 __tablename__ = 'users_group_to_perm'
258 262 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
259 263 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
260 264 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
261 265 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
262 266
263 users_group = relation('UsersGroup')
264 permission = relation('Permission')
267 users_group = relationship('UsersGroup')
268 permission = relationship('Permission')
265 269
266 270 class GroupToPerm(Base, BaseModel):
267 271 __tablename__ = 'group_to_perm'
268 272 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
269 273
270 274 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
271 275 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
272 276 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
273 277 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
274 278
275 user = relation('User')
276 permission = relation('Permission')
277 group = relation('Group')
279 user = relationship('User')
280 permission = relationship('Permission')
281 group = relationship('Group')
278 282
279 283 class Statistics(Base, BaseModel):
280 284 __tablename__ = 'statistics'
281 285 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
282 286 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
283 287 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
284 288 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
285 289 commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data
286 290 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
287 291 languages = Column("languages", LargeBinary(), nullable=False)#JSON data
288 292
289 repository = relation('Repository', single_parent=True)
293 repository = relationship('Repository', single_parent=True)
290 294
291 295 class UserFollowing(Base, BaseModel):
292 296 __tablename__ = 'user_followings'
293 297 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
294 298 UniqueConstraint('user_id', 'follows_user_id')
295 299 , {'useexisting':True})
296 300
297 301 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
298 302 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
299 303 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
300 304 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
301 305
302 user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
306 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
303 307
304 follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
305 follows_repository = relation('Repository')
308 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
309 follows_repository = relationship('Repository')
306 310
307 311 class CacheInvalidation(Base, BaseModel):
308 312 __tablename__ = 'cache_invalidation'
309 313 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
310 314 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
311 315 cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
312 316 cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
313 317 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
314 318
315 319
316 320 def __init__(self, cache_key, cache_args=''):
317 321 self.cache_key = cache_key
318 322 self.cache_args = cache_args
319 323 self.cache_active = False
320 324
321 325 def __repr__(self):
322 326 return "<%s('%s:%s')>" % (self.__class__.__name__,
323 327 self.cache_id, self.cache_key)
324 328
325 329 class DbMigrateVersion(Base, BaseModel):
326 330 __tablename__ = 'db_migrate_version'
327 331 __table_args__ = {'useexisting':True}
328 332 repository_id = Column('repository_id', String(250), primary_key=True)
329 333 repository_path = Column('repository_path', Text)
330 334 version = Column('version', Integer)
331 335
@@ -1,531 +1,537 b''
1 1 """ this is forms validation classes
2 2 http://formencode.org/module-formencode.validators.html
3 3 for list off all availible validators
4 4
5 5 we can create our own validators
6 6
7 7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 8 pre_validators [] These validators will be applied before the schema
9 9 chained_validators [] These validators will be applied after the schema
10 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 11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 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 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 16 <name> = formencode.validators.<name of validator>
17 17 <name> must equal form name
18 18 list=[1,2,3,4,5]
19 19 for SELECT use formencode.All(OneOf(list), Int())
20 20
21 21 """
22 22 import os
23 23 import re
24 24 import logging
25 25
26 26 import formencode
27 27 from formencode import All
28 28 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 Email, Bool, StringBoolean
29 Email, Bool, StringBoolean, Set
30 30
31 31 from pylons.i18n.translation import _
32 32
33 33 import rhodecode.lib.helpers as h
34 34 from rhodecode.lib.auth import authenticate, get_crypt_password
35 35 from rhodecode.lib.exceptions import LdapImportError
36 36 from rhodecode.model import meta
37 37 from rhodecode.model.user import UserModel
38 38 from rhodecode.model.repo import RepoModel
39 39 from rhodecode.model.users_group import UsersGroupModel
40 40 from rhodecode.model.db import User
41 41 from rhodecode import BACKENDS
42 42
43 43 from webhelpers.pylonslib.secure_form import authentication_token
44 44
45 45 log = logging.getLogger(__name__)
46 46
47 47 #this is needed to translate the messages using _() in validators
48 48 class State_obj(object):
49 49 _ = staticmethod(_)
50 50
51 51 #===============================================================================
52 52 # VALIDATORS
53 53 #===============================================================================
54 54 class ValidAuthToken(formencode.validators.FancyValidator):
55 55 messages = {'invalid_token':_('Token mismatch')}
56 56
57 57 def validate_python(self, value, state):
58 58
59 59 if value != authentication_token():
60 60 raise formencode.Invalid(self.message('invalid_token', state,
61 61 search_number=value), value, state)
62 62
63 63 def ValidUsername(edit, old_data):
64 64 class _ValidUsername(formencode.validators.FancyValidator):
65 65
66 66 def validate_python(self, value, state):
67 67 if value in ['default', 'new_user']:
68 68 raise formencode.Invalid(_('Invalid username'), value, state)
69 69 #check if user is unique
70 70 old_un = None
71 71 if edit:
72 72 old_un = UserModel().get(old_data.get('user_id')).username
73 73
74 74 if old_un != value or not edit:
75 75 if UserModel().get_by_username(value, cache=False,
76 76 case_insensitive=True):
77 77 raise formencode.Invalid(_('This username already exists') ,
78 78 value, state)
79 79
80 80
81 81 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
82 82 raise formencode.Invalid(_('Username may only contain '
83 83 'alphanumeric characters underscores, '
84 84 'periods or dashes and must begin with '
85 85 'alphanumeric character'),
86 86 value, state)
87 87
88 88
89 89
90 90 return _ValidUsername
91 91
92 92
93 93
94 94 def ValidUsersGroup(edit, old_data):
95 95
96 96 class _ValidUsersGroup(formencode.validators.FancyValidator):
97 97
98 98 def validate_python(self, value, state):
99 99 if value in ['default']:
100 100 raise formencode.Invalid(_('Invalid group name'), value, state)
101 101 #check if group is unique
102 old_un = None
102 old_ugname = None
103 103 if edit:
104 old_un = UserModel().get(old_data.get('users_group_id')).username
104 old_ugname = UsersGroupModel()\
105 .get(old_data.get('users_group_id')).users_group_name
105 106
106 if old_un != value or not edit:
107 if old_ugname != value or not edit:
107 108 if UsersGroupModel().get_by_groupname(value, cache=False,
108 109 case_insensitive=True):
109 110 raise formencode.Invalid(_('This users group already exists') ,
110 111 value, state)
111 112
112 113
113 114 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
114 115 raise formencode.Invalid(_('Group name may only contain '
115 116 'alphanumeric characters underscores, '
116 117 'periods or dashes and must begin with '
117 118 'alphanumeric character'),
118 119 value, state)
119 120
120 121 return _ValidUsersGroup
121 122
122 123
123 124
124 125 class ValidPassword(formencode.validators.FancyValidator):
125 126
126 127 def to_python(self, value, state):
127 128
128 129 if value:
129 130
130 131 if value.get('password'):
131 132 try:
132 133 value['password'] = get_crypt_password(value['password'])
133 134 except UnicodeEncodeError:
134 135 e_dict = {'password':_('Invalid characters in password')}
135 136 raise formencode.Invalid('', value, state, error_dict=e_dict)
136 137
137 138 if value.get('password_confirmation'):
138 139 try:
139 140 value['password_confirmation'] = \
140 141 get_crypt_password(value['password_confirmation'])
141 142 except UnicodeEncodeError:
142 143 e_dict = {'password_confirmation':_('Invalid characters in password')}
143 144 raise formencode.Invalid('', value, state, error_dict=e_dict)
144 145
145 146 if value.get('new_password'):
146 147 try:
147 148 value['new_password'] = \
148 149 get_crypt_password(value['new_password'])
149 150 except UnicodeEncodeError:
150 151 e_dict = {'new_password':_('Invalid characters in password')}
151 152 raise formencode.Invalid('', value, state, error_dict=e_dict)
152 153
153 154 return value
154 155
155 156 class ValidPasswordsMatch(formencode.validators.FancyValidator):
156 157
157 158 def validate_python(self, value, state):
158 159
159 160 if value['password'] != value['password_confirmation']:
160 161 e_dict = {'password_confirmation':
161 162 _('Password do not match')}
162 163 raise formencode.Invalid('', value, state, error_dict=e_dict)
163 164
164 165 class ValidAuth(formencode.validators.FancyValidator):
165 166 messages = {
166 167 'invalid_password':_('invalid password'),
167 168 'invalid_login':_('invalid user name'),
168 169 'disabled_account':_('Your account is disabled')
169 170
170 171 }
171 172 #error mapping
172 173 e_dict = {'username':messages['invalid_login'],
173 174 'password':messages['invalid_password']}
174 175 e_dict_disable = {'username':messages['disabled_account']}
175 176
176 177 def validate_python(self, value, state):
177 178 password = value['password']
178 179 username = value['username']
179 180 user = UserModel().get_by_username(username)
180 181
181 182 if authenticate(username, password):
182 183 return value
183 184 else:
184 185 if user and user.active is False:
185 186 log.warning('user %s is disabled', username)
186 187 raise formencode.Invalid(self.message('disabled_account',
187 188 state=State_obj),
188 189 value, state,
189 190 error_dict=self.e_dict_disable)
190 191 else:
191 192 log.warning('user %s not authenticated', username)
192 193 raise formencode.Invalid(self.message('invalid_password',
193 194 state=State_obj), value, state,
194 195 error_dict=self.e_dict)
195 196
196 197 class ValidRepoUser(formencode.validators.FancyValidator):
197 198
198 199 def to_python(self, value, state):
199 200 sa = meta.Session()
200 201 try:
201 202 self.user_db = sa.query(User)\
202 203 .filter(User.active == True)\
203 204 .filter(User.username == value).one()
204 205 except Exception:
205 206 raise formencode.Invalid(_('This username is not valid'),
206 207 value, state)
207 208 finally:
208 209 meta.Session.remove()
209 210
210 211 return self.user_db.user_id
211 212
212 213 def ValidRepoName(edit, old_data):
213 214 class _ValidRepoName(formencode.validators.FancyValidator):
214 215
215 216 def to_python(self, value, state):
216 217 slug = h.repo_name_slug(value)
217 218 if slug in ['_admin']:
218 219 raise formencode.Invalid(_('This repository name is disallowed'),
219 220 value, state)
220 221 if old_data.get('repo_name') != value or not edit:
221 222 if RepoModel().get_by_repo_name(slug, cache=False):
222 223 raise formencode.Invalid(_('This repository already exists') ,
223 224 value, state)
224 225 return slug
225 226
226 227
227 228 return _ValidRepoName
228 229
229 230 def ValidForkType(old_data):
230 231 class _ValidForkType(formencode.validators.FancyValidator):
231 232
232 233 def to_python(self, value, state):
233 234 if old_data['repo_type'] != value:
234 235 raise formencode.Invalid(_('Fork have to be the same type as original'),
235 236 value, state)
236 237 return value
237 238 return _ValidForkType
238 239
239 240 class ValidPerms(formencode.validators.FancyValidator):
240 241 messages = {'perm_new_user_name':_('This username is not valid')}
241 242
242 243 def to_python(self, value, state):
243 244 perms_update = []
244 245 perms_new = []
245 246 #build a list of permission to update and new permission to create
246 247 for k, v in value.items():
247 248 if k.startswith('perm_'):
248 249 if k.startswith('perm_new_user'):
249 250 new_perm = value.get('perm_new_user', False)
250 251 new_user = value.get('perm_new_user_name', False)
251 252 if new_user and new_perm:
252 253 if (new_user, new_perm) not in perms_new:
253 254 perms_new.append((new_user, new_perm))
254 255 else:
255 256 usr = k[5:]
256 257 if usr == 'default':
257 258 if value['private']:
258 259 #set none for default when updating to private repo
259 260 v = 'repository.none'
260 261 perms_update.append((usr, v))
261 262 value['perms_updates'] = perms_update
262 263 value['perms_new'] = perms_new
263 264 sa = meta.Session
264 265 for k, v in perms_new:
265 266 try:
266 267 self.user_db = sa.query(User)\
267 268 .filter(User.active == True)\
268 269 .filter(User.username == k).one()
269 270 except Exception:
270 271 msg = self.message('perm_new_user_name',
271 272 state=State_obj)
272 273 raise formencode.Invalid(msg, value, state,
273 274 error_dict={'perm_new_user_name':msg})
274 275 return value
275 276
276 277 class ValidSettings(formencode.validators.FancyValidator):
277 278
278 279 def to_python(self, value, state):
279 280 #settings form can't edit user
280 281 if value.has_key('user'):
281 282 del['value']['user']
282 283
283 284 return value
284 285
285 286 class ValidPath(formencode.validators.FancyValidator):
286 287 def to_python(self, value, state):
287 288
288 289 if not os.path.isdir(value):
289 290 msg = _('This is not a valid path')
290 291 raise formencode.Invalid(msg, value, state,
291 292 error_dict={'paths_root_path':msg})
292 293 return value
293 294
294 295 def UniqSystemEmail(old_data):
295 296 class _UniqSystemEmail(formencode.validators.FancyValidator):
296 297 def to_python(self, value, state):
297 298 value = value.lower()
298 299 if old_data.get('email') != value:
299 300 sa = meta.Session()
300 301 try:
301 302 user = sa.query(User).filter(User.email == value).scalar()
302 303 if user:
303 304 raise formencode.Invalid(_("This e-mail address is already taken") ,
304 305 value, state)
305 306 finally:
306 307 meta.Session.remove()
307 308
308 309 return value
309 310
310 311 return _UniqSystemEmail
311 312
312 313 class ValidSystemEmail(formencode.validators.FancyValidator):
313 314 def to_python(self, value, state):
314 315 value = value.lower()
315 316 sa = meta.Session
316 317 try:
317 318 user = sa.query(User).filter(User.email == value).scalar()
318 319 if user is None:
319 320 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
320 321 value, state)
321 322 finally:
322 323 meta.Session.remove()
323 324
324 325 return value
325 326
326 327 class LdapLibValidator(formencode.validators.FancyValidator):
327 328
328 329 def to_python(self, value, state):
329 330
330 331 try:
331 332 import ldap
332 333 except ImportError:
333 334 raise LdapImportError
334 335 return value
335 336
336 337 class BaseDnValidator(formencode.validators.FancyValidator):
337 338
338 339 def to_python(self, value, state):
339 340
340 341 try:
341 342 value % {'user':'valid'}
342 343
343 344 if value.find('%(user)s') == -1:
344 345 raise formencode.Invalid(_("You need to specify %(user)s in "
345 346 "template for example uid=%(user)s "
346 347 ",dc=company...") ,
347 348 value, state)
348 349
349 350 except KeyError:
350 351 raise formencode.Invalid(_("Wrong template used, only %(user)s "
351 352 "is an valid entry") ,
352 353 value, state)
353 354
354 355 return value
355 356
356 357 #===============================================================================
357 358 # FORMS
358 359 #===============================================================================
359 360 class LoginForm(formencode.Schema):
360 361 allow_extra_fields = True
361 362 filter_extra_fields = True
362 363 username = UnicodeString(
363 364 strip=True,
364 365 min=1,
365 366 not_empty=True,
366 367 messages={
367 368 'empty':_('Please enter a login'),
368 369 'tooShort':_('Enter a value %(min)i characters long or more')}
369 370 )
370 371
371 372 password = UnicodeString(
372 373 strip=True,
373 374 min=6,
374 375 not_empty=True,
375 376 messages={
376 377 'empty':_('Please enter a password'),
377 378 'tooShort':_('Enter %(min)i characters or more')}
378 379 )
379 380
380 381
381 382 #chained validators have access to all data
382 383 chained_validators = [ValidAuth]
383 384
384 385 def UserForm(edit=False, old_data={}):
385 386 class _UserForm(formencode.Schema):
386 387 allow_extra_fields = True
387 388 filter_extra_fields = True
388 389 username = All(UnicodeString(strip=True, min=1, not_empty=True),
389 390 ValidUsername(edit, old_data))
390 391 if edit:
391 392 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
392 393 admin = StringBoolean(if_missing=False)
393 394 else:
394 395 password = All(UnicodeString(strip=True, min=6, not_empty=True))
395 396 active = StringBoolean(if_missing=False)
396 397 name = UnicodeString(strip=True, min=1, not_empty=True)
397 398 lastname = UnicodeString(strip=True, min=1, not_empty=True)
398 399 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
399 400
400 401 chained_validators = [ValidPassword]
401 402
402 403 return _UserForm
403 404
404 405
405 def UsersGroupForm(edit=False, old_data={}):
406 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
406 407 class _UsersGroupForm(formencode.Schema):
407 408 allow_extra_fields = True
408 409 filter_extra_fields = True
409 410
410 411 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
411 412 ValidUsersGroup(edit, old_data))
412 413
413 414 users_group_active = StringBoolean(if_missing=False)
414 415
416 if edit:
417 users_group_members = OneOf(available_members, hideList=False,
418 testValueList=True,
419 if_missing=None, not_empty=False)
420
415 421 return _UsersGroupForm
416 422
417 423 def RegisterForm(edit=False, old_data={}):
418 424 class _RegisterForm(formencode.Schema):
419 425 allow_extra_fields = True
420 426 filter_extra_fields = True
421 427 username = All(ValidUsername(edit, old_data),
422 428 UnicodeString(strip=True, min=1, not_empty=True))
423 429 password = All(UnicodeString(strip=True, min=6, not_empty=True))
424 430 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
425 431 active = StringBoolean(if_missing=False)
426 432 name = UnicodeString(strip=True, min=1, not_empty=True)
427 433 lastname = UnicodeString(strip=True, min=1, not_empty=True)
428 434 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
429 435
430 436 chained_validators = [ValidPasswordsMatch, ValidPassword]
431 437
432 438 return _RegisterForm
433 439
434 440 def PasswordResetForm():
435 441 class _PasswordResetForm(formencode.Schema):
436 442 allow_extra_fields = True
437 443 filter_extra_fields = True
438 444 email = All(ValidSystemEmail(), Email(not_empty=True))
439 445 return _PasswordResetForm
440 446
441 447 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
442 448 class _RepoForm(formencode.Schema):
443 449 allow_extra_fields = True
444 450 filter_extra_fields = False
445 451 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
446 452 ValidRepoName(edit, old_data))
447 453 description = UnicodeString(strip=True, min=1, not_empty=True)
448 454 private = StringBoolean(if_missing=False)
449 455 enable_statistics = StringBoolean(if_missing=False)
450 456 enable_downloads = StringBoolean(if_missing=False)
451 457 repo_type = OneOf(supported_backends)
452 458 if edit:
453 459 user = All(Int(not_empty=True), ValidRepoUser)
454 460
455 461 chained_validators = [ValidPerms]
456 462 return _RepoForm
457 463
458 464 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
459 465 class _RepoForkForm(formencode.Schema):
460 466 allow_extra_fields = True
461 467 filter_extra_fields = False
462 468 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
463 469 ValidRepoName(edit, old_data))
464 470 description = UnicodeString(strip=True, min=1, not_empty=True)
465 471 private = StringBoolean(if_missing=False)
466 472 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
467 473 return _RepoForkForm
468 474
469 475 def RepoSettingsForm(edit=False, old_data={}):
470 476 class _RepoForm(formencode.Schema):
471 477 allow_extra_fields = True
472 478 filter_extra_fields = False
473 479 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
474 480 ValidRepoName(edit, old_data))
475 481 description = UnicodeString(strip=True, min=1, not_empty=True)
476 482 private = StringBoolean(if_missing=False)
477 483
478 484 chained_validators = [ValidPerms, ValidSettings]
479 485 return _RepoForm
480 486
481 487
482 488 def ApplicationSettingsForm():
483 489 class _ApplicationSettingsForm(formencode.Schema):
484 490 allow_extra_fields = True
485 491 filter_extra_fields = False
486 492 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
487 493 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
488 494 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
489 495
490 496 return _ApplicationSettingsForm
491 497
492 498 def ApplicationUiSettingsForm():
493 499 class _ApplicationUiSettingsForm(formencode.Schema):
494 500 allow_extra_fields = True
495 501 filter_extra_fields = False
496 502 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
497 503 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
498 504 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
499 505 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
500 506 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
501 507 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
502 508
503 509 return _ApplicationUiSettingsForm
504 510
505 511 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
506 512 class _DefaultPermissionsForm(formencode.Schema):
507 513 allow_extra_fields = True
508 514 filter_extra_fields = True
509 515 overwrite_default = StringBoolean(if_missing=False)
510 516 anonymous = OneOf(['True', 'False'], if_missing=False)
511 517 default_perm = OneOf(perms_choices)
512 518 default_register = OneOf(register_choices)
513 519 default_create = OneOf(create_choices)
514 520
515 521 return _DefaultPermissionsForm
516 522
517 523
518 524 def LdapSettingsForm():
519 525 class _LdapSettingsForm(formencode.Schema):
520 526 allow_extra_fields = True
521 527 filter_extra_fields = True
522 528 pre_validators = [LdapLibValidator]
523 529 ldap_active = StringBoolean(if_missing=False)
524 530 ldap_host = UnicodeString(strip=True,)
525 531 ldap_port = Number(strip=True,)
526 532 ldap_ldaps = StringBoolean(if_missing=False)
527 533 ldap_dn_user = UnicodeString(strip=True,)
528 534 ldap_dn_pass = UnicodeString(strip=True,)
529 535 ldap_base_dn = All(BaseDnValidator, UnicodeString(strip=True,))
530 536
531 537 return _LdapSettingsForm
@@ -1,79 +1,101 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.model.user_group
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 users groups model for RhodeCode
7 7
8 8 :created_on: Jan 25, 2011
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import logging
29 29 import traceback
30 30
31 31 from pylons.i18n.translation import _
32 32
33 33 from rhodecode.model import BaseModel
34 34 from rhodecode.model.caching_query import FromCache
35 from rhodecode.model.db import UsersGroup
36
37 from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException
35 from rhodecode.model.db import UsersGroup, UsersGroupMember
38 36
39 37 from sqlalchemy.exc import DatabaseError
40 38
41 39 log = logging.getLogger(__name__)
42 40
43 41
44 42 class UsersGroupModel(BaseModel):
45 43
46 44 def get(self, users_group_id, cache=False):
47 45 users_group = self.sa.query(UsersGroup)
48 46 if cache:
49 47 users_group = users_group.options(FromCache("sql_cache_short",
50 48 "get_users_group_%s" % users_group_id))
51 49 return users_group.get(users_group_id)
52 50
53 51
54 def get_by_groupname(self, users_group_name, cache=False, case_insensitive=False):
52 def get_by_groupname(self, users_group_name, cache=False,
53 case_insensitive=False):
55 54
56 55 if case_insensitive:
57 56 user = self.sa.query(UsersGroup)\
58 57 .filter(UsersGroup.users_group_name.ilike(users_group_name))
59 58 else:
60 59 user = self.sa.query(UsersGroup)\
61 60 .filter(UsersGroup.users_group_name == users_group_name)
62 61 if cache:
63 62 user = user.options(FromCache("sql_cache_short",
64 63 "get_user_%s" % users_group_name))
65 64 return user.scalar()
66 65
67 66 def create(self, form_data):
68 67 try:
69 68 new_users_group = UsersGroup()
70 69 for k, v in form_data.items():
71 70 setattr(new_users_group, k, v)
72 71
73 72 self.sa.add(new_users_group)
74 73 self.sa.commit()
75 74 except:
76 75 log.error(traceback.format_exc())
77 76 self.sa.rollback()
78 77 raise
79 78
79 def update(self, users_group_id, form_data):
80
81 try:
82 users_group = self.get(users_group_id, cache=False)
83
84 for k, v in form_data.items():
85 if k == 'users_group_members':
86 users_group.members = []
87 self.sa.flush()
88 members_list = []
89 if v:
90 for u_id in set(v):
91 members_list.append(UsersGroupMember(users_group_id,
92 u_id))
93 setattr(users_group, 'members', members_list)
94 setattr(users_group, k, v)
95
96 self.sa.add(users_group)
97 self.sa.commit()
98 except:
99 log.error(traceback.format_exc())
100 self.sa.rollback()
101 raise
@@ -0,0 +1,166 b''
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
3
4 <%def name="title()">
5 ${_('Edit users group')} ${c.users_group.users_group_name} - ${c.rhodecode_name}
6 </%def>
7
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 &raquo;
11 ${h.link_to(_('UsersGroups'),h.url('users_groups'))}
12 &raquo;
13 ${_('edit')} "${c.users_group.users_group_name}"
14 </%def>
15
16 <%def name="page_nav()">
17 ${self.menu('admin')}
18 </%def>
19
20 <%def name="main()">
21 <div class="box">
22 <!-- box / title -->
23 <div class="title">
24 ${self.breadcrumbs()}
25 </div>
26 <!-- end box / title -->
27 ${h.form(url('users_group', id=c.users_group.users_group_id),method='put', id='edit_users_group')}
28 <div class="form">
29 <!-- fields -->
30 <div class="fields">
31 <div class="field">
32 <div class="label">
33 <label for="users_group_name">${_('Group name')}:</label>
34 </div>
35 <div class="input">
36 ${h.text('users_group_name',class_='small')}
37 </div>
38 </div>
39
40 <div class="field">
41 <div class="label label-checkbox">
42 <label for="users_group_active">${_('Active')}:</label>
43 </div>
44 <div class="checkboxes">
45 ${h.checkbox('users_group_active',value=True)}
46 </div>
47 </div>
48 <div class="field">
49 <div class="label label-checkbox">
50 <label for="users_group_active">${_('Members')}:</label>
51 </div>
52 <div class="checkboxes">
53 <table>
54 <tr>
55 <td>
56 <div>
57 <div style="float:left">
58 <div class="text">${_('Group members')}</div>
59 ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,style="min-width:210px")}
60 </div>
61 <div style="float:left;width:20px;padding-top:50px">
62 <img alt="add" id="add_element"
63 style="padding:2px;cursor:pointer"
64 src="/images/icons/arrow_left.png">
65 <br />
66 <img alt="remove" id="remove_element"
67 style="padding:2px;cursor:pointer"
68 src="/images/icons/arrow_right.png">
69 </div>
70 <div style="float:left">
71 <div class="text">${_('Available members')}</div>
72 ${h.select('available_members',[],c.available_members,multiple=True,size=8,style="min-width:210px")}
73 </div>
74 </div>
75 </td>
76 </tr>
77 </table>
78 </div>
79
80 </div>
81 <div class="buttons">
82 ${h.submit('save','save',class_="ui-button")}
83 </div>
84 </div>
85 </div>
86 ${h.end_form()}
87 </div>
88
89 <script type="text/javascript">
90 YAHOO.util.Event.onDOMReady(function(){
91 var D = YAHOO.util.Dom;
92 var E = YAHOO.util.Event;
93
94 //definition of containers ID's
95 var available_container = 'available_members';
96 var selected_container = 'users_group_members';
97 //form containing containers id
98 var form_id = 'edit_users_group';
99
100 //temp container for storage.
101 var cache = new Array();
102 var c = D.get(selected_container);
103
104 //get only selected options for further fullfilment
105 for(var i = 0;node =c.options[i];i++){
106 if(node.selected){
107 //push selected to my temp storage left overs :)
108 cache.push(node);
109 }
110 }
111
112 //clear 'selected' select
113 c.options.length = 0;
114
115 //fill it with remembered options
116 for(var i = 0;node = cache[i];i++){
117 c.options[i]=new Option(node.text, node.value, false, false);
118 }
119
120 function prompts_action_callback(e){
121
122 var choosen = D.get(selected_container);
123 var availible = D.get(available_container);
124
125 if (this.id=='add_element'){
126 for(var i=0; node = availible.options[i];i++){
127 if(node.selected){
128 choosen.appendChild(new Option(node.text, node.value, false, false));
129 }
130 }
131 }
132 else if (this.id=='remove_element'){
133
134 //temp container for storage.
135 cache = new Array();
136
137 for(var i = 0;node = choosen.options[i];i++){
138 if(!node.selected){
139 //push left overs :)
140 cache.push(node);
141 }
142 }
143 //clear select
144 choosen.options.length = 0;
145 for(var i = 0;node = cache[i];i++){
146 choosen.options[i]=new Option(node.text, node.value, false, false);
147 }
148 }
149 else{
150
151 }
152 }
153
154
155 E.addListener(['add_element','remove_element'],'click',prompts_action_callback)
156
157 E.addListener(form_id,'submit',function(){
158 var choosen = D.get(selected_container);
159 for (var i = 0; i < choosen.options.length; i++) {
160 choosen.options[i].selected = 'selected';
161 }
162 })
163 });
164 </script>
165
166 </%def> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now