##// END OF EJS Templates
sqlalchemy sessions cleanup in admin...
marcink -
r2662:91c442a4 beta
parent child Browse files
Show More
@@ -1,59 +1,59 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.admin
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Controller for Admin panel of Rhodecode
7 7
8 8 :created_on: Apr 7, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27
28 28 from pylons import request, tmpl_context as c
29 29 from sqlalchemy.orm import joinedload
30 30 from webhelpers.paginate import Page
31 31
32 32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
33 33 from rhodecode.lib.base import BaseController, render
34 34 from rhodecode.model.db import UserLog
35 35
36 36 log = logging.getLogger(__name__)
37 37
38 38
39 39 class AdminController(BaseController):
40 40
41 41 @LoginRequired()
42 42 def __before__(self):
43 43 super(AdminController, self).__before__()
44 44
45 45 @HasPermissionAllDecorator('hg.admin')
46 46 def index(self):
47 47
48 users_log = self.sa.query(UserLog)\
48 users_log = UserLog.query()\
49 49 .options(joinedload(UserLog.user))\
50 50 .options(joinedload(UserLog.repository))\
51 51 .order_by(UserLog.action_date.desc())
52 52
53 53 p = int(request.params.get('page', 1))
54 54 c.users_log = Page(users_log, page=p, items_per_page=10)
55 55 c.log_data = render('admin/admin_log.html')
56 56
57 57 if request.environ.get('HTTP_X_PARTIAL_XHR'):
58 58 return c.log_data
59 59 return render('admin/admin.html')
@@ -1,149 +1,150 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.ldap_settings
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 ldap controller for RhodeCode
7 7
8 8 :created_on: Nov 26, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25 import logging
26 26 import formencode
27 27 import traceback
28 28
29 29 from formencode import htmlfill
30 30
31 31 from pylons import request, response, session, tmpl_context as c, url
32 32 from pylons.controllers.util import abort, redirect
33 33 from pylons.i18n.translation import _
34 34
35 35 from sqlalchemy.exc import DatabaseError
36 36
37 37 from rhodecode.lib.base import BaseController, render
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
40 40 from rhodecode.lib.exceptions import LdapImportError
41 41 from rhodecode.model.forms import LdapSettingsForm
42 42 from rhodecode.model.db import RhodeCodeSetting
43 from rhodecode.model.meta import Session
43 44
44 45 log = logging.getLogger(__name__)
45 46
46 47
47 48 class LdapSettingsController(BaseController):
48 49
49 50 search_scope_choices = [('BASE', _('BASE'),),
50 51 ('ONELEVEL', _('ONELEVEL'),),
51 52 ('SUBTREE', _('SUBTREE'),),
52 53 ]
53 54 search_scope_default = 'SUBTREE'
54 55
55 56 tls_reqcert_choices = [('NEVER', _('NEVER'),),
56 57 ('ALLOW', _('ALLOW'),),
57 58 ('TRY', _('TRY'),),
58 59 ('DEMAND', _('DEMAND'),),
59 60 ('HARD', _('HARD'),),
60 61 ]
61 62 tls_reqcert_default = 'DEMAND'
62 63
63 64 tls_kind_choices = [('PLAIN', _('No encryption'),),
64 65 ('LDAPS', _('LDAPS connection'),),
65 66 ('START_TLS', _('START_TLS on LDAP connection'),)
66 67 ]
67 68
68 69 tls_kind_default = 'PLAIN'
69 70
70 71 @LoginRequired()
71 72 @HasPermissionAllDecorator('hg.admin')
72 73 def __before__(self):
73 74 c.admin_user = session.get('admin_user')
74 75 c.admin_username = session.get('admin_username')
75 76 c.search_scope_choices = self.search_scope_choices
76 77 c.tls_reqcert_choices = self.tls_reqcert_choices
77 78 c.tls_kind_choices = self.tls_kind_choices
78 79
79 80 c.search_scope_cur = self.search_scope_default
80 81 c.tls_reqcert_cur = self.tls_reqcert_default
81 82 c.tls_kind_cur = self.tls_kind_default
82 83
83 84 super(LdapSettingsController, self).__before__()
84 85
85 86 def index(self):
86 87 defaults = RhodeCodeSetting.get_ldap_settings()
87 88 c.search_scope_cur = defaults.get('ldap_search_scope')
88 89 c.tls_reqcert_cur = defaults.get('ldap_tls_reqcert')
89 90 c.tls_kind_cur = defaults.get('ldap_tls_kind')
90 91
91 92 return htmlfill.render(
92 93 render('admin/ldap/ldap.html'),
93 94 defaults=defaults,
94 95 encoding="UTF-8",
95 96 force_defaults=True,)
96 97
97 98 def ldap_settings(self):
98 99 """POST ldap create and store ldap settings"""
99 100
100 101 _form = LdapSettingsForm([x[0] for x in self.tls_reqcert_choices],
101 102 [x[0] for x in self.search_scope_choices],
102 103 [x[0] for x in self.tls_kind_choices])()
103 104 # check the ldap lib
104 105 ldap_active = False
105 106 try:
106 107 import ldap
107 108 ldap_active = True
108 109 except ImportError:
109 110 pass
110 111
111 112 try:
112 113 form_result = _form.to_python(dict(request.POST))
113 114
114 115 try:
115 116
116 117 for k, v in form_result.items():
117 118 if k.startswith('ldap_'):
118 119 if k == 'ldap_active':
119 120 v = ldap_active
120 121 setting = RhodeCodeSetting.get_by_name(k)
121 122 setting.app_settings_value = v
122 self.sa.add(setting)
123 Session().add(setting)
123 124
124 self.sa.commit()
125 Session().commit()
125 126 h.flash(_('Ldap settings updated successfully'),
126 127 category='success')
127 128 if not ldap_active:
128 129 #if ldap is missing send an info to user
129 130 h.flash(_('Unable to activate ldap. The "python-ldap" library '
130 131 'is missing.'), category='warning')
131 132
132 133 except (DatabaseError,):
133 134 raise
134 135
135 136 except formencode.Invalid, errors:
136 137 e = errors.error_dict or {}
137 138
138 139 return htmlfill.render(
139 140 render('admin/ldap/ldap.html'),
140 141 defaults=errors.value,
141 142 errors=e,
142 143 prefix_error=False,
143 144 encoding="UTF-8")
144 145 except Exception:
145 146 log.error(traceback.format_exc())
146 147 h.flash(_('error occurred during update of ldap settings'),
147 148 category='error')
148 149
149 150 return redirect(url('ldap_home'))
@@ -1,170 +1,170 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.notifications
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 notifications controller for RhodeCode
7 7
8 8 :created_on: Nov 23, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28
29 29 from pylons import request
30 30 from pylons import tmpl_context as c, url
31 31 from pylons.controllers.util import redirect
32 32
33 33 from webhelpers.paginate import Page
34 34
35 35 from rhodecode.lib.base import BaseController, render
36 36 from rhodecode.model.db import Notification
37 37
38 38 from rhodecode.model.notification import NotificationModel
39 39 from rhodecode.lib.auth import LoginRequired, NotAnonymous
40 40 from rhodecode.lib import helpers as h
41 41 from rhodecode.model.meta import Session
42 42
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46
47 47 class NotificationsController(BaseController):
48 48 """REST Controller styled on the Atom Publishing Protocol"""
49 49 # To properly map this controller, ensure your config/routing.py
50 50 # file has a resource setup:
51 51 # map.resource('notification', 'notifications', controller='_admin/notifications',
52 52 # path_prefix='/_admin', name_prefix='_admin_')
53 53
54 54 @LoginRequired()
55 55 @NotAnonymous()
56 56 def __before__(self):
57 57 super(NotificationsController, self).__before__()
58 58
59 59 def index(self, format='html'):
60 60 """GET /_admin/notifications: All items in the collection"""
61 61 # url('notifications')
62 62 c.user = self.rhodecode_user
63 63 notif = NotificationModel().get_for_user(self.rhodecode_user.user_id,
64 64 filter_=request.GET.getall('type'))
65 65 p = int(request.params.get('page', 1))
66 66 c.notifications = Page(notif, page=p, items_per_page=10)
67 67 c.pull_request_type = Notification.TYPE_PULL_REQUEST
68 68 c.comment_type = [Notification.TYPE_CHANGESET_COMMENT,
69 69 Notification.TYPE_PULL_REQUEST_COMMENT]
70 70
71 71 _current_filter = request.GET.getall('type')
72 72 c.current_filter = 'all'
73 73 if _current_filter == [c.pull_request_type]:
74 74 c.current_filter = 'pull_request'
75 75 elif _current_filter == c.comment_type:
76 76 c.current_filter = 'comment'
77 77
78 78 return render('admin/notifications/notifications.html')
79 79
80 80 def mark_all_read(self):
81 81 if request.environ.get('HTTP_X_PARTIAL_XHR'):
82 82 nm = NotificationModel()
83 83 # mark all read
84 84 nm.mark_all_read_for_user(self.rhodecode_user.user_id,
85 85 filter_=request.GET.getall('type'))
86 Session.commit()
86 Session().commit()
87 87 c.user = self.rhodecode_user
88 88 notif = nm.get_for_user(self.rhodecode_user.user_id,
89 89 filter_=request.GET.getall('type'))
90 90 c.notifications = Page(notif, page=1, items_per_page=10)
91 91 return render('admin/notifications/notifications_data.html')
92 92
93 93 def create(self):
94 94 """POST /_admin/notifications: Create a new item"""
95 95 # url('notifications')
96 96
97 97 def new(self, format='html'):
98 98 """GET /_admin/notifications/new: Form to create a new item"""
99 99 # url('new_notification')
100 100
101 101 def update(self, notification_id):
102 102 """PUT /_admin/notifications/id: Update an existing item"""
103 103 # Forms posted to this method should contain a hidden field:
104 104 # <input type="hidden" name="_method" value="PUT" />
105 105 # Or using helpers:
106 106 # h.form(url('notification', notification_id=ID),
107 107 # method='put')
108 108 # url('notification', notification_id=ID)
109 109 try:
110 110 no = Notification.get(notification_id)
111 111 owner = lambda: (no.notifications_to_users.user.user_id
112 112 == c.rhodecode_user.user_id)
113 113 if h.HasPermissionAny('hg.admin')() or owner:
114 114 NotificationModel().mark_read(c.rhodecode_user.user_id, no)
115 Session.commit()
115 Session().commit()
116 116 return 'ok'
117 117 except Exception:
118 118 Session.rollback()
119 119 log.error(traceback.format_exc())
120 120 return 'fail'
121 121
122 122 def delete(self, notification_id):
123 123 """DELETE /_admin/notifications/id: Delete an existing item"""
124 124 # Forms posted to this method should contain a hidden field:
125 125 # <input type="hidden" name="_method" value="DELETE" />
126 126 # Or using helpers:
127 127 # h.form(url('notification', notification_id=ID),
128 128 # method='delete')
129 129 # url('notification', notification_id=ID)
130 130
131 131 try:
132 132 no = Notification.get(notification_id)
133 133 owner = lambda: (no.notifications_to_users.user.user_id
134 134 == c.rhodecode_user.user_id)
135 135 if h.HasPermissionAny('hg.admin')() or owner:
136 136 NotificationModel().delete(c.rhodecode_user.user_id, no)
137 Session.commit()
137 Session().commit()
138 138 return 'ok'
139 139 except Exception:
140 140 Session.rollback()
141 141 log.error(traceback.format_exc())
142 142 return 'fail'
143 143
144 144 def show(self, notification_id, format='html'):
145 145 """GET /_admin/notifications/id: Show a specific item"""
146 146 # url('notification', notification_id=ID)
147 147 c.user = self.rhodecode_user
148 148 no = Notification.get(notification_id)
149 149
150 150 owner = lambda: (no.notifications_to_users.user.user_id
151 151 == c.user.user_id)
152 152 if no and (h.HasPermissionAny('hg.admin', 'repository.admin')() or owner):
153 153 unotification = NotificationModel()\
154 154 .get_user_notification(c.user.user_id, no)
155 155
156 156 # if this association to user is not valid, we don't want to show
157 157 # this message
158 158 if unotification:
159 159 if unotification.read is False:
160 160 unotification.mark_as_read()
161 Session.commit()
161 Session().commit()
162 162 c.notification = no
163 163
164 164 return render('admin/notifications/show_notification.html')
165 165
166 166 return redirect(url('notifications'))
167 167
168 168 def edit(self, notification_id, format='html'):
169 169 """GET /_admin/notifications/id/edit: Form to edit an existing item"""
170 170 # url('edit_notification', notification_id=ID)
@@ -1,169 +1,169 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.permissions
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 permissions controller for Rhodecode
7 7
8 8 :created_on: Apr 27, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29 from formencode import htmlfill
30 30
31 31 from pylons import request, session, tmpl_context as c, url
32 32 from pylons.controllers.util import abort, redirect
33 33 from pylons.i18n.translation import _
34 34
35 35 from rhodecode.lib import helpers as h
36 36 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
37 37 from rhodecode.lib.base import BaseController, render
38 38 from rhodecode.model.forms import DefaultPermissionsForm
39 39 from rhodecode.model.permission import PermissionModel
40 40 from rhodecode.model.db import User
41 41 from rhodecode.model.meta import Session
42 42
43 43 log = logging.getLogger(__name__)
44 44
45 45
46 46 class PermissionsController(BaseController):
47 47 """REST Controller styled on the Atom Publishing Protocol"""
48 48 # To properly map this controller, ensure your config/routing.py
49 49 # file has a resource setup:
50 50 # map.resource('permission', 'permissions')
51 51
52 52 @LoginRequired()
53 53 @HasPermissionAllDecorator('hg.admin')
54 54 def __before__(self):
55 55 c.admin_user = session.get('admin_user')
56 56 c.admin_username = session.get('admin_username')
57 57 super(PermissionsController, self).__before__()
58 58
59 59 self.perms_choices = [('repository.none', _('None'),),
60 60 ('repository.read', _('Read'),),
61 61 ('repository.write', _('Write'),),
62 62 ('repository.admin', _('Admin'),)]
63 63 self.register_choices = [
64 64 ('hg.register.none',
65 65 _('disabled')),
66 66 ('hg.register.manual_activate',
67 67 _('allowed with manual account activation')),
68 68 ('hg.register.auto_activate',
69 69 _('allowed with automatic account activation')), ]
70 70
71 71 self.create_choices = [('hg.create.none', _('Disabled')),
72 72 ('hg.create.repository', _('Enabled'))]
73 73
74 74 def index(self, format='html'):
75 75 """GET /permissions: All items in the collection"""
76 76 # url('permissions')
77 77
78 78 def create(self):
79 79 """POST /permissions: Create a new item"""
80 80 # url('permissions')
81 81
82 82 def new(self, format='html'):
83 83 """GET /permissions/new: Form to create a new item"""
84 84 # url('new_permission')
85 85
86 86 def update(self, id):
87 87 """PUT /permissions/id: Update an existing item"""
88 88 # Forms posted to this method should contain a hidden field:
89 89 # <input type="hidden" name="_method" value="PUT" />
90 90 # Or using helpers:
91 91 # h.form(url('permission', id=ID),
92 92 # method='put')
93 93 # url('permission', id=ID)
94 94
95 95 permission_model = PermissionModel()
96 96
97 97 _form = DefaultPermissionsForm([x[0] for x in self.perms_choices],
98 98 [x[0] for x in self.register_choices],
99 99 [x[0] for x in self.create_choices])()
100 100
101 101 try:
102 102 form_result = _form.to_python(dict(request.POST))
103 103 form_result.update({'perm_user_name': id})
104 104 permission_model.update(form_result)
105 Session.commit()
105 Session().commit()
106 106 h.flash(_('Default permissions updated successfully'),
107 107 category='success')
108 108
109 109 except formencode.Invalid, errors:
110 110 c.perms_choices = self.perms_choices
111 111 c.register_choices = self.register_choices
112 112 c.create_choices = self.create_choices
113 113 defaults = errors.value
114 114
115 115 return htmlfill.render(
116 116 render('admin/permissions/permissions.html'),
117 117 defaults=defaults,
118 118 errors=errors.error_dict or {},
119 119 prefix_error=False,
120 120 encoding="UTF-8")
121 121 except Exception:
122 122 log.error(traceback.format_exc())
123 123 h.flash(_('error occurred during update of permissions'),
124 124 category='error')
125 125
126 126 return redirect(url('edit_permission', id=id))
127 127
128 128 def delete(self, id):
129 129 """DELETE /permissions/id: Delete an existing item"""
130 130 # Forms posted to this method should contain a hidden field:
131 131 # <input type="hidden" name="_method" value="DELETE" />
132 132 # Or using helpers:
133 133 # h.form(url('permission', id=ID),
134 134 # method='delete')
135 135 # url('permission', id=ID)
136 136
137 137 def show(self, id, format='html'):
138 138 """GET /permissions/id: Show a specific item"""
139 139 # url('permission', id=ID)
140 140
141 141 def edit(self, id, format='html'):
142 142 """GET /permissions/id/edit: Form to edit an existing item"""
143 143 #url('edit_permission', id=ID)
144 144 c.perms_choices = self.perms_choices
145 145 c.register_choices = self.register_choices
146 146 c.create_choices = self.create_choices
147 147
148 148 if id == 'default':
149 149 default_user = User.get_by_username('default')
150 150 defaults = {'_method': 'put',
151 151 'anonymous': default_user.active}
152 152
153 153 for p in default_user.user_perms:
154 154 if p.permission.permission_name.startswith('repository.'):
155 155 defaults['default_perm'] = p.permission.permission_name
156 156
157 157 if p.permission.permission_name.startswith('hg.register.'):
158 158 defaults['default_register'] = p.permission.permission_name
159 159
160 160 if p.permission.permission_name.startswith('hg.create.'):
161 161 defaults['default_create'] = p.permission.permission_name
162 162
163 163 return htmlfill.render(
164 164 render('admin/permissions/permissions.html'),
165 165 defaults=defaults,
166 166 encoding="UTF-8",
167 167 force_defaults=True,)
168 168 else:
169 169 return redirect(url('admin_home'))
@@ -1,448 +1,448 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.repos
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repositories controller for RhodeCode
7 7
8 8 :created_on: Apr 7, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29 from formencode import htmlfill
30 30
31 31 from webob.exc import HTTPInternalServerError
32 32 from pylons import request, session, tmpl_context as c, url
33 33 from pylons.controllers.util import redirect
34 34 from pylons.i18n.translation import _
35 35 from sqlalchemy.exc import IntegrityError
36 36
37 37 from rhodecode.lib import helpers as h
38 38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
39 39 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator
40 40 from rhodecode.lib.base import BaseController, render
41 41 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
42 42 from rhodecode.lib.helpers import get_token
43 43 from rhodecode.model.meta import Session
44 44 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup
45 45 from rhodecode.model.forms import RepoForm
46 46 from rhodecode.model.scm import ScmModel
47 47 from rhodecode.model.repo import RepoModel
48 48
49 49 log = logging.getLogger(__name__)
50 50
51 51
52 52 class ReposController(BaseController):
53 53 """
54 54 REST Controller styled on the Atom Publishing Protocol"""
55 55 # To properly map this controller, ensure your config/routing.py
56 56 # file has a resource setup:
57 57 # map.resource('repo', 'repos')
58 58
59 59 @LoginRequired()
60 60 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
61 61 def __before__(self):
62 62 c.admin_user = session.get('admin_user')
63 63 c.admin_username = session.get('admin_username')
64 64 super(ReposController, self).__before__()
65 65
66 66 def __load_defaults(self):
67 67 c.repo_groups = RepoGroup.groups_choices()
68 68 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
69 69
70 70 repo_model = RepoModel()
71 71 c.users_array = repo_model.get_users_js()
72 72 c.users_groups_array = repo_model.get_users_groups_js()
73 73 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
74 74 c.landing_revs_choices = choices
75 75
76 76 def __load_data(self, repo_name=None):
77 77 """
78 78 Load defaults settings for edit, and update
79 79
80 80 :param repo_name:
81 81 """
82 82 self.__load_defaults()
83 83
84 84 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
85 85 repo = db_repo.scm_instance
86 86
87 87 if c.repo_info is None:
88 88 h.flash(_('%s repository is not mapped to db perhaps'
89 89 ' it was created or renamed from the filesystem'
90 90 ' please run the application again'
91 91 ' in order to rescan repositories') % repo_name,
92 92 category='error')
93 93
94 94 return redirect(url('repos'))
95 95
96 96 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
97 97 c.landing_revs_choices = choices
98 98
99 99 c.default_user_id = User.get_by_username('default').user_id
100 100 c.in_public_journal = UserFollowing.query()\
101 101 .filter(UserFollowing.user_id == c.default_user_id)\
102 102 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
103 103
104 104 if c.repo_info.stats:
105 105 # this is on what revision we ended up so we add +1 for count
106 106 last_rev = c.repo_info.stats.stat_on_revision + 1
107 107 else:
108 108 last_rev = 0
109 109 c.stats_revision = last_rev
110 110
111 111 c.repo_last_rev = repo.count() if repo.revisions else 0
112 112
113 113 if last_rev == 0 or c.repo_last_rev == 0:
114 114 c.stats_percentage = 0
115 115 else:
116 116 c.stats_percentage = '%.2f' % ((float((last_rev)) /
117 117 c.repo_last_rev) * 100)
118 118
119 119 defaults = RepoModel()._get_defaults(repo_name)
120 120
121 121 c.repos_list = [('', _('--REMOVE FORK--'))]
122 122 c.repos_list += [(x.repo_id, x.repo_name) for x in
123 123 Repository.query().order_by(Repository.repo_name).all()
124 124 if x.repo_id != c.repo_info.repo_id]
125 125
126 126 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
127 127 return defaults
128 128
129 129 @HasPermissionAllDecorator('hg.admin')
130 130 def index(self, format='html'):
131 131 """GET /repos: All items in the collection"""
132 132 # url('repos')
133 133
134 134 c.repos_list = ScmModel().get_repos(Repository.query()
135 135 .order_by(Repository.repo_name)
136 136 .all(), sort_key='name_sort')
137 137 return render('admin/repos/repos.html')
138 138
139 139 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
140 140 def create(self):
141 141 """
142 142 POST /repos: Create a new item"""
143 143 # url('repos')
144 144
145 145 self.__load_defaults()
146 146 form_result = {}
147 147 try:
148 148 form_result = RepoForm(repo_groups=c.repo_groups_choices,
149 149 landing_revs=c.landing_revs_choices)()\
150 150 .to_python(dict(request.POST))
151 151 new_repo = RepoModel().create(form_result,
152 152 self.rhodecode_user.user_id)
153 153 if form_result['clone_uri']:
154 154 h.flash(_('created repository %s from %s') \
155 155 % (form_result['repo_name'], form_result['clone_uri']),
156 156 category='success')
157 157 else:
158 158 h.flash(_('created repository %s') % form_result['repo_name'],
159 159 category='success')
160 160
161 161 if request.POST.get('user_created'):
162 162 # created by regular non admin user
163 163 action_logger(self.rhodecode_user, 'user_created_repo',
164 164 form_result['repo_name_full'], self.ip_addr,
165 165 self.sa)
166 166 else:
167 167 action_logger(self.rhodecode_user, 'admin_created_repo',
168 168 form_result['repo_name_full'], self.ip_addr,
169 169 self.sa)
170 Session.commit()
170 Session().commit()
171 171 except formencode.Invalid, errors:
172 172
173 173 c.new_repo = errors.value['repo_name']
174 174
175 175 if request.POST.get('user_created'):
176 176 r = render('admin/repos/repo_add_create_repository.html')
177 177 else:
178 178 r = render('admin/repos/repo_add.html')
179 179
180 180 return htmlfill.render(
181 181 r,
182 182 defaults=errors.value,
183 183 errors=errors.error_dict or {},
184 184 prefix_error=False,
185 185 encoding="UTF-8")
186 186
187 187 except Exception:
188 188 log.error(traceback.format_exc())
189 189 msg = _('error occurred during creation of repository %s') \
190 190 % form_result.get('repo_name')
191 191 h.flash(msg, category='error')
192 192 #redirect to our new repo !
193 193 return redirect(url('summary_home', repo_name=new_repo.repo_name))
194 194
195 195 @HasPermissionAllDecorator('hg.admin')
196 196 def new(self, format='html'):
197 197 """GET /repos/new: Form to create a new item"""
198 198 new_repo = request.GET.get('repo', '')
199 199 c.new_repo = repo_name_slug(new_repo)
200 200 self.__load_defaults()
201 201 return render('admin/repos/repo_add.html')
202 202
203 203 @HasPermissionAllDecorator('hg.admin')
204 204 def update(self, repo_name):
205 205 """
206 206 PUT /repos/repo_name: Update an existing item"""
207 207 # Forms posted to this method should contain a hidden field:
208 208 # <input type="hidden" name="_method" value="PUT" />
209 209 # Or using helpers:
210 210 # h.form(url('repo', repo_name=ID),
211 211 # method='put')
212 212 # url('repo', repo_name=ID)
213 213 self.__load_defaults()
214 214 repo_model = RepoModel()
215 215 changed_name = repo_name
216 216 #override the choices with extracted revisions !
217 217 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
218 218 c.landing_revs_choices = choices
219 219
220 220 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
221 221 repo_groups=c.repo_groups_choices,
222 222 landing_revs=c.landing_revs_choices)()
223 223 try:
224 224 form_result = _form.to_python(dict(request.POST))
225 225 repo = repo_model.update(repo_name, form_result)
226 226 invalidate_cache('get_repo_cached_%s' % repo_name)
227 227 h.flash(_('Repository %s updated successfully') % repo_name,
228 228 category='success')
229 229 changed_name = repo.repo_name
230 230 action_logger(self.rhodecode_user, 'admin_updated_repo',
231 231 changed_name, self.ip_addr, self.sa)
232 Session.commit()
232 Session().commit()
233 233 except formencode.Invalid, errors:
234 234 defaults = self.__load_data(repo_name)
235 235 defaults.update(errors.value)
236 236 return htmlfill.render(
237 237 render('admin/repos/repo_edit.html'),
238 238 defaults=defaults,
239 239 errors=errors.error_dict or {},
240 240 prefix_error=False,
241 241 encoding="UTF-8")
242 242
243 243 except Exception:
244 244 log.error(traceback.format_exc())
245 245 h.flash(_('error occurred during update of repository %s') \
246 246 % repo_name, category='error')
247 247 return redirect(url('edit_repo', repo_name=changed_name))
248 248
249 249 @HasPermissionAllDecorator('hg.admin')
250 250 def delete(self, repo_name):
251 251 """
252 252 DELETE /repos/repo_name: Delete an existing item"""
253 253 # Forms posted to this method should contain a hidden field:
254 254 # <input type="hidden" name="_method" value="DELETE" />
255 255 # Or using helpers:
256 256 # h.form(url('repo', repo_name=ID),
257 257 # method='delete')
258 258 # url('repo', repo_name=ID)
259 259
260 260 repo_model = RepoModel()
261 261 repo = repo_model.get_by_repo_name(repo_name)
262 262 if not repo:
263 263 h.flash(_('%s repository is not mapped to db perhaps'
264 264 ' it was moved or renamed from the filesystem'
265 265 ' please run the application again'
266 266 ' in order to rescan repositories') % repo_name,
267 267 category='error')
268 268
269 269 return redirect(url('repos'))
270 270 try:
271 271 action_logger(self.rhodecode_user, 'admin_deleted_repo',
272 272 repo_name, self.ip_addr, self.sa)
273 273 repo_model.delete(repo)
274 274 invalidate_cache('get_repo_cached_%s' % repo_name)
275 275 h.flash(_('deleted repository %s') % repo_name, category='success')
276 Session.commit()
276 Session().commit()
277 277 except IntegrityError, e:
278 278 if e.message.find('repositories_fork_id_fkey') != -1:
279 279 log.error(traceback.format_exc())
280 280 h.flash(_('Cannot delete %s it still contains attached '
281 281 'forks') % repo_name,
282 282 category='warning')
283 283 else:
284 284 log.error(traceback.format_exc())
285 285 h.flash(_('An error occurred during '
286 286 'deletion of %s') % repo_name,
287 287 category='error')
288 288
289 289 except Exception, e:
290 290 log.error(traceback.format_exc())
291 291 h.flash(_('An error occurred during deletion of %s') % repo_name,
292 292 category='error')
293 293
294 294 return redirect(url('repos'))
295 295
296 296 @HasRepoPermissionAllDecorator('repository.admin')
297 297 def delete_perm_user(self, repo_name):
298 298 """
299 299 DELETE an existing repository permission user
300 300
301 301 :param repo_name:
302 302 """
303 303 try:
304 304 RepoModel().revoke_user_permission(repo=repo_name,
305 305 user=request.POST['user_id'])
306 Session.commit()
306 Session().commit()
307 307 except Exception:
308 308 log.error(traceback.format_exc())
309 309 h.flash(_('An error occurred during deletion of repository user'),
310 310 category='error')
311 311 raise HTTPInternalServerError()
312 312
313 313 @HasRepoPermissionAllDecorator('repository.admin')
314 314 def delete_perm_users_group(self, repo_name):
315 315 """
316 316 DELETE an existing repository permission users group
317 317
318 318 :param repo_name:
319 319 """
320 320
321 321 try:
322 322 RepoModel().revoke_users_group_permission(
323 323 repo=repo_name, group_name=request.POST['users_group_id']
324 324 )
325 Session.commit()
325 Session().commit()
326 326 except Exception:
327 327 log.error(traceback.format_exc())
328 328 h.flash(_('An error occurred during deletion of repository'
329 329 ' users groups'),
330 330 category='error')
331 331 raise HTTPInternalServerError()
332 332
333 333 @HasPermissionAllDecorator('hg.admin')
334 334 def repo_stats(self, repo_name):
335 335 """
336 336 DELETE an existing repository statistics
337 337
338 338 :param repo_name:
339 339 """
340 340
341 341 try:
342 342 RepoModel().delete_stats(repo_name)
343 Session.commit()
343 Session().commit()
344 344 except Exception, e:
345 345 h.flash(_('An error occurred during deletion of repository stats'),
346 346 category='error')
347 347 return redirect(url('edit_repo', repo_name=repo_name))
348 348
349 349 @HasPermissionAllDecorator('hg.admin')
350 350 def repo_cache(self, repo_name):
351 351 """
352 352 INVALIDATE existing repository cache
353 353
354 354 :param repo_name:
355 355 """
356 356
357 357 try:
358 358 ScmModel().mark_for_invalidation(repo_name)
359 Session.commit()
359 Session().commit()
360 360 except Exception, e:
361 361 h.flash(_('An error occurred during cache invalidation'),
362 362 category='error')
363 363 return redirect(url('edit_repo', repo_name=repo_name))
364 364
365 365 @HasPermissionAllDecorator('hg.admin')
366 366 def repo_public_journal(self, repo_name):
367 367 """
368 368 Set's this repository to be visible in public journal,
369 369 in other words assing default user to follow this repo
370 370
371 371 :param repo_name:
372 372 """
373 373
374 374 cur_token = request.POST.get('auth_token')
375 375 token = get_token()
376 376 if cur_token == token:
377 377 try:
378 378 repo_id = Repository.get_by_repo_name(repo_name).repo_id
379 379 user_id = User.get_by_username('default').user_id
380 380 self.scm_model.toggle_following_repo(repo_id, user_id)
381 381 h.flash(_('Updated repository visibility in public journal'),
382 382 category='success')
383 Session.commit()
383 Session().commit()
384 384 except:
385 385 h.flash(_('An error occurred during setting this'
386 386 ' repository in public journal'),
387 387 category='error')
388 388
389 389 else:
390 390 h.flash(_('Token mismatch'), category='error')
391 391 return redirect(url('edit_repo', repo_name=repo_name))
392 392
393 393 @HasPermissionAllDecorator('hg.admin')
394 394 def repo_pull(self, repo_name):
395 395 """
396 396 Runs task to update given repository with remote changes,
397 397 ie. make pull on remote location
398 398
399 399 :param repo_name:
400 400 """
401 401 try:
402 402 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
403 403 h.flash(_('Pulled from remote location'), category='success')
404 404 except Exception, e:
405 405 h.flash(_('An error occurred during pull from remote location'),
406 406 category='error')
407 407
408 408 return redirect(url('edit_repo', repo_name=repo_name))
409 409
410 410 @HasPermissionAllDecorator('hg.admin')
411 411 def repo_as_fork(self, repo_name):
412 412 """
413 413 Mark given repository as a fork of another
414 414
415 415 :param repo_name:
416 416 """
417 417 try:
418 418 fork_id = request.POST.get('id_fork_of')
419 419 repo = ScmModel().mark_as_fork(repo_name, fork_id,
420 420 self.rhodecode_user.username)
421 421 fork = repo.fork.repo_name if repo.fork else _('Nothing')
422 422 Session().commit()
423 423 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
424 424 category='success')
425 425 except Exception, e:
426 426 log.error(traceback.format_exc())
427 427 h.flash(_('An error occurred during this operation'),
428 428 category='error')
429 429
430 430 return redirect(url('edit_repo', repo_name=repo_name))
431 431
432 432 @HasPermissionAllDecorator('hg.admin')
433 433 def show(self, repo_name, format='html'):
434 434 """GET /repos/repo_name: Show a specific item"""
435 435 # url('repo', repo_name=ID)
436 436
437 437 @HasPermissionAllDecorator('hg.admin')
438 438 def edit(self, repo_name, format='html'):
439 439 """GET /repos/repo_name/edit: Form to edit an existing item"""
440 440 # url('edit_repo', repo_name=ID)
441 441 defaults = self.__load_data(repo_name)
442 442
443 443 return htmlfill.render(
444 444 render('admin/repos/repo_edit.html'),
445 445 defaults=defaults,
446 446 encoding="UTF-8",
447 447 force_defaults=False
448 448 )
@@ -1,316 +1,316 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.repos_groups
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repositories groups controller for RhodeCode
7 7
8 8 :created_on: Mar 23, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29
30 30 from formencode import htmlfill
31 31
32 32 from pylons import request, tmpl_context as c, url
33 33 from pylons.controllers.util import redirect
34 34 from pylons.i18n.translation import _
35 35
36 36 from sqlalchemy.exc import IntegrityError
37 37
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
40 40 HasReposGroupPermissionAnyDecorator
41 41 from rhodecode.lib.base import BaseController, render
42 42 from rhodecode.model.db import RepoGroup
43 43 from rhodecode.model.repos_group import ReposGroupModel
44 44 from rhodecode.model.forms import ReposGroupForm
45 45 from rhodecode.model.meta import Session
46 46 from rhodecode.model.repo import RepoModel
47 47 from webob.exc import HTTPInternalServerError, HTTPNotFound
48 48
49 49 log = logging.getLogger(__name__)
50 50
51 51
52 52 class ReposGroupsController(BaseController):
53 53 """REST Controller styled on the Atom Publishing Protocol"""
54 54 # To properly map this controller, ensure your config/routing.py
55 55 # file has a resource setup:
56 56 # map.resource('repos_group', 'repos_groups')
57 57
58 58 @LoginRequired()
59 59 def __before__(self):
60 60 super(ReposGroupsController, self).__before__()
61 61
62 62 def __load_defaults(self):
63 63 c.repo_groups = RepoGroup.groups_choices()
64 64 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
65 65
66 66 repo_model = RepoModel()
67 67 c.users_array = repo_model.get_users_js()
68 68 c.users_groups_array = repo_model.get_users_groups_js()
69 69
70 70 def __load_data(self, group_id):
71 71 """
72 72 Load defaults settings for edit, and update
73 73
74 74 :param group_id:
75 75 """
76 76 self.__load_defaults()
77 77
78 78 repo_group = RepoGroup.get_or_404(group_id)
79 79
80 80 data = repo_group.get_dict()
81 81
82 82 data['group_name'] = repo_group.name
83 83
84 84 # fill repository users
85 85 for p in repo_group.repo_group_to_perm:
86 86 data.update({'u_perm_%s' % p.user.username:
87 87 p.permission.permission_name})
88 88
89 89 # fill repository groups
90 90 for p in repo_group.users_group_to_perm:
91 91 data.update({'g_perm_%s' % p.users_group.users_group_name:
92 92 p.permission.permission_name})
93 93
94 94 return data
95 95
96 96 @HasPermissionAnyDecorator('hg.admin')
97 97 def index(self, format='html'):
98 98 """GET /repos_groups: All items in the collection"""
99 99 # url('repos_groups')
100 100 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
101 101 c.groups = sorted(RepoGroup.query().all(), key=sk)
102 102 return render('admin/repos_groups/repos_groups_show.html')
103 103
104 104 @HasPermissionAnyDecorator('hg.admin')
105 105 def create(self):
106 106 """POST /repos_groups: Create a new item"""
107 107 # url('repos_groups')
108 108 self.__load_defaults()
109 109 repos_group_form = ReposGroupForm(available_groups =
110 110 c.repo_groups_choices)()
111 111 try:
112 112 form_result = repos_group_form.to_python(dict(request.POST))
113 113 ReposGroupModel().create(
114 114 group_name=form_result['group_name'],
115 115 group_description=form_result['group_description'],
116 116 parent=form_result['group_parent_id']
117 117 )
118 Session.commit()
118 Session().commit()
119 119 h.flash(_('created repos group %s') \
120 120 % form_result['group_name'], category='success')
121 121 #TODO: in futureaction_logger(, '', '', '', self.sa)
122 122 except formencode.Invalid, errors:
123 123
124 124 return htmlfill.render(
125 125 render('admin/repos_groups/repos_groups_add.html'),
126 126 defaults=errors.value,
127 127 errors=errors.error_dict or {},
128 128 prefix_error=False,
129 129 encoding="UTF-8")
130 130 except Exception:
131 131 log.error(traceback.format_exc())
132 132 h.flash(_('error occurred during creation of repos group %s') \
133 133 % request.POST.get('group_name'), category='error')
134 134
135 135 return redirect(url('repos_groups'))
136 136
137 137 @HasPermissionAnyDecorator('hg.admin')
138 138 def new(self, format='html'):
139 139 """GET /repos_groups/new: Form to create a new item"""
140 140 # url('new_repos_group')
141 141 self.__load_defaults()
142 142 return render('admin/repos_groups/repos_groups_add.html')
143 143
144 144 @HasPermissionAnyDecorator('hg.admin')
145 145 def update(self, id):
146 146 """PUT /repos_groups/id: Update an existing item"""
147 147 # Forms posted to this method should contain a hidden field:
148 148 # <input type="hidden" name="_method" value="PUT" />
149 149 # Or using helpers:
150 150 # h.form(url('repos_group', id=ID),
151 151 # method='put')
152 152 # url('repos_group', id=ID)
153 153
154 154 self.__load_defaults()
155 155 c.repos_group = RepoGroup.get(id)
156 156
157 157 repos_group_form = ReposGroupForm(
158 158 edit=True,
159 159 old_data=c.repos_group.get_dict(),
160 160 available_groups=c.repo_groups_choices
161 161 )()
162 162 try:
163 163 form_result = repos_group_form.to_python(dict(request.POST))
164 164 ReposGroupModel().update(id, form_result)
165 Session.commit()
165 Session().commit()
166 166 h.flash(_('updated repos group %s') \
167 167 % form_result['group_name'], category='success')
168 168 #TODO: in futureaction_logger(, '', '', '', self.sa)
169 169 except formencode.Invalid, errors:
170 170
171 171 return htmlfill.render(
172 172 render('admin/repos_groups/repos_groups_edit.html'),
173 173 defaults=errors.value,
174 174 errors=errors.error_dict or {},
175 175 prefix_error=False,
176 176 encoding="UTF-8")
177 177 except Exception:
178 178 log.error(traceback.format_exc())
179 179 h.flash(_('error occurred during update of repos group %s') \
180 180 % request.POST.get('group_name'), category='error')
181 181
182 182 return redirect(url('repos_groups'))
183 183
184 184 @HasPermissionAnyDecorator('hg.admin')
185 185 def delete(self, id):
186 186 """DELETE /repos_groups/id: Delete an existing item"""
187 187 # Forms posted to this method should contain a hidden field:
188 188 # <input type="hidden" name="_method" value="DELETE" />
189 189 # Or using helpers:
190 190 # h.form(url('repos_group', id=ID),
191 191 # method='delete')
192 192 # url('repos_group', id=ID)
193 193
194 194 gr = RepoGroup.get(id)
195 195 repos = gr.repositories.all()
196 196 if repos:
197 197 h.flash(_('This group contains %s repositores and cannot be '
198 198 'deleted') % len(repos),
199 199 category='error')
200 200 return redirect(url('repos_groups'))
201 201
202 202 try:
203 203 ReposGroupModel().delete(id)
204 Session.commit()
204 Session().commit()
205 205 h.flash(_('removed repos group %s') % gr.group_name, category='success')
206 206 #TODO: in future action_logger(, '', '', '', self.sa)
207 207 except IntegrityError, e:
208 208 if e.message.find('groups_group_parent_id_fkey') != -1:
209 209 log.error(traceback.format_exc())
210 210 h.flash(_('Cannot delete this group it still contains '
211 211 'subgroups'),
212 212 category='warning')
213 213 else:
214 214 log.error(traceback.format_exc())
215 215 h.flash(_('error occurred during deletion of repos '
216 216 'group %s') % gr.group_name, category='error')
217 217
218 218 except Exception:
219 219 log.error(traceback.format_exc())
220 220 h.flash(_('error occurred during deletion of repos '
221 221 'group %s') % gr.group_name, category='error')
222 222
223 223 return redirect(url('repos_groups'))
224 224
225 225 @HasReposGroupPermissionAnyDecorator('group.admin')
226 226 def delete_repos_group_user_perm(self, group_name):
227 227 """
228 228 DELETE an existing repositories group permission user
229 229
230 230 :param group_name:
231 231 """
232 232
233 233 try:
234 234 ReposGroupModel().revoke_user_permission(
235 235 repos_group=group_name, user=request.POST['user_id']
236 236 )
237 Session.commit()
237 Session().commit()
238 238 except Exception:
239 239 log.error(traceback.format_exc())
240 240 h.flash(_('An error occurred during deletion of group user'),
241 241 category='error')
242 242 raise HTTPInternalServerError()
243 243
244 244 @HasReposGroupPermissionAnyDecorator('group.admin')
245 245 def delete_repos_group_users_group_perm(self, group_name):
246 246 """
247 247 DELETE an existing repositories group permission users group
248 248
249 249 :param group_name:
250 250 """
251 251
252 252 try:
253 253 ReposGroupModel().revoke_users_group_permission(
254 254 repos_group=group_name,
255 255 group_name=request.POST['users_group_id']
256 256 )
257 Session.commit()
257 Session().commit()
258 258 except Exception:
259 259 log.error(traceback.format_exc())
260 260 h.flash(_('An error occurred during deletion of group'
261 261 ' users groups'),
262 262 category='error')
263 263 raise HTTPInternalServerError()
264 264
265 265 def show_by_name(self, group_name):
266 266 """
267 267 This is a proxy that does a lookup group_name -> id, and shows
268 268 the group by id view instead
269 269 """
270 270 group_name = group_name.rstrip('/')
271 271 id_ = RepoGroup.get_by_group_name(group_name)
272 272 if id_:
273 273 return self.show(id_.group_id)
274 274 raise HTTPNotFound
275 275
276 276 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
277 277 'group.admin')
278 278 def show(self, id, format='html'):
279 279 """GET /repos_groups/id: Show a specific item"""
280 280 # url('repos_group', id=ID)
281 281
282 282 c.group = RepoGroup.get_or_404(id)
283 283
284 284 c.group_repos = c.group.repositories.all()
285 285
286 286 #overwrite our cached list with current filter
287 287 gr_filter = c.group_repos
288 288 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
289 289
290 290 c.repos_list = c.cached_repo_list
291 291
292 292 c.repo_cnt = 0
293 293
294 c.groups = self.sa.query(RepoGroup).order_by(RepoGroup.group_name)\
294 c.groups = RepoGroup.query().order_by(RepoGroup.group_name)\
295 295 .filter(RepoGroup.group_parent_id == id).all()
296 296
297 297 return render('admin/repos_groups/repos_groups.html')
298 298
299 299 @HasPermissionAnyDecorator('hg.admin')
300 300 def edit(self, id, format='html'):
301 301 """GET /repos_groups/id/edit: Form to edit an existing item"""
302 302 # url('edit_repos_group', id=ID)
303 303
304 304 c.repos_group = ReposGroupModel()._get_repos_group(id)
305 305 defaults = self.__load_data(c.repos_group.group_id)
306 306
307 307 # we need to exclude this group from the group list for editing
308 308 c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id,
309 309 c.repo_groups)
310 310
311 311 return htmlfill.render(
312 312 render('admin/repos_groups/repos_groups_edit.html'),
313 313 defaults=defaults,
314 314 encoding="UTF-8",
315 315 force_defaults=False
316 316 )
@@ -1,447 +1,438 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.settings
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 settings controller for rhodecode admin
7 7
8 8 :created_on: Jul 14, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29 import pkg_resources
30 30 import platform
31 31
32 32 from sqlalchemy import func
33 33 from formencode import htmlfill
34 34 from pylons import request, session, tmpl_context as c, url, config
35 35 from pylons.controllers.util import abort, redirect
36 36 from pylons.i18n.translation import _
37 37
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 40 HasPermissionAnyDecorator, NotAnonymous
41 41 from rhodecode.lib.base import BaseController, render
42 42 from rhodecode.lib.celerylib import tasks, run_task
43 43 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
44 44 set_rhodecode_config, repo_name_slug
45 45 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
46 46 RhodeCodeSetting, PullRequest, PullRequestReviewers
47 47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
48 48 ApplicationUiSettingsForm
49 49 from rhodecode.model.scm import ScmModel
50 50 from rhodecode.model.user import UserModel
51 51 from rhodecode.model.db import User
52 52 from rhodecode.model.notification import EmailNotificationModel
53 53 from rhodecode.model.meta import Session
54 from pylons.decorators import jsonify
55 from rhodecode.model.pull_request import PullRequestModel
56 54
57 55 log = logging.getLogger(__name__)
58 56
59 57
60 58 class SettingsController(BaseController):
61 59 """REST Controller styled on the Atom Publishing Protocol"""
62 60 # To properly map this controller, ensure your config/routing.py
63 61 # file has a resource setup:
64 62 # map.resource('setting', 'settings', controller='admin/settings',
65 63 # path_prefix='/admin', name_prefix='admin_')
66 64
67 65 @LoginRequired()
68 66 def __before__(self):
69 67 c.admin_user = session.get('admin_user')
70 68 c.admin_username = session.get('admin_username')
71 69 c.modules = sorted([(p.project_name, p.version)
72 70 for p in pkg_resources.working_set],
73 71 key=lambda k: k[0].lower())
74 72 c.py_version = platform.python_version()
75 73 c.platform = platform.platform()
76 74 super(SettingsController, self).__before__()
77 75
78 76 @HasPermissionAllDecorator('hg.admin')
79 77 def index(self, format='html'):
80 78 """GET /admin/settings: All items in the collection"""
81 79 # url('admin_settings')
82 80
83 81 defaults = RhodeCodeSetting.get_app_settings()
84 82 defaults.update(self.get_hg_ui_settings())
85 83
86 84 return htmlfill.render(
87 85 render('admin/settings/settings.html'),
88 86 defaults=defaults,
89 87 encoding="UTF-8",
90 88 force_defaults=False
91 89 )
92 90
93 91 @HasPermissionAllDecorator('hg.admin')
94 92 def create(self):
95 93 """POST /admin/settings: Create a new item"""
96 94 # url('admin_settings')
97 95
98 96 @HasPermissionAllDecorator('hg.admin')
99 97 def new(self, format='html'):
100 98 """GET /admin/settings/new: Form to create a new item"""
101 99 # url('admin_new_setting')
102 100
103 101 @HasPermissionAllDecorator('hg.admin')
104 102 def update(self, setting_id):
105 103 """PUT /admin/settings/setting_id: Update an existing item"""
106 104 # Forms posted to this method should contain a hidden field:
107 105 # <input type="hidden" name="_method" value="PUT" />
108 106 # Or using helpers:
109 107 # h.form(url('admin_setting', setting_id=ID),
110 108 # method='put')
111 109 # url('admin_setting', setting_id=ID)
110
112 111 if setting_id == 'mapping':
113 112 rm_obsolete = request.POST.get('destroy', False)
114 113 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
115 114 initial = ScmModel().repo_scan()
116 115 log.debug('invalidating all repositories')
117 116 for repo_name in initial.keys():
118 117 invalidate_cache('get_repo_cached_%s' % repo_name)
119 118
120 119 added, removed = repo2db_mapper(initial, rm_obsolete)
121 120
122 121 h.flash(_('Repositories successfully'
123 122 ' rescanned added: %s,removed: %s') % (added, removed),
124 category='success')
123 category='success')
125 124
126 125 if setting_id == 'whoosh':
127 126 repo_location = self.get_hg_ui_settings()['paths_root_path']
128 127 full_index = request.POST.get('full_index', False)
129 128 run_task(tasks.whoosh_index, repo_location, full_index)
129 h.flash(_('Whoosh reindex task scheduled'), category='success')
130 130
131 h.flash(_('Whoosh reindex task scheduled'), category='success')
132 131 if setting_id == 'global':
133 132
134 133 application_form = ApplicationSettingsForm()()
135 134 try:
136 135 form_result = application_form.to_python(dict(request.POST))
137
138 try:
139 hgsettings1 = RhodeCodeSetting.get_by_name('title')
140 hgsettings1.app_settings_value = \
141 form_result['rhodecode_title']
136 except formencode.Invalid, errors:
137 return htmlfill.render(
138 render('admin/settings/settings.html'),
139 defaults=errors.value,
140 errors=errors.error_dict or {},
141 prefix_error=False,
142 encoding="UTF-8"
143 )
142 144
143 hgsettings2 = RhodeCodeSetting.get_by_name('realm')
144 hgsettings2.app_settings_value = \
145 form_result['rhodecode_realm']
145 try:
146 sett1 = RhodeCodeSetting.get_by_name('title')
147 sett1.app_settings_value = form_result['rhodecode_title']
148 Session().add(sett1)
146 149
147 hgsettings3 = RhodeCodeSetting.get_by_name('ga_code')
148 hgsettings3.app_settings_value = \
149 form_result['rhodecode_ga_code']
150 sett2 = RhodeCodeSetting.get_by_name('realm')
151 sett2.app_settings_value = form_result['rhodecode_realm']
152 Session().add(sett2)
150 153
151 self.sa.add(hgsettings1)
152 self.sa.add(hgsettings2)
153 self.sa.add(hgsettings3)
154 self.sa.commit()
155 set_rhodecode_config(config)
156 h.flash(_('Updated application settings'),
157 category='success')
154 sett3 = RhodeCodeSetting.get_by_name('ga_code')
155 sett3.app_settings_value = form_result['rhodecode_ga_code']
156 Session().add(sett3)
157
158 Session().commit()
159 set_rhodecode_config(config)
160 h.flash(_('Updated application settings'), category='success')
158 161
159 except Exception:
160 log.error(traceback.format_exc())
161 h.flash(_('error occurred during updating '
162 'application settings'),
163 category='error')
162 except Exception:
163 log.error(traceback.format_exc())
164 h.flash(_('error occurred during updating '
165 'application settings'),
166 category='error')
164 167
165 self.sa.rollback()
166
168 if setting_id == 'vcs':
169 application_form = ApplicationUiSettingsForm()()
170 try:
171 form_result = application_form.to_python(dict(request.POST))
167 172 except formencode.Invalid, errors:
168 173 return htmlfill.render(
169 174 render('admin/settings/settings.html'),
170 175 defaults=errors.value,
171 176 errors=errors.error_dict or {},
172 177 prefix_error=False,
173 encoding="UTF-8")
178 encoding="UTF-8"
179 )
174 180
175 if setting_id == 'mercurial':
176 application_form = ApplicationUiSettingsForm()()
177 181 try:
178 form_result = application_form.to_python(dict(request.POST))
179 182 # fix namespaces for hooks
180 183 _f = lambda s: s.replace('.', '_')
181 try:
182 184
183 hgsettings1 = self.sa.query(RhodeCodeUi)\
184 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
185 hgsettings1.ui_value = form_result['web_push_ssl']
185 sett1 = RhodeCodeUi.query()\
186 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
187 sett1.ui_value = form_result['web_push_ssl']
186 188
187 hgsettings2 = self.sa.query(RhodeCodeUi)\
188 .filter(RhodeCodeUi.ui_key == '/').one()
189 hgsettings2.ui_value = form_result['paths_root_path']
189 sett2 = RhodeCodeUi.query()\
190 .filter(RhodeCodeUi.ui_key == '/').one()
191 sett2.ui_value = form_result['paths_root_path']
190 192
191 #HOOKS
192 hgsettings3 = self.sa.query(RhodeCodeUi)\
193 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_UPDATE)\
194 .one()
195 hgsettings3.ui_active = bool(form_result[_f('hooks_%s' %
196 RhodeCodeUi.HOOK_UPDATE)])
193 #HOOKS
194 sett3 = RhodeCodeUi.query()\
195 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_UPDATE)\
196 .one()
197 sett3.ui_active = bool(form_result[_f('hooks_%s' %
198 RhodeCodeUi.HOOK_UPDATE)])
197 199
198 hgsettings4 = self.sa.query(RhodeCodeUi)\
199 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_REPO_SIZE)\
200 .one()
201 hgsettings4.ui_active = bool(form_result[_f('hooks_%s' %
202 RhodeCodeUi.HOOK_REPO_SIZE)])
203
204 hgsettings5 = self.sa.query(RhodeCodeUi)\
205 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_PUSH)\
206 .one()
207 hgsettings5.ui_active = bool(form_result[_f('hooks_%s' %
208 RhodeCodeUi.HOOK_PUSH)])
200 sett4 = RhodeCodeUi.query()\
201 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_REPO_SIZE)\
202 .one()
203 sett4.ui_active = bool(form_result[_f('hooks_%s' %
204 RhodeCodeUi.HOOK_REPO_SIZE)])
209 205
210 hgsettings6 = self.sa.query(RhodeCodeUi)\
211 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_PULL)\
212 .one()
213 hgsettings6.ui_active = bool(form_result[_f('hooks_%s' %
214 RhodeCodeUi.HOOK_PULL)])
206 sett5 = RhodeCodeUi.query()\
207 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_PUSH)\
208 .one()
209 sett5.ui_active = bool(form_result[_f('hooks_%s' %
210 RhodeCodeUi.HOOK_PUSH)])
215 211
216 self.sa.add(hgsettings1)
217 self.sa.add(hgsettings2)
218 self.sa.add(hgsettings3)
219 self.sa.add(hgsettings4)
220 self.sa.add(hgsettings5)
221 self.sa.add(hgsettings6)
222 self.sa.commit()
212 sett6 = RhodeCodeUi.query()\
213 .filter(RhodeCodeUi.ui_key == RhodeCodeUi.HOOK_PULL)\
214 .one()
215 sett6.ui_active = bool(form_result[_f('hooks_%s' %
216 RhodeCodeUi.HOOK_PULL)])
223 217
224 h.flash(_('Updated mercurial settings'),
225 category='success')
226
227 except:
228 log.error(traceback.format_exc())
229 h.flash(_('error occurred during updating '
230 'application settings'), category='error')
218 Session().add(sett1)
219 Session().add(sett2)
220 Session().add(sett3)
221 Session().add(sett4)
222 Session().add(sett5)
223 Session().add(sett6)
224 Session().commit()
231 225
232 self.sa.rollback()
226 h.flash(_('Updated mercurial settings'), category='success')
233 227
234 except formencode.Invalid, errors:
235 return htmlfill.render(
236 render('admin/settings/settings.html'),
237 defaults=errors.value,
238 errors=errors.error_dict or {},
239 prefix_error=False,
240 encoding="UTF-8")
228 except Exception:
229 log.error(traceback.format_exc())
230 h.flash(_('error occurred during updating '
231 'application settings'), category='error')
241 232
242 233 if setting_id == 'hooks':
243 234 ui_key = request.POST.get('new_hook_ui_key')
244 235 ui_value = request.POST.get('new_hook_ui_value')
245 236 try:
246 237
247 238 if ui_value and ui_key:
248 239 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
249 240 h.flash(_('Added new hook'),
250 241 category='success')
251 242
252 243 # check for edits
253 244 update = False
254 245 _d = request.POST.dict_of_lists()
255 246 for k, v in zip(_d.get('hook_ui_key', []),
256 247 _d.get('hook_ui_value_new', [])):
257 248 RhodeCodeUi.create_or_update_hook(k, v)
258 249 update = True
259 250
260 251 if update:
261 252 h.flash(_('Updated hooks'), category='success')
262 self.sa.commit()
263 except:
253 Session().commit()
254 except Exception:
264 255 log.error(traceback.format_exc())
265 256 h.flash(_('error occurred during hook creation'),
266 257 category='error')
267 258
268 259 return redirect(url('admin_edit_setting', setting_id='hooks'))
269 260
270 261 if setting_id == 'email':
271 262 test_email = request.POST.get('test_email')
272 263 test_email_subj = 'RhodeCode TestEmail'
273 264 test_email_body = 'RhodeCode Email test'
274 265
275 266 test_email_html_body = EmailNotificationModel()\
276 267 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
277 268 body=test_email_body)
278 269
279 270 recipients = [test_email] if [test_email] else None
280 271
281 272 run_task(tasks.send_email, recipients, test_email_subj,
282 273 test_email_body, test_email_html_body)
283 274
284 275 h.flash(_('Email task created'), category='success')
285 276 return redirect(url('admin_settings'))
286 277
287 278 @HasPermissionAllDecorator('hg.admin')
288 279 def delete(self, setting_id):
289 280 """DELETE /admin/settings/setting_id: Delete an existing item"""
290 281 # Forms posted to this method should contain a hidden field:
291 282 # <input type="hidden" name="_method" value="DELETE" />
292 283 # Or using helpers:
293 284 # h.form(url('admin_setting', setting_id=ID),
294 285 # method='delete')
295 286 # url('admin_setting', setting_id=ID)
296 287 if setting_id == 'hooks':
297 288 hook_id = request.POST.get('hook_id')
298 289 RhodeCodeUi.delete(hook_id)
299 self.sa.commit()
290 Session().commit()
300 291
301 292 @HasPermissionAllDecorator('hg.admin')
302 293 def show(self, setting_id, format='html'):
303 294 """
304 295 GET /admin/settings/setting_id: Show a specific item"""
305 296 # url('admin_setting', setting_id=ID)
306 297
307 298 @HasPermissionAllDecorator('hg.admin')
308 299 def edit(self, setting_id, format='html'):
309 300 """
310 301 GET /admin/settings/setting_id/edit: Form to
311 302 edit an existing item"""
312 303 # url('admin_edit_setting', setting_id=ID)
313 304
314 305 c.hooks = RhodeCodeUi.get_builtin_hooks()
315 306 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
316 307
317 308 return htmlfill.render(
318 309 render('admin/settings/hooks.html'),
319 310 defaults={},
320 311 encoding="UTF-8",
321 312 force_defaults=False
322 313 )
323 314
324 315 @NotAnonymous()
325 316 def my_account(self):
326 317 """
327 318 GET /_admin/my_account Displays info about my account
328 319 """
329 320 # url('admin_settings_my_account')
330 321
331 322 c.user = User.get(self.rhodecode_user.user_id)
332 all_repos = self.sa.query(Repository)\
323 all_repos = Session().query(Repository)\
333 324 .filter(Repository.user_id == c.user.user_id)\
334 325 .order_by(func.lower(Repository.repo_name)).all()
335 326
336 327 c.user_repos = ScmModel().get_repos(all_repos)
337 328
338 329 if c.user.username == 'default':
339 330 h.flash(_("You can't edit this user since it's"
340 331 " crucial for entire application"), category='warning')
341 332 return redirect(url('users'))
342 333
343 334 defaults = c.user.get_dict()
344 335
345 336 c.form = htmlfill.render(
346 337 render('admin/users/user_edit_my_account_form.html'),
347 338 defaults=defaults,
348 339 encoding="UTF-8",
349 340 force_defaults=False
350 341 )
351 342 return render('admin/users/user_edit_my_account.html')
352 343
353 344 @NotAnonymous()
354 345 def my_account_update(self):
355 346 """PUT /_admin/my_account_update: Update an existing item"""
356 347 # Forms posted to this method should contain a hidden field:
357 348 # <input type="hidden" name="_method" value="PUT" />
358 349 # Or using helpers:
359 350 # h.form(url('admin_settings_my_account_update'),
360 351 # method='put')
361 352 # url('admin_settings_my_account_update', id=ID)
362 353 uid = self.rhodecode_user.user_id
363 354 email = self.rhodecode_user.email
364 355 _form = UserForm(edit=True,
365 356 old_data={'user_id': uid, 'email': email})()
366 357 form_result = {}
367 358 try:
368 359 form_result = _form.to_python(dict(request.POST))
369 360 UserModel().update_my_account(uid, form_result)
370 361 h.flash(_('Your account was updated successfully'),
371 362 category='success')
372 Session.commit()
363 Session().commit()
373 364 except formencode.Invalid, errors:
374 365 c.user = User.get(self.rhodecode_user.user_id)
375 366
376 367 c.form = htmlfill.render(
377 368 render('admin/users/user_edit_my_account_form.html'),
378 369 defaults=errors.value,
379 370 errors=errors.error_dict or {},
380 371 prefix_error=False,
381 372 encoding="UTF-8")
382 373 return render('admin/users/user_edit_my_account.html')
383 374 except Exception:
384 375 log.error(traceback.format_exc())
385 376 h.flash(_('error occurred during update of user %s') \
386 377 % form_result.get('username'), category='error')
387 378
388 379 return redirect(url('my_account'))
389
380
390 381 @NotAnonymous()
391 382 def my_account_my_repos(self):
392 all_repos = self.sa.query(Repository)\
383 all_repos = Session().query(Repository)\
393 384 .filter(Repository.user_id == self.rhodecode_user.user_id)\
394 385 .order_by(func.lower(Repository.repo_name))\
395 386 .all()
396 387 c.user_repos = ScmModel().get_repos(all_repos)
397 388 return render('admin/users/user_edit_my_account_repos.html')
398 389
399 390 @NotAnonymous()
400 391 def my_account_my_pullrequests(self):
401 392 c.my_pull_requests = PullRequest.query()\
402 393 .filter(PullRequest.user_id==
403 394 self.rhodecode_user.user_id)\
404 395 .all()
405 396 c.participate_in_pull_requests = \
406 397 [x.pull_request for x in PullRequestReviewers.query()\
407 398 .filter(PullRequestReviewers.user_id==
408 399 self.rhodecode_user.user_id)\
409 400 .all()]
410 401 return render('admin/users/user_edit_my_account_pullrequests.html')
411 402
412 403 @NotAnonymous()
413 404 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
414 405 def create_repository(self):
415 406 """GET /_admin/create_repository: Form to create a new item"""
416 407
417 408 c.repo_groups = RepoGroup.groups_choices()
418 409 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
419 410 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
420 411
421 412 new_repo = request.GET.get('repo', '')
422 413 c.new_repo = repo_name_slug(new_repo)
423 414
424 415 return render('admin/repos/repo_add_create_repository.html')
425 416
426 417 @NotAnonymous()
427 418 def get_hg_ui_settings(self):
428 ret = self.sa.query(RhodeCodeUi).all()
419 ret = RhodeCodeUi.query().all()
429 420
430 421 if not ret:
431 422 raise Exception('Could not get application ui settings !')
432 423 settings = {}
433 424 for each in ret:
434 425 k = each.ui_key
435 426 v = each.ui_value
436 427 if k == '/':
437 428 k = 'root_path'
438 429
439 430 if k.find('.') != -1:
440 431 k = k.replace('.', '_')
441 432
442 433 if each.ui_section == 'hooks':
443 434 v = each.ui_active
444 435
445 436 settings[each.ui_section + '_' + k] = v
446 437
447 438 return settings
@@ -1,295 +1,295 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.users
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Users crud controller for pylons
7 7
8 8 :created_on: Apr 4, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29 from pylons import response
30 30
31 31 from formencode import htmlfill
32 32 from pylons import request, session, tmpl_context as c, url, config
33 33 from pylons.controllers.util import redirect
34 34 from pylons.i18n.translation import _
35 35
36 36 from rhodecode.lib.exceptions import DefaultUserException, \
37 37 UserOwnsReposException
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 40 AuthUser
41 41 from rhodecode.lib.base import BaseController, render
42 42
43 43 from rhodecode.model.db import User, Permission, UserEmailMap
44 44 from rhodecode.model.forms import UserForm
45 45 from rhodecode.model.user import UserModel
46 46 from rhodecode.model.meta import Session
47 47 from rhodecode.lib.utils import action_logger
48 48 from rhodecode.lib.compat import json
49 49
50 50 log = logging.getLogger(__name__)
51 51
52 52
53 53 class UsersController(BaseController):
54 54 """REST Controller styled on the Atom Publishing Protocol"""
55 55 # To properly map this controller, ensure your config/routing.py
56 56 # file has a resource setup:
57 57 # map.resource('user', 'users')
58 58
59 59 @LoginRequired()
60 60 @HasPermissionAllDecorator('hg.admin')
61 61 def __before__(self):
62 62 c.admin_user = session.get('admin_user')
63 63 c.admin_username = session.get('admin_username')
64 64 super(UsersController, self).__before__()
65 65 c.available_permissions = config['available_permissions']
66 66
67 67 def index(self, format='html'):
68 68 """GET /users: All items in the collection"""
69 69 # url('users')
70 70
71 71 c.users_list = User.query().order_by(User.username).all()
72 72
73 73 users_data = []
74 74 total_records = len(c.users_list)
75 75 grav_tmpl = """<div class="gravatar"><img alt="gravatar" src="%s"/> </div>"""
76 76 usr_tmpl = """<a href="%s">%s</a>""" % (h.url('edit_user', id='__ID__'), '%s')
77 77 usr_tmpl = usr_tmpl.replace('__ID__', '%s')
78 78 edit_tmpl = '''
79 79 <form action="/_admin/users/%s" method="post">
80 80 <div style="display:none">
81 81 <input name="_method" type="hidden" value="%s">
82 82 </div>
83 83 <input class="delete_icon action_button" id="remove_user_%s"
84 84 name="remove_" onclick="return confirm('%s');"
85 85 type="submit" value="delete">
86 86 </form>
87 87 '''
88 88 for user in c.users_list:
89 89 users_data.append({
90 90 "gravatar": grav_tmpl % h.gravatar_url(user.email, 24),
91 91 "raw_username": user.username,
92 92 "username": usr_tmpl % (user.user_id, user.username),
93 93 "firstname": user.name,
94 94 "lastname": user.lastname,
95 95 "last_login": h.fmt_date(user.last_login),
96 96 "active": h.bool2icon(user.active),
97 97 "admin": h.bool2icon(user.admin),
98 98 "ldap": h.bool2icon(bool(user.ldap_dn)),
99 99 "action": edit_tmpl % (user.user_id, _('delete'),
100 100 user.user_id,
101 101 _('Confirm to delete this user: %s') % user.username
102 102 ),
103 103 })
104 104
105 105 c.data = json.dumps({
106 106 "totalRecords": total_records,
107 107 "startIndex": 0,
108 108 "sort": None,
109 109 "dir": "asc",
110 110 "records": users_data
111 111 })
112 112
113 113 return render('admin/users/users.html')
114 114
115 115 def create(self):
116 116 """POST /users: Create a new item"""
117 117 # url('users')
118 118
119 119 user_model = UserModel()
120 120 user_form = UserForm()()
121 121 try:
122 122 form_result = user_form.to_python(dict(request.POST))
123 123 user_model.create(form_result)
124 124 usr = form_result['username']
125 125 action_logger(self.rhodecode_user, 'admin_created_user:%s' % usr,
126 126 None, self.ip_addr, self.sa)
127 127 h.flash(_('created user %s') % usr,
128 128 category='success')
129 Session.commit()
129 Session().commit()
130 130 except formencode.Invalid, errors:
131 131 return htmlfill.render(
132 132 render('admin/users/user_add.html'),
133 133 defaults=errors.value,
134 134 errors=errors.error_dict or {},
135 135 prefix_error=False,
136 136 encoding="UTF-8")
137 137 except Exception:
138 138 log.error(traceback.format_exc())
139 139 h.flash(_('error occurred during creation of user %s') \
140 140 % request.POST.get('username'), category='error')
141 141 return redirect(url('users'))
142 142
143 143 def new(self, format='html'):
144 144 """GET /users/new: Form to create a new item"""
145 145 # url('new_user')
146 146 return render('admin/users/user_add.html')
147 147
148 148 def update(self, id):
149 149 """PUT /users/id: Update an existing item"""
150 150 # Forms posted to this method should contain a hidden field:
151 151 # <input type="hidden" name="_method" value="PUT" />
152 152 # Or using helpers:
153 153 # h.form(url('update_user', id=ID),
154 154 # method='put')
155 155 # url('user', id=ID)
156 156 user_model = UserModel()
157 157 c.user = user_model.get(id)
158 158 c.perm_user = AuthUser(user_id=id)
159 159 _form = UserForm(edit=True, old_data={'user_id': id,
160 160 'email': c.user.email})()
161 161 form_result = {}
162 162 try:
163 163 form_result = _form.to_python(dict(request.POST))
164 164 user_model.update(id, form_result)
165 165 usr = form_result['username']
166 166 action_logger(self.rhodecode_user, 'admin_updated_user:%s' % usr,
167 167 None, self.ip_addr, self.sa)
168 168 h.flash(_('User updated successfully'), category='success')
169 Session.commit()
169 Session().commit()
170 170 except formencode.Invalid, errors:
171 171 c.user_email_map = UserEmailMap.query()\
172 172 .filter(UserEmailMap.user == c.user).all()
173 173 defaults = errors.value
174 174 e = errors.error_dict or {}
175 175 perm = Permission.get_by_key('hg.create.repository')
176 176 defaults.update({'create_repo_perm': user_model.has_perm(id, perm)})
177 177 defaults.update({'_method': 'put'})
178 178 return htmlfill.render(
179 179 render('admin/users/user_edit.html'),
180 180 defaults=defaults,
181 181 errors=e,
182 182 prefix_error=False,
183 183 encoding="UTF-8")
184 184 except Exception:
185 185 log.error(traceback.format_exc())
186 186 h.flash(_('error occurred during update of user %s') \
187 187 % form_result.get('username'), category='error')
188 188 return redirect(url('users'))
189 189
190 190 def delete(self, id):
191 191 """DELETE /users/id: Delete an existing item"""
192 192 # Forms posted to this method should contain a hidden field:
193 193 # <input type="hidden" name="_method" value="DELETE" />
194 194 # Or using helpers:
195 195 # h.form(url('delete_user', id=ID),
196 196 # method='delete')
197 197 # url('user', id=ID)
198 198 user_model = UserModel()
199 199 try:
200 200 user_model.delete(id)
201 Session.commit()
201 Session().commit()
202 202 h.flash(_('successfully deleted user'), category='success')
203 203 except (UserOwnsReposException, DefaultUserException), e:
204 204 h.flash(e, category='warning')
205 205 except Exception:
206 206 log.error(traceback.format_exc())
207 207 h.flash(_('An error occurred during deletion of user'),
208 208 category='error')
209 209 return redirect(url('users'))
210 210
211 211 def show(self, id, format='html'):
212 212 """GET /users/id: Show a specific item"""
213 213 # url('user', id=ID)
214 214
215 215 def edit(self, id, format='html'):
216 216 """GET /users/id/edit: Form to edit an existing item"""
217 217 # url('edit_user', id=ID)
218 218 c.user = User.get_or_404(id)
219 219
220 220 if c.user.username == 'default':
221 221 h.flash(_("You can't edit this user"), category='warning')
222 222 return redirect(url('users'))
223 223 c.perm_user = AuthUser(user_id=id)
224 224 c.user.permissions = {}
225 225 c.granted_permissions = UserModel().fill_perms(c.user)\
226 226 .permissions['global']
227 227 c.user_email_map = UserEmailMap.query()\
228 228 .filter(UserEmailMap.user == c.user).all()
229 229 defaults = c.user.get_dict()
230 230 perm = Permission.get_by_key('hg.create.repository')
231 231 defaults.update({'create_repo_perm': UserModel().has_perm(id, perm)})
232 232
233 233 return htmlfill.render(
234 234 render('admin/users/user_edit.html'),
235 235 defaults=defaults,
236 236 encoding="UTF-8",
237 237 force_defaults=False
238 238 )
239 239
240 240 def update_perm(self, id):
241 241 """PUT /users_perm/id: Update an existing item"""
242 242 # url('user_perm', id=ID, method='put')
243 243
244 244 grant_perm = request.POST.get('create_repo_perm', False)
245 245 user_model = UserModel()
246 246
247 247 if grant_perm:
248 248 perm = Permission.get_by_key('hg.create.none')
249 249 user_model.revoke_perm(id, perm)
250 250
251 251 perm = Permission.get_by_key('hg.create.repository')
252 252 user_model.grant_perm(id, perm)
253 253 h.flash(_("Granted 'repository create' permission to user"),
254 254 category='success')
255 Session.commit()
255 Session().commit()
256 256 else:
257 257 perm = Permission.get_by_key('hg.create.repository')
258 258 user_model.revoke_perm(id, perm)
259 259
260 260 perm = Permission.get_by_key('hg.create.none')
261 261 user_model.grant_perm(id, perm)
262 262 h.flash(_("Revoked 'repository create' permission to user"),
263 263 category='success')
264 Session.commit()
264 Session().commit()
265 265 return redirect(url('edit_user', id=id))
266 266
267 267 def add_email(self, id):
268 268 """POST /user_emails:Add an existing item"""
269 269 # url('user_emails', id=ID, method='put')
270 270
271 271 #TODO: validation and form !!!
272 272 email = request.POST.get('new_email')
273 273 user_model = UserModel()
274 274
275 275 try:
276 276 user_model.add_extra_email(id, email)
277 Session.commit()
277 Session().commit()
278 278 h.flash(_("Added email %s to user") % email, category='success')
279 279 except formencode.Invalid, error:
280 280 msg = error.error_dict['email']
281 281 h.flash(msg, category='error')
282 282 except Exception:
283 283 log.error(traceback.format_exc())
284 284 h.flash(_('An error occurred during email saving'),
285 285 category='error')
286 286 return redirect(url('edit_user', id=id))
287 287
288 288 def delete_email(self, id):
289 289 """DELETE /user_emails_delete/id: Delete an existing item"""
290 290 # url('user_emails_delete', id=ID, method='delete')
291 291 user_model = UserModel()
292 292 user_model.delete_extra_email(id, request.POST.get('del_email'))
293 Session.commit()
293 Session().commit()
294 294 h.flash(_("Removed email from user"), category='success')
295 295 return redirect(url('edit_user', id=id))
@@ -1,232 +1,232 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) 2010-2012 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 modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29
30 30 from formencode import htmlfill
31 31 from pylons import request, session, tmpl_context as c, url, config
32 32 from pylons.controllers.util import abort, redirect
33 33 from pylons.i18n.translation import _
34 34
35 35 from rhodecode.lib import helpers as h
36 36 from rhodecode.lib.exceptions import UsersGroupsAssignedException
37 37 from rhodecode.lib.utils2 import safe_unicode
38 38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
39 39 from rhodecode.lib.base import BaseController, render
40 40
41 41 from rhodecode.model.users_group import UsersGroupModel
42 42
43 43 from rhodecode.model.db import User, UsersGroup, Permission, UsersGroupToPerm
44 44 from rhodecode.model.forms import UsersGroupForm
45 45 from rhodecode.model.meta import Session
46 46 from rhodecode.lib.utils import action_logger
47 47
48 48 log = logging.getLogger(__name__)
49 49
50 50
51 51 class UsersGroupsController(BaseController):
52 52 """REST Controller styled on the Atom Publishing Protocol"""
53 53 # To properly map this controller, ensure your config/routing.py
54 54 # file has a resource setup:
55 55 # map.resource('users_group', 'users_groups')
56 56
57 57 @LoginRequired()
58 58 @HasPermissionAllDecorator('hg.admin')
59 59 def __before__(self):
60 60 c.admin_user = session.get('admin_user')
61 61 c.admin_username = session.get('admin_username')
62 62 super(UsersGroupsController, self).__before__()
63 63 c.available_permissions = config['available_permissions']
64 64
65 65 def index(self, format='html'):
66 66 """GET /users_groups: All items in the collection"""
67 67 # url('users_groups')
68 c.users_groups_list = self.sa.query(UsersGroup).all()
68 c.users_groups_list = UsersGroup().query().all()
69 69 return render('admin/users_groups/users_groups.html')
70 70
71 71 def create(self):
72 72 """POST /users_groups: Create a new item"""
73 73 # url('users_groups')
74 74
75 75 users_group_form = UsersGroupForm()()
76 76 try:
77 77 form_result = users_group_form.to_python(dict(request.POST))
78 78 UsersGroupModel().create(name=form_result['users_group_name'],
79 79 active=form_result['users_group_active'])
80 80 gr = form_result['users_group_name']
81 81 action_logger(self.rhodecode_user,
82 82 'admin_created_users_group:%s' % gr,
83 83 None, self.ip_addr, self.sa)
84 84 h.flash(_('created users group %s') % gr, category='success')
85 Session.commit()
85 Session().commit()
86 86 except formencode.Invalid, errors:
87 87 return htmlfill.render(
88 88 render('admin/users_groups/users_group_add.html'),
89 89 defaults=errors.value,
90 90 errors=errors.error_dict or {},
91 91 prefix_error=False,
92 92 encoding="UTF-8")
93 93 except Exception:
94 94 log.error(traceback.format_exc())
95 95 h.flash(_('error occurred during creation of users group %s') \
96 96 % request.POST.get('users_group_name'), category='error')
97 97
98 98 return redirect(url('users_groups'))
99 99
100 100 def new(self, format='html'):
101 101 """GET /users_groups/new: Form to create a new item"""
102 102 # url('new_users_group')
103 103 return render('admin/users_groups/users_group_add.html')
104 104
105 105 def update(self, id):
106 106 """PUT /users_groups/id: Update an existing item"""
107 107 # Forms posted to this method should contain a hidden field:
108 108 # <input type="hidden" name="_method" value="PUT" />
109 109 # Or using helpers:
110 110 # h.form(url('users_group', id=ID),
111 111 # method='put')
112 112 # url('users_group', id=ID)
113 113
114 114 c.users_group = UsersGroup.get(id)
115 115 c.group_members_obj = [x.user for x in c.users_group.members]
116 116 c.group_members = [(x.user_id, x.username) for x in
117 117 c.group_members_obj]
118 118
119 119 c.available_members = [(x.user_id, x.username) for x in
120 self.sa.query(User).all()]
120 User.query().all()]
121 121
122 122 available_members = [safe_unicode(x[0]) for x in c.available_members]
123 123
124 124 users_group_form = UsersGroupForm(edit=True,
125 125 old_data=c.users_group.get_dict(),
126 126 available_members=available_members)()
127 127
128 128 try:
129 129 form_result = users_group_form.to_python(request.POST)
130 130 UsersGroupModel().update(c.users_group, form_result)
131 131 gr = form_result['users_group_name']
132 132 action_logger(self.rhodecode_user,
133 133 'admin_updated_users_group:%s' % gr,
134 134 None, self.ip_addr, self.sa)
135 135 h.flash(_('updated users group %s') % gr, category='success')
136 Session.commit()
136 Session().commit()
137 137 except formencode.Invalid, errors:
138 138 e = errors.error_dict or {}
139 139
140 140 perm = Permission.get_by_key('hg.create.repository')
141 141 e.update({'create_repo_perm':
142 142 UsersGroupModel().has_perm(id, perm)})
143 143
144 144 return htmlfill.render(
145 145 render('admin/users_groups/users_group_edit.html'),
146 146 defaults=errors.value,
147 147 errors=e,
148 148 prefix_error=False,
149 149 encoding="UTF-8")
150 150 except Exception:
151 151 log.error(traceback.format_exc())
152 152 h.flash(_('error occurred during update of users group %s') \
153 153 % request.POST.get('users_group_name'), category='error')
154 154
155 155 return redirect(url('users_groups'))
156 156
157 157 def delete(self, id):
158 158 """DELETE /users_groups/id: Delete an existing item"""
159 159 # Forms posted to this method should contain a hidden field:
160 160 # <input type="hidden" name="_method" value="DELETE" />
161 161 # Or using helpers:
162 162 # h.form(url('users_group', id=ID),
163 163 # method='delete')
164 164 # url('users_group', id=ID)
165 165
166 166 try:
167 167 UsersGroupModel().delete(id)
168 Session.commit()
168 Session().commit()
169 169 h.flash(_('successfully deleted users group'), category='success')
170 170 except UsersGroupsAssignedException, e:
171 171 h.flash(e, category='error')
172 172 except Exception:
173 173 log.error(traceback.format_exc())
174 174 h.flash(_('An error occurred during deletion of users group'),
175 175 category='error')
176 176 return redirect(url('users_groups'))
177 177
178 178 def show(self, id, format='html'):
179 179 """GET /users_groups/id: Show a specific item"""
180 180 # url('users_group', id=ID)
181 181
182 182 def edit(self, id, format='html'):
183 183 """GET /users_groups/id/edit: Form to edit an existing item"""
184 184 # url('edit_users_group', id=ID)
185 185
186 c.users_group = self.sa.query(UsersGroup).get(id)
186 c.users_group = UsersGroup.get(id)
187 187 if not c.users_group:
188 188 return redirect(url('users_groups'))
189 189
190 190 c.users_group.permissions = {}
191 191 c.group_members_obj = [x.user for x in c.users_group.members]
192 192 c.group_members = [(x.user_id, x.username) for x in
193 193 c.group_members_obj]
194 194 c.available_members = [(x.user_id, x.username) for x in
195 self.sa.query(User).all()]
195 User.query().all()]
196 196 defaults = c.users_group.get_dict()
197 197 perm = Permission.get_by_key('hg.create.repository')
198 198 defaults.update({'create_repo_perm':
199 199 UsersGroupModel().has_perm(c.users_group, perm)})
200 200 return htmlfill.render(
201 201 render('admin/users_groups/users_group_edit.html'),
202 202 defaults=defaults,
203 203 encoding="UTF-8",
204 204 force_defaults=False
205 205 )
206 206
207 207 def update_perm(self, id):
208 208 """PUT /users_perm/id: Update an existing item"""
209 209 # url('users_group_perm', id=ID, method='put')
210 210
211 211 grant_perm = request.POST.get('create_repo_perm', False)
212 212
213 213 if grant_perm:
214 214 perm = Permission.get_by_key('hg.create.none')
215 215 UsersGroupModel().revoke_perm(id, perm)
216 216
217 217 perm = Permission.get_by_key('hg.create.repository')
218 218 UsersGroupModel().grant_perm(id, perm)
219 219 h.flash(_("Granted 'repository create' permission to user"),
220 220 category='success')
221 221
222 Session.commit()
222 Session().commit()
223 223 else:
224 224 perm = Permission.get_by_key('hg.create.repository')
225 225 UsersGroupModel().revoke_perm(id, perm)
226 226
227 227 perm = Permission.get_by_key('hg.create.none')
228 228 UsersGroupModel().grant_perm(id, perm)
229 229 h.flash(_("Revoked 'repository create' permission to user"),
230 230 category='success')
231 Session.commit()
231 Session().commit()
232 232 return redirect(url('edit_users_group', id=id))
@@ -1,516 +1,523 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.db_manage
4 4 ~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Database creation, and setup module for RhodeCode. Used for creation
7 7 of database as well as for migration operations
8 8
9 9 :created_on: Apr 10, 2010
10 10 :author: marcink
11 11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software: you can redistribute it and/or modify
15 15 # it under the terms of the GNU General Public License as published by
16 16 # the Free Software Foundation, either version 3 of the License, or
17 17 # (at your option) any later version.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 26
27 27 import os
28 28 import sys
29 29 import uuid
30 30 import logging
31 31 from os.path import dirname as dn, join as jn
32 32
33 33 from rhodecode import __dbversion__
34 34 from rhodecode.model import meta
35 35
36 36 from rhodecode.model.user import UserModel
37 37 from rhodecode.lib.utils import ask_ok
38 38 from rhodecode.model import init_model
39 39 from rhodecode.model.db import User, Permission, RhodeCodeUi, \
40 40 RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup,\
41 41 UserRepoGroupToPerm
42 42
43 43 from sqlalchemy.engine import create_engine
44 44 from rhodecode.model.repos_group import ReposGroupModel
45 45
46 46 log = logging.getLogger(__name__)
47 47
48 48
49 49 class DbManage(object):
50 50 def __init__(self, log_sql, dbconf, root, tests=False):
51 51 self.dbname = dbconf.split('/')[-1]
52 52 self.tests = tests
53 53 self.root = root
54 54 self.dburi = dbconf
55 55 self.log_sql = log_sql
56 56 self.db_exists = False
57 57 self.init_db()
58 58
59 59 def init_db(self):
60 60 engine = create_engine(self.dburi, echo=self.log_sql)
61 61 init_model(engine)
62 self.sa = meta.Session
62 self.sa = meta.Session()
63 63
64 64 def create_tables(self, override=False, defaults={}):
65 65 """
66 66 Create a auth database
67 67 """
68 68 quiet = defaults.get('quiet')
69 69 log.info("Any existing database is going to be destroyed")
70 70 if self.tests or quiet:
71 71 destroy = True
72 72 else:
73 73 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
74 74 if not destroy:
75 75 sys.exit()
76 76 if destroy:
77 77 meta.Base.metadata.drop_all()
78 78
79 79 checkfirst = not override
80 80 meta.Base.metadata.create_all(checkfirst=checkfirst)
81 81 log.info('Created tables for %s' % self.dbname)
82 82
83 83 def set_db_version(self):
84 84 ver = DbMigrateVersion()
85 85 ver.version = __dbversion__
86 86 ver.repository_id = 'rhodecode_db_migrations'
87 87 ver.repository_path = 'versions'
88 88 self.sa.add(ver)
89 89 log.info('db version set to: %s' % __dbversion__)
90 90
91 91 def upgrade(self):
92 92 """
93 93 Upgrades given database schema to given revision following
94 94 all needed steps, to perform the upgrade
95 95
96 96 """
97 97
98 98 from rhodecode.lib.dbmigrate.migrate.versioning import api
99 99 from rhodecode.lib.dbmigrate.migrate.exceptions import \
100 100 DatabaseNotControlledError
101 101
102 102 if 'sqlite' in self.dburi:
103 103 print (
104 104 '********************** WARNING **********************\n'
105 105 'Make sure your version of sqlite is at least 3.7.X. \n'
106 106 'Earlier versions are known to fail on some migrations\n'
107 107 '*****************************************************\n'
108 108 )
109 109 upgrade = ask_ok('You are about to perform database upgrade, make '
110 110 'sure You backed up your database before. '
111 111 'Continue ? [y/n]')
112 112 if not upgrade:
113 113 sys.exit('Nothing done')
114 114
115 115 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
116 116 'rhodecode/lib/dbmigrate')
117 117 db_uri = self.dburi
118 118
119 119 try:
120 120 curr_version = api.db_version(db_uri, repository_path)
121 121 msg = ('Found current database under version'
122 122 ' control with version %s' % curr_version)
123 123
124 124 except (RuntimeError, DatabaseNotControlledError):
125 125 curr_version = 1
126 126 msg = ('Current database is not under version control. Setting'
127 127 ' as version %s' % curr_version)
128 128 api.version_control(db_uri, repository_path, curr_version)
129 129
130 130 print (msg)
131 131
132 132 if curr_version == __dbversion__:
133 133 sys.exit('This database is already at the newest version')
134 134
135 135 #======================================================================
136 136 # UPGRADE STEPS
137 137 #======================================================================
138 138 class UpgradeSteps(object):
139 139 """
140 140 Those steps follow schema versions so for example schema
141 141 for example schema with seq 002 == step_2 and so on.
142 142 """
143 143
144 144 def __init__(self, klass):
145 145 self.klass = klass
146 146
147 147 def step_0(self):
148 148 # step 0 is the schema upgrade, and than follow proper upgrades
149 149 print ('attempting to do database upgrade to version %s' \
150 150 % __dbversion__)
151 151 api.upgrade(db_uri, repository_path, __dbversion__)
152 152 print ('Schema upgrade completed')
153 153
154 154 def step_1(self):
155 155 pass
156 156
157 157 def step_2(self):
158 158 print ('Patching repo paths for newer version of RhodeCode')
159 159 self.klass.fix_repo_paths()
160 160
161 161 print ('Patching default user of RhodeCode')
162 162 self.klass.fix_default_user()
163 163
164 164 log.info('Changing ui settings')
165 165 self.klass.create_ui_settings()
166 166
167 167 def step_3(self):
168 168 print ('Adding additional settings into RhodeCode db')
169 169 self.klass.fix_settings()
170 170 print ('Adding ldap defaults')
171 171 self.klass.create_ldap_options(skip_existing=True)
172 172
173 173 def step_4(self):
174 174 print ('create permissions and fix groups')
175 175 self.klass.create_permissions()
176 176 self.klass.fixup_groups()
177 177
178 178 def step_5(self):
179 179 pass
180 180
181 181 def step_6(self):
182 182 pass
183 183 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
184 184
185 185 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
186 186 for step in upgrade_steps:
187 187 print ('performing upgrade step %s' % step)
188 188 getattr(UpgradeSteps(self), 'step_%s' % step)()
189 189 self.sa.commit()
190 190
191 191 def fix_repo_paths(self):
192 192 """
193 193 Fixes a old rhodecode version path into new one without a '*'
194 194 """
195 195
196 196 paths = self.sa.query(RhodeCodeUi)\
197 197 .filter(RhodeCodeUi.ui_key == '/')\
198 198 .scalar()
199 199
200 200 paths.ui_value = paths.ui_value.replace('*', '')
201 201
202 202 try:
203 203 self.sa.add(paths)
204 204 self.sa.commit()
205 205 except:
206 206 self.sa.rollback()
207 207 raise
208 208
209 209 def fix_default_user(self):
210 210 """
211 211 Fixes a old default user with some 'nicer' default values,
212 212 used mostly for anonymous access
213 213 """
214 214 def_user = self.sa.query(User)\
215 215 .filter(User.username == 'default')\
216 216 .one()
217 217
218 218 def_user.name = 'Anonymous'
219 219 def_user.lastname = 'User'
220 220 def_user.email = 'anonymous@rhodecode.org'
221 221
222 222 try:
223 223 self.sa.add(def_user)
224 224 self.sa.commit()
225 225 except:
226 226 self.sa.rollback()
227 227 raise
228 228
229 229 def fix_settings(self):
230 230 """
231 231 Fixes rhodecode settings adds ga_code key for google analytics
232 232 """
233 233
234 234 hgsettings3 = RhodeCodeSetting('ga_code', '')
235 235
236 236 try:
237 237 self.sa.add(hgsettings3)
238 238 self.sa.commit()
239 239 except:
240 240 self.sa.rollback()
241 241 raise
242 242
243 243 def admin_prompt(self, second=False, defaults={}):
244 244 if not self.tests:
245 245 import getpass
246 246
247 247 # defaults
248 248 username = defaults.get('username')
249 249 password = defaults.get('password')
250 250 email = defaults.get('email')
251 251
252 252 def get_password():
253 253 password = getpass.getpass('Specify admin password '
254 254 '(min 6 chars):')
255 255 confirm = getpass.getpass('Confirm password:')
256 256
257 257 if password != confirm:
258 258 log.error('passwords mismatch')
259 259 return False
260 260 if len(password) < 6:
261 261 log.error('password is to short use at least 6 characters')
262 262 return False
263 263
264 264 return password
265 265 if username is None:
266 266 username = raw_input('Specify admin username:')
267 267 if password is None:
268 268 password = get_password()
269 269 if not password:
270 270 #second try
271 271 password = get_password()
272 272 if not password:
273 273 sys.exit()
274 274 if email is None:
275 275 email = raw_input('Specify admin email:')
276 276 self.create_user(username, password, email, True)
277 277 else:
278 278 log.info('creating admin and regular test users')
279 279 from rhodecode.tests import TEST_USER_ADMIN_LOGIN,\
280 280 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL,\
281 281 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,\
282 282 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
283 283 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
284 284
285 285 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
286 286 TEST_USER_ADMIN_EMAIL, True)
287 287
288 288 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
289 289 TEST_USER_REGULAR_EMAIL, False)
290 290
291 291 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
292 292 TEST_USER_REGULAR2_EMAIL, False)
293 293
294 294 def create_ui_settings(self):
295 295 """
296 296 Creates ui settings, fills out hooks
297 297 and disables dotencode
298 298 """
299 299
300 300 #HOOKS
301 301 hooks1_key = RhodeCodeUi.HOOK_UPDATE
302 302 hooks1_ = self.sa.query(RhodeCodeUi)\
303 303 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
304 304
305 305 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
306 306 hooks1.ui_section = 'hooks'
307 307 hooks1.ui_key = hooks1_key
308 308 hooks1.ui_value = 'hg update >&2'
309 309 hooks1.ui_active = False
310 310
311 311 hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
312 312 hooks2_ = self.sa.query(RhodeCodeUi)\
313 313 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
314 314
315 315 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
316 316 hooks2.ui_section = 'hooks'
317 317 hooks2.ui_key = hooks2_key
318 318 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
319 319
320 320 hooks3 = RhodeCodeUi()
321 321 hooks3.ui_section = 'hooks'
322 322 hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
323 323 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
324 324
325 325 hooks4 = RhodeCodeUi()
326 326 hooks4.ui_section = 'hooks'
327 327 hooks4.ui_key = RhodeCodeUi.HOOK_PULL
328 328 hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
329 329
330 330 # For mercurial 1.7 set backward comapatibility with format
331 331 dotencode_disable = RhodeCodeUi()
332 332 dotencode_disable.ui_section = 'format'
333 333 dotencode_disable.ui_key = 'dotencode'
334 334 dotencode_disable.ui_value = 'false'
335 335
336 336 # enable largefiles
337 337 largefiles = RhodeCodeUi()
338 338 largefiles.ui_section = 'extensions'
339 339 largefiles.ui_key = 'largefiles'
340 340 largefiles.ui_value = ''
341 341
342 342 self.sa.add(hooks1)
343 343 self.sa.add(hooks2)
344 344 self.sa.add(hooks3)
345 345 self.sa.add(hooks4)
346 346 self.sa.add(largefiles)
347 347
348 348 def create_ldap_options(self, skip_existing=False):
349 349 """Creates ldap settings"""
350 350
351 351 for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
352 352 ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
353 353 ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
354 354 ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
355 355 ('ldap_filter', ''), ('ldap_search_scope', ''),
356 356 ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
357 357 ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
358 358
359 359 if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
360 360 log.debug('Skipping option %s' % k)
361 361 continue
362 362 setting = RhodeCodeSetting(k, v)
363 363 self.sa.add(setting)
364 364
365 365 def fixup_groups(self):
366 366 def_usr = User.get_by_username('default')
367 367 for g in RepoGroup.query().all():
368 368 g.group_name = g.get_new_name(g.name)
369 369 self.sa.add(g)
370 370 # get default perm
371 371 default = UserRepoGroupToPerm.query()\
372 372 .filter(UserRepoGroupToPerm.group == g)\
373 373 .filter(UserRepoGroupToPerm.user == def_usr)\
374 374 .scalar()
375 375
376 376 if default is None:
377 377 log.debug('missing default permission for group %s adding' % g)
378 378 ReposGroupModel()._create_default_perms(g)
379 379
380 380 def config_prompt(self, test_repo_path='', retries=3, defaults={}):
381 381 _path = defaults.get('repos_location')
382 382 if retries == 3:
383 383 log.info('Setting up repositories config')
384 384
385 385 if _path is not None:
386 386 path = _path
387 387 elif not self.tests and not test_repo_path:
388 388 path = raw_input(
389 389 'Enter a valid absolute path to store repositories. '
390 390 'All repositories in that path will be added automatically:'
391 391 )
392 392 else:
393 393 path = test_repo_path
394 394 path_ok = True
395 395
396 396 # check proper dir
397 397 if not os.path.isdir(path):
398 398 path_ok = False
399 399 log.error('Given path %s is not a valid directory' % path)
400 400
401 401 elif not os.path.isabs(path):
402 402 path_ok = False
403 403 log.error('Given path %s is not an absolute path' % path)
404 404
405 405 # check write access
406 406 elif not os.access(path, os.W_OK) and path_ok:
407 407 path_ok = False
408 408 log.error('No write permission to given path %s' % path)
409 409
410 410 if retries == 0:
411 411 sys.exit('max retries reached')
412 412 if path_ok is False:
413 413 retries -= 1
414 414 return self.config_prompt(test_repo_path, retries)
415 415
416 416 return path
417 417
418 418 def create_settings(self, path):
419 419
420 420 self.create_ui_settings()
421 421
422 422 #HG UI OPTIONS
423 423 web1 = RhodeCodeUi()
424 424 web1.ui_section = 'web'
425 425 web1.ui_key = 'push_ssl'
426 426 web1.ui_value = 'false'
427 427
428 428 web2 = RhodeCodeUi()
429 429 web2.ui_section = 'web'
430 430 web2.ui_key = 'allow_archive'
431 431 web2.ui_value = 'gz zip bz2'
432 432
433 433 web3 = RhodeCodeUi()
434 434 web3.ui_section = 'web'
435 435 web3.ui_key = 'allow_push'
436 436 web3.ui_value = '*'
437 437
438 438 web4 = RhodeCodeUi()
439 439 web4.ui_section = 'web'
440 440 web4.ui_key = 'baseurl'
441 441 web4.ui_value = '/'
442 442
443 443 paths = RhodeCodeUi()
444 444 paths.ui_section = 'paths'
445 445 paths.ui_key = '/'
446 446 paths.ui_value = path
447 447
448 hgsettings1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
449 hgsettings2 = RhodeCodeSetting('title', 'RhodeCode')
450 hgsettings3 = RhodeCodeSetting('ga_code', '')
448 sett1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
449 sett2 = RhodeCodeSetting('title', 'RhodeCode')
450 sett3 = RhodeCodeSetting('ga_code', '')
451
452 sett4 = RhodeCodeSetting('show_public_icon', True)
453 sett5 = RhodeCodeSetting('show_private_icon', True)
454 sett6 = RhodeCodeSetting('stylify_metatags', False)
451 455
452 456 self.sa.add(web1)
453 457 self.sa.add(web2)
454 458 self.sa.add(web3)
455 459 self.sa.add(web4)
456 460 self.sa.add(paths)
457 self.sa.add(hgsettings1)
458 self.sa.add(hgsettings2)
459 self.sa.add(hgsettings3)
461 self.sa.add(sett1)
462 self.sa.add(sett2)
463 self.sa.add(sett3)
464 self.sa.add(sett4)
465 self.sa.add(sett5)
466 self.sa.add(sett6)
460 467
461 468 self.create_ldap_options()
462 469
463 470 log.info('created ui config')
464 471
465 472 def create_user(self, username, password, email='', admin=False):
466 473 log.info('creating user %s' % username)
467 474 UserModel().create_or_update(username, password, email,
468 475 firstname='RhodeCode', lastname='Admin',
469 476 active=True, admin=admin)
470 477
471 478 def create_default_user(self):
472 479 log.info('creating default user')
473 480 # create default user for handling default permissions.
474 481 UserModel().create_or_update(username='default',
475 482 password=str(uuid.uuid1())[:8],
476 483 email='anonymous@rhodecode.org',
477 484 firstname='Anonymous', lastname='User')
478 485
479 486 def create_permissions(self):
480 487 # module.(access|create|change|delete)_[name]
481 488 # module.(none|read|write|admin)
482 489
483 490 for p in Permission.PERMS:
484 491 if not Permission.get_by_key(p[0]):
485 492 new_perm = Permission()
486 493 new_perm.permission_name = p[0]
487 494 new_perm.permission_longname = p[0]
488 495 self.sa.add(new_perm)
489 496
490 497 def populate_default_permissions(self):
491 498 log.info('creating default user permissions')
492 499
493 500 default_user = self.sa.query(User)\
494 501 .filter(User.username == 'default').scalar()
495 502
496 503 reg_perm = UserToPerm()
497 504 reg_perm.user = default_user
498 505 reg_perm.permission = self.sa.query(Permission)\
499 506 .filter(Permission.permission_name == 'hg.register.manual_activate')\
500 507 .scalar()
501 508
502 509 create_repo_perm = UserToPerm()
503 510 create_repo_perm.user = default_user
504 511 create_repo_perm.permission = self.sa.query(Permission)\
505 512 .filter(Permission.permission_name == 'hg.create.repository')\
506 513 .scalar()
507 514
508 515 default_repo_perm = UserToPerm()
509 516 default_repo_perm.user = default_user
510 517 default_repo_perm.permission = self.sa.query(Permission)\
511 518 .filter(Permission.permission_name == 'repository.read')\
512 519 .scalar()
513 520
514 521 self.sa.add(reg_perm)
515 522 self.sa.add(create_repo_perm)
516 523 self.sa.add(default_repo_perm)
@@ -1,246 +1,246 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.html"/>
3 3
4 4 <%def name="title()">
5 5 ${_('Settings 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; ${_('Settings')}
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 </div>
22 22 <!-- end box / title -->
23 23
24 24 <h3>${_('Remap and rescan repositories')}</h3>
25 25 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
26 26 <div class="form">
27 27 <!-- fields -->
28 28
29 29 <div class="fields">
30 30 <div class="field">
31 31 <div class="label label-checkbox">
32 32 <label for="destroy">${_('rescan option')}:</label>
33 33 </div>
34 34 <div class="checkboxes">
35 35 <div class="checkbox">
36 36 ${h.checkbox('destroy',True)}
37 37 <label for="destroy">
38 38 <span class="tooltip" title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
39 39 ${_('destroy old data')}</span> </label>
40 40 </div>
41 41 </div>
42 42 </div>
43 43
44 44 <div class="buttons">
45 45 ${h.submit('rescan',_('Rescan repositories'),class_="ui-btn large")}
46 46 </div>
47 47 </div>
48 48 </div>
49 49 ${h.end_form()}
50 50
51 51 <h3>${_('Whoosh indexing')}</h3>
52 52 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
53 53 <div class="form">
54 54 <!-- fields -->
55 55
56 56 <div class="fields">
57 57 <div class="field">
58 58 <div class="label label-checkbox">
59 59 <label>${_('index build option')}:</label>
60 60 </div>
61 61 <div class="checkboxes">
62 62 <div class="checkbox">
63 63 ${h.checkbox('full_index',True)}
64 64 <label for="full_index">${_('build from scratch')}</label>
65 65 </div>
66 66 </div>
67 67 </div>
68 68
69 69 <div class="buttons">
70 70 ${h.submit('reindex',_('Reindex'),class_="ui-btn large")}
71 71 </div>
72 72 </div>
73 73 </div>
74 74 ${h.end_form()}
75 75
76 76 <h3>${_('Global application settings')}</h3>
77 77 ${h.form(url('admin_setting', setting_id='global'),method='put')}
78 78 <div class="form">
79 79 <!-- fields -->
80 80
81 81 <div class="fields">
82 82
83 83 <div class="field">
84 84 <div class="label">
85 85 <label for="rhodecode_title">${_('Application name')}:</label>
86 86 </div>
87 87 <div class="input">
88 88 ${h.text('rhodecode_title',size=30)}
89 89 </div>
90 90 </div>
91 91
92 92 <div class="field">
93 93 <div class="label">
94 94 <label for="rhodecode_realm">${_('Realm text')}:</label>
95 95 </div>
96 96 <div class="input">
97 97 ${h.text('rhodecode_realm',size=30)}
98 98 </div>
99 99 </div>
100 100
101 101 <div class="field">
102 102 <div class="label">
103 103 <label for="rhodecode_ga_code">${_('GA code')}:</label>
104 104 </div>
105 105 <div class="input">
106 106 ${h.text('rhodecode_ga_code',size=30)}
107 107 </div>
108 108 </div>
109 109
110 110 <div class="buttons">
111 111 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
112 112 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
113 113 </div>
114 114 </div>
115 115 </div>
116 116 ${h.end_form()}
117 117
118 <h3>${_('Mercurial settings')}</h3>
119 ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
118 <h3>${_('VCS settings')}</h3>
119 ${h.form(url('admin_setting', setting_id='vcs'),method='put')}
120 120 <div class="form">
121 121 <!-- fields -->
122 122
123 123 <div class="fields">
124 124
125 125 <div class="field">
126 126 <div class="label label-checkbox">
127 127 <label>${_('Web')}:</label>
128 128 </div>
129 129 <div class="checkboxes">
130 130 <div class="checkbox">
131 131 ${h.checkbox('web_push_ssl','true')}
132 132 <label for="web_push_ssl">${_('require ssl for pushing')}</label>
133 133 </div>
134 134 </div>
135 135 </div>
136 136
137 137 <div class="field">
138 138 <div class="label label-checkbox">
139 139 <label>${_('Hooks')}:</label>
140 140 </div>
141 141 <div class="checkboxes">
142 142 <div class="checkbox">
143 143 ${h.checkbox('hooks_changegroup_update','True')}
144 144 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
145 145 </div>
146 146 <div class="checkbox">
147 147 ${h.checkbox('hooks_changegroup_repo_size','True')}
148 148 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
149 149 </div>
150 150 <div class="checkbox">
151 151 ${h.checkbox('hooks_changegroup_push_logger','True')}
152 152 <label for="hooks_changegroup_push_logger">${_('Log user push commands')}</label>
153 153 </div>
154 154 <div class="checkbox">
155 155 ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
156 156 <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
157 157 </div>
158 158 </div>
159 159 <div class="input" style="margin-top:10px">
160 160 ${h.link_to(_('advanced setup'),url('admin_edit_setting',setting_id='hooks'),class_="ui-btn")}
161 161 </div>
162 162 </div>
163 163 <div class="field">
164 164 <div class="label">
165 165 <label for="paths_root_path">${_('Repositories location')}:</label>
166 166 </div>
167 167 <div class="input">
168 168 ${h.text('paths_root_path',size=30,readonly="readonly")}
169 169 <span id="path_unlock" class="tooltip"
170 170 title="${h.tooltip(_('This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock.'))}">
171 171 ${_('unlock')}</span>
172 172 </div>
173 173 </div>
174 174
175 175 <div class="buttons">
176 176 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
177 177 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
178 178 </div>
179 179 </div>
180 180 </div>
181 181 ${h.end_form()}
182 182
183 183 <script type="text/javascript">
184 184 YAHOO.util.Event.onDOMReady(function(){
185 185 YAHOO.util.Event.addListener('path_unlock','click',function(){
186 186 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
187 187 });
188 188 });
189 189 </script>
190 190
191 191 <h3>${_('Test Email')}</h3>
192 192 ${h.form(url('admin_setting', setting_id='email'),method='put')}
193 193 <div class="form">
194 194 <!-- fields -->
195 195
196 196 <div class="fields">
197 197 <div class="field">
198 198 <div class="label">
199 199 <label for="test_email">${_('Email to')}:</label>
200 200 </div>
201 201 <div class="input">
202 202 ${h.text('test_email',size=30)}
203 203 </div>
204 204 </div>
205 205
206 206 <div class="buttons">
207 207 ${h.submit('send',_('Send'),class_="ui-btn large")}
208 208 </div>
209 209 </div>
210 210 </div>
211 211 ${h.end_form()}
212 212
213 213 <h3>${_('System Info and Packages')}</h3>
214 214 <div class="form">
215 215 <div>
216 216 <h5 id="expand_modules" style="cursor: pointer">&darr; ${_('show')} &darr;</h5>
217 217 </div>
218 218 <div id="expand_modules_table" style="display:none">
219 219 <h5>Python - ${c.py_version}</h5>
220 220 <h5>System - ${c.platform}</h5>
221 221
222 222 <table class="table" style="margin:0px 0px 0px 20px">
223 223 <colgroup>
224 224 <col style="width:220px">
225 225 </colgroup>
226 226 <tbody>
227 227 %for key, value in c.modules:
228 228 <tr>
229 229 <th style="text-align: right;padding-right:5px;">${key}</th>
230 230 <td>${value}</td>
231 231 </tr>
232 232 %endfor
233 233 </tbody>
234 234 </table>
235 235 </div>
236 236 </div>
237 237
238 238 <script type="text/javascript">
239 239 YUE.on('expand_modules','click',function(e){
240 240 YUD.setStyle('expand_modules_table','display','');
241 241 YUD.setStyle('expand_modules','display','none');
242 242 })
243 243 </script>
244 244
245 245 </div>
246 246 </%def>
General Comments 0
You need to be logged in to leave comments. Login now