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