##// END OF EJS Templates
#56 fixed found bugs, implemented adding of new group + forms+validators...
marcink -
r959:fff21c9b beta
parent child Browse files
Show More
@@ -1,213 +1,217
1 1 """
2 2 Routes configuration
3 3
4 4 The more specific and detailed routes should be defined first so they
5 5 may take precedent over the more generic routes. For more information
6 6 refer to the routes manual at http://routes.groovie.org/docs/
7 7 """
8 8 from __future__ import with_statement
9 9 from routes import Mapper
10 10 from rhodecode.lib.utils import check_repo_fast as cr
11 11
12 12 def make_map(config):
13 13 """Create, configure and return the routes Mapper"""
14 14 map = Mapper(directory=config['pylons.paths']['controllers'],
15 15 always_scan=config['debug'])
16 16 map.minimization = False
17 17 map.explicit = False
18 18
19 19 def check_repo(environ, match_dict):
20 20 """
21 21 check for valid repository for proper 404 handling
22 22 :param environ:
23 23 :param match_dict:
24 24 """
25 25 repo_name = match_dict.get('repo_name')
26 26 return not cr(repo_name, config['base_path'])
27 27
28 28 # The ErrorController route (handles 404/500 error pages); it should
29 29 # likely stay at the top, ensuring it can always be resolved
30 30 map.connect('/error/{action}', controller='error')
31 31 map.connect('/error/{action}/{id}', controller='error')
32 32
33 33 #==========================================================================
34 34 # CUSTOM ROUTES HERE
35 35 #==========================================================================
36 36
37 37 #MAIN PAGE
38 38 map.connect('home', '/', controller='home', action='index')
39 39 map.connect('bugtracker', "http://bitbucket.org/marcinkuzminski/rhodecode/issues", _static=True)
40 40 map.connect('gpl_license', "http://www.gnu.org/licenses/gpl.html", _static=True)
41 41 #ADMIN REPOSITORY REST ROUTES
42 42 with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
43 43 m.connect("repos", "/repos",
44 44 action="create", conditions=dict(method=["POST"]))
45 45 m.connect("repos", "/repos",
46 46 action="index", conditions=dict(method=["GET"]))
47 47 m.connect("formatted_repos", "/repos.{format}",
48 48 action="index",
49 49 conditions=dict(method=["GET"]))
50 50 m.connect("new_repo", "/repos/new",
51 51 action="new", conditions=dict(method=["GET"]))
52 52 m.connect("formatted_new_repo", "/repos/new.{format}",
53 53 action="new", conditions=dict(method=["GET"]))
54 54 m.connect("/repos/{repo_name:.*}",
55 55 action="update", conditions=dict(method=["PUT"],
56 56 function=check_repo))
57 57 m.connect("/repos/{repo_name:.*}",
58 58 action="delete", conditions=dict(method=["DELETE"],
59 59 function=check_repo))
60 60 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
61 61 action="edit", conditions=dict(method=["GET"],
62 62 function=check_repo))
63 63 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
64 64 action="edit", conditions=dict(method=["GET"],
65 65 function=check_repo))
66 66 m.connect("repo", "/repos/{repo_name:.*}",
67 67 action="show", conditions=dict(method=["GET"],
68 68 function=check_repo))
69 69 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
70 70 action="show", conditions=dict(method=["GET"],
71 71 function=check_repo))
72 72 #ajax delete repo perm user
73 73 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
74 74 action="delete_perm_user", conditions=dict(method=["DELETE"],
75 75 function=check_repo))
76 76 #settings actions
77 77 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
78 78 action="repo_stats", conditions=dict(method=["DELETE"],
79 79 function=check_repo))
80 80 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
81 81 action="repo_cache", conditions=dict(method=["DELETE"],
82 82 function=check_repo))
83
84 #ADMIN USER REST ROUTES
85 map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
86
83 87 #ADMIN USER REST ROUTES
84 88 map.resource('users_group', 'users_groups', controller='admin/users_groups', path_prefix='/_admin')
85 89
86 90 #ADMIN GROUP REST ROUTES
87 91 map.resource('group', 'groups', controller='admin/groups', path_prefix='/_admin')
88 92
89 93 #ADMIN PERMISSIONS REST ROUTES
90 94 map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
91 95
92 96 ##ADMIN LDAP SETTINGS
93 97 map.connect('ldap_settings', '/_admin/ldap', controller='admin/ldap_settings',
94 98 action='ldap_settings', conditions=dict(method=["POST"]))
95 99 map.connect('ldap_home', '/_admin/ldap', controller='admin/ldap_settings',)
96 100
97 101
98 102 #ADMIN SETTINGS REST ROUTES
99 103 with map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
100 104 m.connect("admin_settings", "/settings",
101 105 action="create", conditions=dict(method=["POST"]))
102 106 m.connect("admin_settings", "/settings",
103 107 action="index", conditions=dict(method=["GET"]))
104 108 m.connect("formatted_admin_settings", "/settings.{format}",
105 109 action="index", conditions=dict(method=["GET"]))
106 110 m.connect("admin_new_setting", "/settings/new",
107 111 action="new", conditions=dict(method=["GET"]))
108 112 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
109 113 action="new", conditions=dict(method=["GET"]))
110 114 m.connect("/settings/{setting_id}",
111 115 action="update", conditions=dict(method=["PUT"]))
112 116 m.connect("/settings/{setting_id}",
113 117 action="delete", conditions=dict(method=["DELETE"]))
114 118 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
115 119 action="edit", conditions=dict(method=["GET"]))
116 120 m.connect("formatted_admin_edit_setting", "/settings/{setting_id}.{format}/edit",
117 121 action="edit", conditions=dict(method=["GET"]))
118 122 m.connect("admin_setting", "/settings/{setting_id}",
119 123 action="show", conditions=dict(method=["GET"]))
120 124 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
121 125 action="show", conditions=dict(method=["GET"]))
122 126 m.connect("admin_settings_my_account", "/my_account",
123 127 action="my_account", conditions=dict(method=["GET"]))
124 128 m.connect("admin_settings_my_account_update", "/my_account_update",
125 129 action="my_account_update", conditions=dict(method=["PUT"]))
126 130 m.connect("admin_settings_create_repository", "/create_repository",
127 131 action="create_repository", conditions=dict(method=["GET"]))
128 132
129 133 #ADMIN MAIN PAGES
130 134 with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
131 135 m.connect('admin_home', '', action='index')#main page
132 136 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
133 137 action='add_repo')
134 138
135 139
136 140 #USER JOURNAL
137 141 map.connect('journal', '/_admin/journal', controller='journal',)
138 142 map.connect('toggle_following', '/_admin/toggle_following', controller='journal',
139 143 action='toggle_following', conditions=dict(method=["POST"]))
140 144
141 145
142 146 #SEARCH
143 147 map.connect('search', '/_admin/search', controller='search',)
144 148 map.connect('search_repo', '/_admin/search/{search_repo:.*}', controller='search')
145 149
146 150 #LOGIN/LOGOUT/REGISTER/SIGN IN
147 151 map.connect('login_home', '/_admin/login', controller='login')
148 152 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
149 153 map.connect('register', '/_admin/register', controller='login', action='register')
150 154 map.connect('reset_password', '/_admin/password_reset', controller='login', action='password_reset')
151 155
152 156 #FEEDS
153 157 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
154 158 controller='feed', action='rss',
155 159 conditions=dict(function=check_repo))
156 160 map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
157 161 controller='feed', action='atom',
158 162 conditions=dict(function=check_repo))
159 163
160 164
161 165 #REPOSITORY ROUTES
162 166 map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
163 167 controller='changeset', revision='tip',
164 168 conditions=dict(function=check_repo))
165 169 map.connect('raw_changeset_home', '/{repo_name:.*}/raw-changeset/{revision}',
166 170 controller='changeset', action='raw_changeset', revision='tip',
167 171 conditions=dict(function=check_repo))
168 172 map.connect('summary_home', '/{repo_name:.*}/summary',
169 173 controller='summary', conditions=dict(function=check_repo))
170 174 map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
171 175 controller='shortlog', conditions=dict(function=check_repo))
172 176 map.connect('branches_home', '/{repo_name:.*}/branches',
173 177 controller='branches', conditions=dict(function=check_repo))
174 178 map.connect('tags_home', '/{repo_name:.*}/tags',
175 179 controller='tags', conditions=dict(function=check_repo))
176 180 map.connect('changelog_home', '/{repo_name:.*}/changelog',
177 181 controller='changelog', conditions=dict(function=check_repo))
178 182 map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
179 183 controller='files', revision='tip', f_path='',
180 184 conditions=dict(function=check_repo))
181 185 map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
182 186 controller='files', action='diff', revision='tip', f_path='',
183 187 conditions=dict(function=check_repo))
184 188 map.connect('files_rawfile_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
185 189 controller='files', action='rawfile', revision='tip', f_path='',
186 190 conditions=dict(function=check_repo))
187 191 map.connect('files_raw_home', '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
188 192 controller='files', action='raw', revision='tip', f_path='',
189 193 conditions=dict(function=check_repo))
190 194 map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
191 195 controller='files', action='annotate', revision='tip', f_path='',
192 196 conditions=dict(function=check_repo))
193 197 map.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
194 198 controller='files', action='archivefile',
195 199 conditions=dict(function=check_repo))
196 200 map.connect('repo_settings_delete', '/{repo_name:.*}/settings',
197 201 controller='settings', action="delete",
198 202 conditions=dict(method=["DELETE"], function=check_repo))
199 203 map.connect('repo_settings_update', '/{repo_name:.*}/settings',
200 204 controller='settings', action="update",
201 205 conditions=dict(method=["PUT"], function=check_repo))
202 206 map.connect('repo_settings_home', '/{repo_name:.*}/settings',
203 207 controller='settings', action='index',
204 208 conditions=dict(function=check_repo))
205 209
206 210 map.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
207 211 controller='settings', action='fork_create',
208 212 conditions=dict(function=check_repo, method=["POST"]))
209 213 map.connect('repo_fork_home', '/{repo_name:.*}/fork',
210 214 controller='settings', action='fork',
211 215 conditions=dict(function=check_repo))
212 216
213 217 return map
@@ -1,101 +1,124
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 from rhodecode.model.forms import UserForm
44 from rhodecode.model.forms import UserForm, UsersGroupForm
45 45 from rhodecode.model.user import UserModel
46 from rhodecode.model.users_group import UsersGroupModel
46 47
47 48 log = logging.getLogger(__name__)
48 49
49 50 class UsersGroupsController(BaseController):
50 51 """REST Controller styled on the Atom Publishing Protocol"""
51 52 # To properly map this controller, ensure your config/routing.py
52 53 # file has a resource setup:
53 54 # map.resource('users_group', 'users_groups')
54 55
55 56 @LoginRequired()
56 57 @HasPermissionAllDecorator('hg.admin')
57 58 def __before__(self):
58 59 c.admin_user = session.get('admin_user')
59 60 c.admin_username = session.get('admin_username')
60 61 super(UsersGroupsController, self).__before__()
61 62 c.available_permissions = config['available_permissions']
62 63
63 64 def index(self, format='html'):
64 65 """GET /users_groups: All items in the collection"""
65 66 # url('users_groups')
66 c.users_groups_list = []
67 c.users_groups_list = self.sa.query(UsersGroup).all()
67 68 return render('admin/users_groups/users_groups.html')
68 69
69 70 def create(self):
70 71 """POST /users_groups: Create a new item"""
71 72 # url('users_groups')
73 users_group_model = UsersGroupModel()
74 users_group_form = UsersGroupForm()()
75 try:
76 form_result = users_group_form.to_python(dict(request.POST))
77 users_group_model.create(form_result)
78 h.flash(_('created users group %s') % form_result['users_group_name'],
79 category='success')
80 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
81 except formencode.Invalid, errors:
82 return htmlfill.render(
83 render('admin/users_groups/users_group_add.html'),
84 defaults=errors.value,
85 errors=errors.error_dict or {},
86 prefix_error=False,
87 encoding="UTF-8")
88 except Exception:
89 log.error(traceback.format_exc())
90 h.flash(_('error occurred during creation of users group %s') \
91 % request.POST.get('users_group_name'), category='error')
92
93 return redirect(url('users_groups'))
72 94
73 95 def new(self, format='html'):
74 96 """GET /users_groups/new: Form to create a new item"""
75 97 # url('new_users_group')
98 return render('admin/users_groups/users_group_add.html')
76 99
77 100 def update(self, id):
78 101 """PUT /users_groups/id: Update an existing item"""
79 102 # Forms posted to this method should contain a hidden field:
80 103 # <input type="hidden" name="_method" value="PUT" />
81 104 # Or using helpers:
82 105 # h.form(url('users_group', id=ID),
83 106 # method='put')
84 107 # url('users_group', id=ID)
85 108
86 109 def delete(self, id):
87 110 """DELETE /users_groups/id: Delete an existing item"""
88 111 # Forms posted to this method should contain a hidden field:
89 112 # <input type="hidden" name="_method" value="DELETE" />
90 113 # Or using helpers:
91 114 # h.form(url('users_group', id=ID),
92 115 # method='delete')
93 116 # url('users_group', id=ID)
94 117
95 118 def show(self, id, format='html'):
96 119 """GET /users_groups/id: Show a specific item"""
97 120 # url('users_group', id=ID)
98 121
99 122 def edit(self, id, format='html'):
100 123 """GET /users_groups/id/edit: Form to edit an existing item"""
101 124 # url('edit_users_group', id=ID)
@@ -1,331 +1,330
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 32 from sqlalchemy.orm import relation, 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 110 user_log = relation('UserLog', cascade='all')
111 111 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
112 112
113 113 repositories = relation('Repository')
114 114 user_followers = relation('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 153 user = relation('User')
154 154 repository = relation('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 user_group_id = Column("users_groups_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
162 user_group_name = Column("user_group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
163
161 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
162 users_group_name = Column("users_group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
163 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
164 164
165 165 members = relation('UsersGroupMember')
166 166
167
168 167 class UsersGroupMember(Base, BaseModel):
169 168 __tablename__ = 'users_groups_members'
170 169 __table_args__ = {'useexisting':True}
171 170
172 user_groups_members_id = Column("user_groups_members_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
173 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_groups_id'), nullable=False, unique=None, default=None)
171 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
172 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
174 173 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
175 174
176 175 user = relation('User')
177 176 users_group = relation('UsersGroup')
178 177
179 178 class Repository(Base, BaseModel):
180 179 __tablename__ = 'repositories'
181 180 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
182 181 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
183 182 repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
184 183 repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
185 184 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
186 185 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
187 186 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
188 187 description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
189 188 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
190 189 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
191 190
192 191 user = relation('User')
193 192 fork = relation('Repository', remote_side=repo_id)
194 193 group = relation('Group')
195 194 repo_to_perm = relation('RepoToPerm', cascade='all')
196 195 stats = relation('Statistics', cascade='all', uselist=False)
197 196
198 197 repo_followers = relation('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
199 198
200 199 def __repr__(self):
201 200 return "<%s('%s:%s')>" % (self.__class__.__name__,
202 201 self.repo_id, self.repo_name)
203 202
204 203 class Group(Base, BaseModel):
205 204 __tablename__ = 'groups'
206 205 __table_args__ = (UniqueConstraint('group_name'), {'useexisting':True},)
207 206
208 207 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
209 208 group_name = Column("group_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
210 209 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
211 210
212 211 parent_group = relation('Group', remote_side=group_id)
213 212
214 213
215 214 def __init__(self, group_name='', parent_group=None):
216 215 self.group_name = group_name
217 216 self.parent_group = parent_group
218 217
219 218 def __repr__(self):
220 219 return "<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
221 220 self.group_name)
222 221
223 222 class Permission(Base, BaseModel):
224 223 __tablename__ = 'permissions'
225 224 __table_args__ = {'useexisting':True}
226 225 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
227 226 permission_name = Column("permission_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
228 227 permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
229 228
230 229 def __repr__(self):
231 230 return "<%s('%s:%s')>" % (self.__class__.__name__,
232 231 self.permission_id, self.permission_name)
233 232
234 233 class RepoToPerm(Base, BaseModel):
235 234 __tablename__ = 'repo_to_perm'
236 235 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
237 236 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
238 237 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
239 238 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
240 239 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
241 240
242 241 user = relation('User')
243 242 permission = relation('Permission')
244 243 repository = relation('Repository')
245 244
246 245 class UserToPerm(Base, BaseModel):
247 246 __tablename__ = 'user_to_perm'
248 247 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
249 248 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
250 249 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
251 250 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
252 251
253 252 user = relation('User')
254 253 permission = relation('Permission')
255 254
256 255 class UsersGroupToPerm(Base, BaseModel):
257 256 __tablename__ = 'users_group_to_perm'
258 257 __table_args__ = (UniqueConstraint('users_group_id', 'permission_id'), {'useexisting':True})
259 258 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
260 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_groups_id'), nullable=False, unique=None, default=None)
259 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
261 260 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
262 261
263 262 users_group = relation('UsersGroup')
264 263 permission = relation('Permission')
265 264
266 265 class GroupToPerm(Base, BaseModel):
267 266 __tablename__ = 'group_to_perm'
268 267 __table_args__ = (UniqueConstraint('group_id', 'permission_id'), {'useexisting':True})
269 268
270 269 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
271 270 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
272 271 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
273 272 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
274 273
275 274 user = relation('User')
276 275 permission = relation('Permission')
277 276 group = relation('Group')
278 277
279 278 class Statistics(Base, BaseModel):
280 279 __tablename__ = 'statistics'
281 280 __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True})
282 281 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
283 282 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
284 283 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
285 284 commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data
286 285 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
287 286 languages = Column("languages", LargeBinary(), nullable=False)#JSON data
288 287
289 288 repository = relation('Repository', single_parent=True)
290 289
291 290 class UserFollowing(Base, BaseModel):
292 291 __tablename__ = 'user_followings'
293 292 __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'),
294 293 UniqueConstraint('user_id', 'follows_user_id')
295 294 , {'useexisting':True})
296 295
297 296 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
298 297 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
299 298 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
300 299 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
301 300
302 301 user = relation('User', primaryjoin='User.user_id==UserFollowing.user_id')
303 302
304 303 follows_user = relation('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
305 304 follows_repository = relation('Repository')
306 305
307 306 class CacheInvalidation(Base, BaseModel):
308 307 __tablename__ = 'cache_invalidation'
309 308 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
310 309 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
311 310 cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
312 311 cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
313 312 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
314 313
315 314
316 315 def __init__(self, cache_key, cache_args=''):
317 316 self.cache_key = cache_key
318 317 self.cache_args = cache_args
319 318 self.cache_active = False
320 319
321 320 def __repr__(self):
322 321 return "<%s('%s:%s')>" % (self.__class__.__name__,
323 322 self.cache_id, self.cache_key)
324 323
325 324 class DbMigrateVersion(Base, BaseModel):
326 325 __tablename__ = 'db_migrate_version'
327 326 __table_args__ = {'useexisting':True}
328 327 repository_id = Column('repository_id', String(250), primary_key=True)
329 328 repository_path = Column('repository_path', Text)
330 329 version = Column('version', Integer)
331 330
@@ -1,484 +1,530
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 29 Email, Bool, StringBoolean
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 from rhodecode.model.users_group import UsersGroupModel
39 40 from rhodecode.model.db import User
40 41 from rhodecode import BACKENDS
41 42
42 43 from webhelpers.pylonslib.secure_form import authentication_token
43 44
44 45 log = logging.getLogger(__name__)
45 46
46 47 #this is needed to translate the messages using _() in validators
47 48 class State_obj(object):
48 49 _ = staticmethod(_)
49 50
50 51 #===============================================================================
51 52 # VALIDATORS
52 53 #===============================================================================
53 54 class ValidAuthToken(formencode.validators.FancyValidator):
54 55 messages = {'invalid_token':_('Token mismatch')}
55 56
56 57 def validate_python(self, value, state):
57 58
58 59 if value != authentication_token():
59 60 raise formencode.Invalid(self.message('invalid_token', state,
60 61 search_number=value), value, state)
61 62
62 63 def ValidUsername(edit, old_data):
63 64 class _ValidUsername(formencode.validators.FancyValidator):
64 65
65 66 def validate_python(self, value, state):
66 67 if value in ['default', 'new_user']:
67 68 raise formencode.Invalid(_('Invalid username'), value, state)
68 69 #check if user is unique
69 70 old_un = None
70 71 if edit:
71 72 old_un = UserModel().get(old_data.get('user_id')).username
72 73
73 74 if old_un != value or not edit:
74 75 if UserModel().get_by_username(value, cache=False,
75 76 case_insensitive=True):
76 77 raise formencode.Invalid(_('This username already exists') ,
77 78 value, state)
78 79
79 80
80 81 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_]+$', value) is None:
81 82 raise formencode.Invalid(_('Username may only contain '
82 83 'alphanumeric characters underscores '
83 84 'or dashes and must begin with '
84 85 'alphanumeric character'),
85 86 value, state)
86 87
87 88
88 89
89 90 return _ValidUsername
90 91
92
93
94 def ValidUsersGroup(edit, old_data):
95
96 class _ValidUsersGroup(formencode.validators.FancyValidator):
97
98 def validate_python(self, value, state):
99 if value in ['default']:
100 raise formencode.Invalid(_('Invalid group name'), value, state)
101 #check if group is unique
102 old_un = None
103 if edit:
104 old_un = UserModel().get(old_data.get('users_group_id')).username
105
106 if old_un != value or not edit:
107 if UsersGroupModel().get_by_groupname(value, cache=False,
108 case_insensitive=True):
109 raise formencode.Invalid(_('This users group already exists') ,
110 value, state)
111
112
113 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
114 raise formencode.Invalid(_('Group name may only contain '
115 'alphanumeric characters underscores, '
116 'periods or dashes and must begin with '
117 'alphanumeric character'),
118 value, state)
119
120 return _ValidUsersGroup
121
122
123
91 124 class ValidPassword(formencode.validators.FancyValidator):
92 125
93 126 def to_python(self, value, state):
94 127
95 128 if value:
96 129
97 130 if value.get('password'):
98 131 try:
99 132 value['password'] = get_crypt_password(value['password'])
100 133 except UnicodeEncodeError:
101 134 e_dict = {'password':_('Invalid characters in password')}
102 135 raise formencode.Invalid('', value, state, error_dict=e_dict)
103 136
104 137 if value.get('password_confirmation'):
105 138 try:
106 139 value['password_confirmation'] = \
107 140 get_crypt_password(value['password_confirmation'])
108 141 except UnicodeEncodeError:
109 142 e_dict = {'password_confirmation':_('Invalid characters in password')}
110 143 raise formencode.Invalid('', value, state, error_dict=e_dict)
111 144
112 145 if value.get('new_password'):
113 146 try:
114 147 value['new_password'] = \
115 148 get_crypt_password(value['new_password'])
116 149 except UnicodeEncodeError:
117 150 e_dict = {'new_password':_('Invalid characters in password')}
118 151 raise formencode.Invalid('', value, state, error_dict=e_dict)
119 152
120 153 return value
121 154
122 155 class ValidPasswordsMatch(formencode.validators.FancyValidator):
123 156
124 157 def validate_python(self, value, state):
125 158
126 159 if value['password'] != value['password_confirmation']:
127 160 e_dict = {'password_confirmation':
128 161 _('Password do not match')}
129 162 raise formencode.Invalid('', value, state, error_dict=e_dict)
130 163
131 164 class ValidAuth(formencode.validators.FancyValidator):
132 165 messages = {
133 166 'invalid_password':_('invalid password'),
134 167 'invalid_login':_('invalid user name'),
135 168 'disabled_account':_('Your account is disabled')
136 169
137 170 }
138 171 #error mapping
139 172 e_dict = {'username':messages['invalid_login'],
140 173 'password':messages['invalid_password']}
141 174 e_dict_disable = {'username':messages['disabled_account']}
142 175
143 176 def validate_python(self, value, state):
144 177 password = value['password']
145 178 username = value['username']
146 179 user = UserModel().get_by_username(username)
147 180
148 181 if authenticate(username, password):
149 182 return value
150 183 else:
151 184 if user and user.active is False:
152 185 log.warning('user %s is disabled', username)
153 186 raise formencode.Invalid(self.message('disabled_account',
154 187 state=State_obj),
155 188 value, state,
156 189 error_dict=self.e_dict_disable)
157 190 else:
158 191 log.warning('user %s not authenticated', username)
159 192 raise formencode.Invalid(self.message('invalid_password',
160 193 state=State_obj), value, state,
161 194 error_dict=self.e_dict)
162 195
163 196 class ValidRepoUser(formencode.validators.FancyValidator):
164 197
165 198 def to_python(self, value, state):
166 199 sa = meta.Session()
167 200 try:
168 201 self.user_db = sa.query(User)\
169 202 .filter(User.active == True)\
170 203 .filter(User.username == value).one()
171 204 except Exception:
172 205 raise formencode.Invalid(_('This username is not valid'),
173 206 value, state)
174 207 finally:
175 208 meta.Session.remove()
176 209
177 210 return self.user_db.user_id
178 211
179 212 def ValidRepoName(edit, old_data):
180 213 class _ValidRepoName(formencode.validators.FancyValidator):
181 214
182 215 def to_python(self, value, state):
183 216 slug = h.repo_name_slug(value)
184 217 if slug in ['_admin']:
185 218 raise formencode.Invalid(_('This repository name is disallowed'),
186 219 value, state)
187 220 if old_data.get('repo_name') != value or not edit:
188 221 if RepoModel().get_by_repo_name(slug, cache=False):
189 222 raise formencode.Invalid(_('This repository already exists') ,
190 223 value, state)
191 224 return slug
192 225
193 226
194 227 return _ValidRepoName
195 228
196 229 def ValidForkType(old_data):
197 230 class _ValidForkType(formencode.validators.FancyValidator):
198 231
199 232 def to_python(self, value, state):
200 233 if old_data['repo_type'] != value:
201 234 raise formencode.Invalid(_('Fork have to be the same type as original'),
202 235 value, state)
203 236 return value
204 237 return _ValidForkType
205 238
206 239 class ValidPerms(formencode.validators.FancyValidator):
207 240 messages = {'perm_new_user_name':_('This username is not valid')}
208 241
209 242 def to_python(self, value, state):
210 243 perms_update = []
211 244 perms_new = []
212 245 #build a list of permission to update and new permission to create
213 246 for k, v in value.items():
214 247 if k.startswith('perm_'):
215 248 if k.startswith('perm_new_user'):
216 249 new_perm = value.get('perm_new_user', False)
217 250 new_user = value.get('perm_new_user_name', False)
218 251 if new_user and new_perm:
219 252 if (new_user, new_perm) not in perms_new:
220 253 perms_new.append((new_user, new_perm))
221 254 else:
222 255 usr = k[5:]
223 256 if usr == 'default':
224 257 if value['private']:
225 258 #set none for default when updating to private repo
226 259 v = 'repository.none'
227 260 perms_update.append((usr, v))
228 261 value['perms_updates'] = perms_update
229 262 value['perms_new'] = perms_new
230 263 sa = meta.Session
231 264 for k, v in perms_new:
232 265 try:
233 266 self.user_db = sa.query(User)\
234 267 .filter(User.active == True)\
235 268 .filter(User.username == k).one()
236 269 except Exception:
237 270 msg = self.message('perm_new_user_name',
238 271 state=State_obj)
239 272 raise formencode.Invalid(msg, value, state,
240 273 error_dict={'perm_new_user_name':msg})
241 274 return value
242 275
243 276 class ValidSettings(formencode.validators.FancyValidator):
244 277
245 278 def to_python(self, value, state):
246 279 #settings form can't edit user
247 280 if value.has_key('user'):
248 281 del['value']['user']
249 282
250 283 return value
251 284
252 285 class ValidPath(formencode.validators.FancyValidator):
253 286 def to_python(self, value, state):
254 287
255 288 if not os.path.isdir(value):
256 289 msg = _('This is not a valid path')
257 290 raise formencode.Invalid(msg, value, state,
258 291 error_dict={'paths_root_path':msg})
259 292 return value
260 293
261 294 def UniqSystemEmail(old_data):
262 295 class _UniqSystemEmail(formencode.validators.FancyValidator):
263 296 def to_python(self, value, state):
264 297 value = value.lower()
265 298 if old_data.get('email') != value:
266 299 sa = meta.Session()
267 300 try:
268 301 user = sa.query(User).filter(User.email == value).scalar()
269 302 if user:
270 303 raise formencode.Invalid(_("This e-mail address is already taken") ,
271 304 value, state)
272 305 finally:
273 306 meta.Session.remove()
274 307
275 308 return value
276 309
277 310 return _UniqSystemEmail
278 311
279 312 class ValidSystemEmail(formencode.validators.FancyValidator):
280 313 def to_python(self, value, state):
281 314 value = value.lower()
282 315 sa = meta.Session
283 316 try:
284 317 user = sa.query(User).filter(User.email == value).scalar()
285 318 if user is None:
286 319 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
287 320 value, state)
288 321 finally:
289 322 meta.Session.remove()
290 323
291 324 return value
292 325
293 326 class LdapLibValidator(formencode.validators.FancyValidator):
294 327
295 328 def to_python(self, value, state):
296 329
297 330 try:
298 331 import ldap
299 332 except ImportError:
300 333 raise LdapImportError
301 334 return value
302 335
303 336 class BaseDnValidator(formencode.validators.FancyValidator):
304 337
305 338 def to_python(self, value, state):
306 339
307 340 try:
308 341 value % {'user':'valid'}
309 342
310 343 if value.find('%(user)s') == -1:
311 344 raise formencode.Invalid(_("You need to specify %(user)s in "
312 345 "template for example uid=%(user)s "
313 346 ",dc=company...") ,
314 347 value, state)
315 348
316 349 except KeyError:
317 350 raise formencode.Invalid(_("Wrong template used, only %(user)s "
318 351 "is an valid entry") ,
319 352 value, state)
320 353
321 354 return value
322 355
323 356 #===============================================================================
324 357 # FORMS
325 358 #===============================================================================
326 359 class LoginForm(formencode.Schema):
327 360 allow_extra_fields = True
328 361 filter_extra_fields = True
329 362 username = UnicodeString(
330 363 strip=True,
331 364 min=1,
332 365 not_empty=True,
333 366 messages={
334 367 'empty':_('Please enter a login'),
335 368 'tooShort':_('Enter a value %(min)i characters long or more')}
336 369 )
337 370
338 371 password = UnicodeString(
339 372 strip=True,
340 373 min=6,
341 374 not_empty=True,
342 375 messages={
343 376 'empty':_('Please enter a password'),
344 377 'tooShort':_('Enter %(min)i characters or more')}
345 378 )
346 379
347 380
348 381 #chained validators have access to all data
349 382 chained_validators = [ValidAuth]
350 383
351 384 def UserForm(edit=False, old_data={}):
352 385 class _UserForm(formencode.Schema):
353 386 allow_extra_fields = True
354 387 filter_extra_fields = True
355 388 username = All(UnicodeString(strip=True, min=1, not_empty=True),
356 389 ValidUsername(edit, old_data))
357 390 if edit:
358 391 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
359 392 admin = StringBoolean(if_missing=False)
360 393 else:
361 394 password = All(UnicodeString(strip=True, min=6, not_empty=True))
362 395 active = StringBoolean(if_missing=False)
363 396 name = UnicodeString(strip=True, min=1, not_empty=True)
364 397 lastname = UnicodeString(strip=True, min=1, not_empty=True)
365 398 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
366 399
367 400 chained_validators = [ValidPassword]
368 401
369 402 return _UserForm
370 403
404
405 def UsersGroupForm(edit=False, old_data={}):
406 class _UsersGroupForm(formencode.Schema):
407 allow_extra_fields = True
408 filter_extra_fields = True
409
410 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
411 ValidUsersGroup(edit, old_data))
412
413 users_group_active = StringBoolean(if_missing=False)
414
415 return _UsersGroupForm
416
371 417 def RegisterForm(edit=False, old_data={}):
372 418 class _RegisterForm(formencode.Schema):
373 419 allow_extra_fields = True
374 420 filter_extra_fields = True
375 421 username = All(ValidUsername(edit, old_data),
376 422 UnicodeString(strip=True, min=1, not_empty=True))
377 423 password = All(UnicodeString(strip=True, min=6, not_empty=True))
378 424 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
379 425 active = StringBoolean(if_missing=False)
380 426 name = UnicodeString(strip=True, min=1, not_empty=True)
381 427 lastname = UnicodeString(strip=True, min=1, not_empty=True)
382 428 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
383 429
384 430 chained_validators = [ValidPasswordsMatch, ValidPassword]
385 431
386 432 return _RegisterForm
387 433
388 434 def PasswordResetForm():
389 435 class _PasswordResetForm(formencode.Schema):
390 436 allow_extra_fields = True
391 437 filter_extra_fields = True
392 438 email = All(ValidSystemEmail(), Email(not_empty=True))
393 439 return _PasswordResetForm
394 440
395 441 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
396 442 class _RepoForm(formencode.Schema):
397 443 allow_extra_fields = True
398 444 filter_extra_fields = False
399 445 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
400 446 ValidRepoName(edit, old_data))
401 447 description = UnicodeString(strip=True, min=1, not_empty=True)
402 448 private = StringBoolean(if_missing=False)
403 449 enable_statistics = StringBoolean(if_missing=False)
404 450 repo_type = OneOf(supported_backends)
405 451 if edit:
406 452 user = All(Int(not_empty=True), ValidRepoUser)
407 453
408 454 chained_validators = [ValidPerms]
409 455 return _RepoForm
410 456
411 457 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
412 458 class _RepoForkForm(formencode.Schema):
413 459 allow_extra_fields = True
414 460 filter_extra_fields = False
415 461 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
416 462 ValidRepoName(edit, old_data))
417 463 description = UnicodeString(strip=True, min=1, not_empty=True)
418 464 private = StringBoolean(if_missing=False)
419 465 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
420 466 return _RepoForkForm
421 467
422 468 def RepoSettingsForm(edit=False, old_data={}):
423 469 class _RepoForm(formencode.Schema):
424 470 allow_extra_fields = True
425 471 filter_extra_fields = False
426 472 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
427 473 ValidRepoName(edit, old_data))
428 474 description = UnicodeString(strip=True, min=1, not_empty=True)
429 475 private = StringBoolean(if_missing=False)
430 476
431 477 chained_validators = [ValidPerms, ValidSettings]
432 478 return _RepoForm
433 479
434 480
435 481 def ApplicationSettingsForm():
436 482 class _ApplicationSettingsForm(formencode.Schema):
437 483 allow_extra_fields = True
438 484 filter_extra_fields = False
439 485 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
440 486 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
441 487 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
442 488
443 489 return _ApplicationSettingsForm
444 490
445 491 def ApplicationUiSettingsForm():
446 492 class _ApplicationUiSettingsForm(formencode.Schema):
447 493 allow_extra_fields = True
448 494 filter_extra_fields = False
449 495 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
450 496 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
451 497 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
452 498 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
453 499 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
454 500 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
455 501
456 502 return _ApplicationUiSettingsForm
457 503
458 504 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
459 505 class _DefaultPermissionsForm(formencode.Schema):
460 506 allow_extra_fields = True
461 507 filter_extra_fields = True
462 508 overwrite_default = StringBoolean(if_missing=False)
463 509 anonymous = OneOf(['True', 'False'], if_missing=False)
464 510 default_perm = OneOf(perms_choices)
465 511 default_register = OneOf(register_choices)
466 512 default_create = OneOf(create_choices)
467 513
468 514 return _DefaultPermissionsForm
469 515
470 516
471 517 def LdapSettingsForm():
472 518 class _LdapSettingsForm(formencode.Schema):
473 519 allow_extra_fields = True
474 520 filter_extra_fields = True
475 521 pre_validators = [LdapLibValidator]
476 522 ldap_active = StringBoolean(if_missing=False)
477 523 ldap_host = UnicodeString(strip=True,)
478 524 ldap_port = Number(strip=True,)
479 525 ldap_ldaps = StringBoolean(if_missing=False)
480 526 ldap_dn_user = UnicodeString(strip=True,)
481 527 ldap_dn_pass = UnicodeString(strip=True,)
482 528 ldap_base_dn = All(BaseDnValidator, UnicodeString(strip=True,))
483 529
484 530 return _LdapSettingsForm
@@ -1,26 +1,79
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
28 import logging
29 import traceback
30
31 from pylons.i18n.translation import _
32
33 from rhodecode.model import BaseModel
34 from rhodecode.model.caching_query import FromCache
35 from rhodecode.model.db import UsersGroup
36
37 from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException
38
39 from sqlalchemy.exc import DatabaseError
40
41 log = logging.getLogger(__name__)
42
43
44 class UsersGroupModel(BaseModel):
45
46 def get(self, users_group_id, cache=False):
47 users_group = self.sa.query(UsersGroup)
48 if cache:
49 users_group = users_group.options(FromCache("sql_cache_short",
50 "get_users_group_%s" % users_group_id))
51 return users_group.get(users_group_id)
52
53
54 def get_by_groupname(self, users_group_name, cache=False, case_insensitive=False):
55
56 if case_insensitive:
57 user = self.sa.query(UsersGroup)\
58 .filter(UsersGroup.users_group_name.ilike(users_group_name))
59 else:
60 user = self.sa.query(UsersGroup)\
61 .filter(UsersGroup.users_group_name == users_group_name)
62 if cache:
63 user = user.options(FromCache("sql_cache_short",
64 "get_user_%s" % users_group_name))
65 return user.scalar()
66
67 def create(self, form_data):
68 try:
69 new_users_group = UsersGroup()
70 for k, v in form_data.items():
71 setattr(new_users_group, k, v)
72
73 self.sa.add(new_users_group)
74 self.sa.commit()
75 except:
76 log.error(traceback.format_exc())
77 self.sa.rollback()
78 raise
79
@@ -0,0 +1,55
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
3
4 <%def name="title()">
5 ${_('Add users group')} - ${c.rhodecode_name}
6 </%def>
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 &raquo;
10 ${h.link_to(_('Users groups'),h.url('users_groups'))}
11 &raquo;
12 ${_('add new users group')}
13 </%def>
14
15 <%def name="page_nav()">
16 ${self.menu('admin')}
17 </%def>
18
19 <%def name="main()">
20 <div class="box">
21 <!-- box / title -->
22 <div class="title">
23 ${self.breadcrumbs()}
24 </div>
25 <!-- end box / title -->
26 ${h.form(url('users_groups'))}
27 <div class="form">
28 <!-- fields -->
29 <div class="fields">
30 <div class="field">
31 <div class="label">
32 <label for="users_group_name">${_('Group name')}:</label>
33 </div>
34 <div class="input">
35 ${h.text('users_group_name',class_='small')}
36 </div>
37 </div>
38
39 <div class="field">
40 <div class="label label-checkbox">
41 <label for="users_group_active">${_('Active')}:</label>
42 </div>
43 <div class="checkboxes">
44 ${h.checkbox('users_group_active',value=True)}
45 </div>
46 </div>
47
48 <div class="buttons">
49 ${h.submit('save','save',class_="ui-button")}
50 </div>
51 </div>
52 </div>
53 ${h.end_form()}
54 </div>
55 </%def> No newline at end of file
@@ -1,54 +1,53
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Users groups administration')} - ${c.rhodecode_name}
6 6 </%def>
7 7
8 8 <%def name="breadcrumbs_links()">
9 9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Users groups')}
10 10 </%def>
11 11
12 12 <%def name="page_nav()">
13 13 ${self.menu('admin')}
14 14 </%def>
15 15
16 16 <%def name="main()">
17 17 <div class="box">
18 18 <!-- box / title -->
19 19 <div class="title">
20 20 ${self.breadcrumbs()}
21 21 <ul class="links">
22 22 <li>
23 23 <span>${h.link_to(u'ADD NEW USER GROUP',h.url('new_users_group'))}</span>
24 24 </li>
25 25
26 26 </ul>
27 27 </div>
28 28 <!-- end box / title -->
29 29 <div class="table">
30 30 <table class="table_disp">
31 31 <tr class="header">
32 <th></th>
33 32 <th class="left">${_('group name')}</th>
34 33 <th class="left">${_('members')}</th>
35 34 <th class="left">${_('active')}</th>
36 35 <th class="left">${_('action')}</th>
37 36 </tr>
38 37 %for cnt,u_group in enumerate(c.users_groups_list):
39 38 <tr class="parity${cnt%2}">
40 <td>${h.link_to(u_group.groupname,h.url('edit_user_group', id=u_group.group_id))}</td>
41 <td>${u_group.members}</td>
42 <td>${h.bool2icon(u_group.active)}</td>
39 <td>${h.link_to(u_group.users_group_name,h.url('edit_users_group', id=u_group.users_group_id))}</td>
40 <td>${len(u_group.members)}</td>
41 <td>${h.bool2icon(u_group.users_group_active)}</td>
43 42 <td>
44 ${h.form(url('users_group', id=group.group_id),method='delete')}
45 ${h.submit('remove_','delete',id="remove_group_%s" % group.group_id,
46 class_="delete_icon action_button",onclick="return confirm('Confirm to delete this user group');")}
43 ${h.form(url('users_group', id=u_group.users_group_id),method='delete')}
44 ${h.submit('remove_','delete',id="remove_group_%s" % u_group.users_group_id,
45 class_="delete_icon action_button",onclick="return confirm('Confirm to delete this users group');")}
47 46 ${h.end_form()}
48 47 </td>
49 48 </tr>
50 49 %endfor
51 50 </table>
52 51 </div>
53 52 </div>
54 53 </%def>
General Comments 0
You need to be logged in to leave comments. Login now