##// END OF EJS Templates
security: added missing csrf checks in few missing views.
ergo -
r1811:d57dfc88 default
parent child Browse files
Show More
@@ -1,102 +1,102 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from pyramid.view import view_config
23 from pyramid.view import view_config
24 from pyramid.httpexceptions import HTTPFound
24 from pyramid.httpexceptions import HTTPFound
25
25
26 from rhodecode.apps._base import BaseAppView
26 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps.admin.navigation import navigation_list
27 from rhodecode.apps.admin.navigation import navigation_list
28 from rhodecode.lib.auth import (
28 from rhodecode.lib.auth import (
29 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
29 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
30 from rhodecode.lib.utils2 import safe_int
30 from rhodecode.lib.utils2 import safe_int
31 from rhodecode.lib import system_info
31 from rhodecode.lib import system_info
32 from rhodecode.lib import user_sessions
32 from rhodecode.lib import user_sessions
33
33
34
34
35 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
36
36
37
37
38 class AdminSessionSettingsView(BaseAppView):
38 class AdminSessionSettingsView(BaseAppView):
39 def load_default_context(self):
39 def load_default_context(self):
40 c = self._get_local_tmpl_context()
40 c = self._get_local_tmpl_context()
41
41
42 self._register_global_c(c)
42 self._register_global_c(c)
43 return c
43 return c
44
44
45 @LoginRequired()
45 @LoginRequired()
46 @HasPermissionAllDecorator('hg.admin')
46 @HasPermissionAllDecorator('hg.admin')
47 @view_config(
47 @view_config(
48 route_name='admin_settings_sessions', request_method='GET',
48 route_name='admin_settings_sessions', request_method='GET',
49 renderer='rhodecode:templates/admin/settings/settings.mako')
49 renderer='rhodecode:templates/admin/settings/settings.mako')
50 def settings_sessions(self):
50 def settings_sessions(self):
51 c = self.load_default_context()
51 c = self.load_default_context()
52
52
53 c.active = 'sessions'
53 c.active = 'sessions'
54 c.navlist = navigation_list(self.request)
54 c.navlist = navigation_list(self.request)
55
55
56 c.cleanup_older_days = 60
56 c.cleanup_older_days = 60
57 older_than_seconds = 60 * 60 * 24 * c.cleanup_older_days
57 older_than_seconds = 60 * 60 * 24 * c.cleanup_older_days
58
58
59 config = system_info.rhodecode_config().get_value()['value']['config']
59 config = system_info.rhodecode_config().get_value()['value']['config']
60 c.session_model = user_sessions.get_session_handler(
60 c.session_model = user_sessions.get_session_handler(
61 config.get('beaker.session.type', 'memory'))(config)
61 config.get('beaker.session.type', 'memory'))(config)
62
62
63 c.session_conf = c.session_model.config
63 c.session_conf = c.session_model.config
64 c.session_count = c.session_model.get_count()
64 c.session_count = c.session_model.get_count()
65 c.session_expired_count = c.session_model.get_expired_count(
65 c.session_expired_count = c.session_model.get_expired_count(
66 older_than_seconds)
66 older_than_seconds)
67
67
68 return self._get_template_context(c)
68 return self._get_template_context(c)
69
69
70 @LoginRequired()
70 @LoginRequired()
71 @HasPermissionAllDecorator('hg.admin')
71 @CSRFRequired()
72 @CSRFRequired()
72 @HasPermissionAllDecorator('hg.admin')
73 @view_config(
73 @view_config(
74 route_name='admin_settings_sessions_cleanup', request_method='POST')
74 route_name='admin_settings_sessions_cleanup', request_method='POST')
75 def settings_sessions_cleanup(self):
75 def settings_sessions_cleanup(self):
76 _ = self.request.translate
76 _ = self.request.translate
77 expire_days = safe_int(self.request.params.get('expire_days'))
77 expire_days = safe_int(self.request.params.get('expire_days'))
78
78
79 if expire_days is None:
79 if expire_days is None:
80 expire_days = 60
80 expire_days = 60
81
81
82 older_than_seconds = 60 * 60 * 24 * expire_days
82 older_than_seconds = 60 * 60 * 24 * expire_days
83
83
84 config = system_info.rhodecode_config().get_value()['value']['config']
84 config = system_info.rhodecode_config().get_value()['value']['config']
85 session_model = user_sessions.get_session_handler(
85 session_model = user_sessions.get_session_handler(
86 config.get('beaker.session.type', 'memory'))(config)
86 config.get('beaker.session.type', 'memory'))(config)
87
87
88 try:
88 try:
89 session_model.clean_sessions(
89 session_model.clean_sessions(
90 older_than_seconds=older_than_seconds)
90 older_than_seconds=older_than_seconds)
91 self.request.session.flash(
91 self.request.session.flash(
92 _('Cleaned up old sessions'), queue='success')
92 _('Cleaned up old sessions'), queue='success')
93 except user_sessions.CleanupCommand as msg:
93 except user_sessions.CleanupCommand as msg:
94 self.request.session.flash(msg.message, queue='warning')
94 self.request.session.flash(msg.message, queue='warning')
95 except Exception as e:
95 except Exception as e:
96 log.exception('Failed session cleanup')
96 log.exception('Failed session cleanup')
97 self.request.session.flash(
97 self.request.session.flash(
98 _('Failed to cleanup up old sessions'), queue='error')
98 _('Failed to cleanup up old sessions'), queue='error')
99
99
100 redirect_to = self.request.resource_path(
100 redirect_to = self.request.resource_path(
101 self.context, route_name='admin_settings_sessions')
101 self.context, route_name='admin_settings_sessions')
102 return HTTPFound(redirect_to)
102 return HTTPFound(redirect_to)
@@ -1,59 +1,59 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from pyramid.view import view_config
23 from pyramid.view import view_config
24
24
25 from rhodecode.apps._base import BaseAppView
25 from rhodecode.apps._base import BaseAppView
26 from rhodecode.apps.svn_support.utils import generate_mod_dav_svn_config
26 from rhodecode.apps.svn_support.utils import generate_mod_dav_svn_config
27 from rhodecode.lib.auth import (
27 from rhodecode.lib.auth import (
28 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
28 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
29
29
30 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
31
31
32
32
33 class SvnConfigAdminSettingsView(BaseAppView):
33 class SvnConfigAdminSettingsView(BaseAppView):
34
34
35 @LoginRequired()
35 @LoginRequired()
36 @HasPermissionAllDecorator('hg.admin')
36 @CSRFRequired()
37 @CSRFRequired()
37 @HasPermissionAllDecorator('hg.admin')
38 @view_config(
38 @view_config(
39 route_name='admin_settings_vcs_svn_generate_cfg',
39 route_name='admin_settings_vcs_svn_generate_cfg',
40 request_method='POST', renderer='json')
40 request_method='POST', renderer='json')
41 def vcs_svn_generate_config(self):
41 def vcs_svn_generate_config(self):
42 _ = self.request.translate
42 _ = self.request.translate
43 try:
43 try:
44 generate_mod_dav_svn_config(self.request.registry)
44 generate_mod_dav_svn_config(self.request.registry)
45 msg = {
45 msg = {
46 'message': _('Apache configuration for Subversion generated.'),
46 'message': _('Apache configuration for Subversion generated.'),
47 'level': 'success',
47 'level': 'success',
48 }
48 }
49 except Exception:
49 except Exception:
50 log.exception(
50 log.exception(
51 'Exception while generating the Apache '
51 'Exception while generating the Apache '
52 'configuration for Subversion.')
52 'configuration for Subversion.')
53 msg = {
53 msg = {
54 'message': _('Failed to generate the Apache configuration for Subversion.'),
54 'message': _('Failed to generate the Apache configuration for Subversion.'),
55 'level': 'error',
55 'level': 'error',
56 }
56 }
57
57
58 data = {'message': msg}
58 data = {'message': msg}
59 return data
59 return data
@@ -1,307 +1,308 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import datetime
22 import datetime
23
23
24 from pyramid.httpexceptions import HTTPFound
24 from pyramid.httpexceptions import HTTPFound
25 from pyramid.view import view_config
25 from pyramid.view import view_config
26 from sqlalchemy.sql.functions import coalesce
26 from sqlalchemy.sql.functions import coalesce
27
27
28 from rhodecode.lib.helpers import Page
28 from rhodecode.lib.helpers import Page
29 from rhodecode.lib.ext_json import json
29 from rhodecode.lib.ext_json import json
30
30
31 from rhodecode.apps._base import BaseAppView, DataGridAppView
31 from rhodecode.apps._base import BaseAppView, DataGridAppView
32 from rhodecode.lib.auth import (
32 from rhodecode.lib.auth import (
33 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
33 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
34 from rhodecode.lib import helpers as h
34 from rhodecode.lib import helpers as h
35 from rhodecode.lib.utils import PartialRenderer
35 from rhodecode.lib.utils import PartialRenderer
36 from rhodecode.lib.utils2 import safe_int, safe_unicode
36 from rhodecode.lib.utils2 import safe_int, safe_unicode
37 from rhodecode.model.auth_token import AuthTokenModel
37 from rhodecode.model.auth_token import AuthTokenModel
38 from rhodecode.model.user import UserModel
38 from rhodecode.model.user import UserModel
39 from rhodecode.model.user_group import UserGroupModel
39 from rhodecode.model.user_group import UserGroupModel
40 from rhodecode.model.db import User, or_
40 from rhodecode.model.db import User, or_
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 AdminUsersView(BaseAppView, DataGridAppView):
46 class AdminUsersView(BaseAppView, DataGridAppView):
47 ALLOW_SCOPED_TOKENS = False
47 ALLOW_SCOPED_TOKENS = False
48 """
48 """
49 This view has alternative version inside EE, if modified please take a look
49 This view has alternative version inside EE, if modified please take a look
50 in there as well.
50 in there as well.
51 """
51 """
52
52
53 def load_default_context(self):
53 def load_default_context(self):
54 c = self._get_local_tmpl_context()
54 c = self._get_local_tmpl_context()
55 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
55 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
56 self._register_global_c(c)
56 self._register_global_c(c)
57 return c
57 return c
58
58
59 def _redirect_for_default_user(self, username):
59 def _redirect_for_default_user(self, username):
60 _ = self.request.translate
60 _ = self.request.translate
61 if username == User.DEFAULT_USER:
61 if username == User.DEFAULT_USER:
62 h.flash(_("You can't edit this user"), category='warning')
62 h.flash(_("You can't edit this user"), category='warning')
63 # TODO(marcink): redirect to 'users' admin panel once this
63 # TODO(marcink): redirect to 'users' admin panel once this
64 # is a pyramid view
64 # is a pyramid view
65 raise HTTPFound('/')
65 raise HTTPFound('/')
66
66
67 @HasPermissionAllDecorator('hg.admin')
67 @HasPermissionAllDecorator('hg.admin')
68 @view_config(
68 @view_config(
69 route_name='users', request_method='GET',
69 route_name='users', request_method='GET',
70 renderer='rhodecode:templates/admin/users/users.mako')
70 renderer='rhodecode:templates/admin/users/users.mako')
71 def users_list(self):
71 def users_list(self):
72 c = self.load_default_context()
72 c = self.load_default_context()
73 return self._get_template_context(c)
73 return self._get_template_context(c)
74
74
75 @HasPermissionAllDecorator('hg.admin')
75 @HasPermissionAllDecorator('hg.admin')
76 @view_config(
76 @view_config(
77 # renderer defined below
77 # renderer defined below
78 route_name='users_data', request_method='GET',
78 route_name='users_data', request_method='GET',
79 renderer='json_ext', xhr=True)
79 renderer='json_ext', xhr=True)
80 def users_list_data(self):
80 def users_list_data(self):
81 draw, start, limit = self._extract_chunk(self.request)
81 draw, start, limit = self._extract_chunk(self.request)
82 search_q, order_by, order_dir = self._extract_ordering(self.request)
82 search_q, order_by, order_dir = self._extract_ordering(self.request)
83
83
84 _render = PartialRenderer('data_table/_dt_elements.mako')
84 _render = PartialRenderer('data_table/_dt_elements.mako')
85
85
86 def user_actions(user_id, username):
86 def user_actions(user_id, username):
87 return _render("user_actions", user_id, username)
87 return _render("user_actions", user_id, username)
88
88
89 users_data_total_count = User.query()\
89 users_data_total_count = User.query()\
90 .filter(User.username != User.DEFAULT_USER) \
90 .filter(User.username != User.DEFAULT_USER) \
91 .count()
91 .count()
92
92
93 # json generate
93 # json generate
94 base_q = User.query().filter(User.username != User.DEFAULT_USER)
94 base_q = User.query().filter(User.username != User.DEFAULT_USER)
95
95
96 if search_q:
96 if search_q:
97 like_expression = u'%{}%'.format(safe_unicode(search_q))
97 like_expression = u'%{}%'.format(safe_unicode(search_q))
98 base_q = base_q.filter(or_(
98 base_q = base_q.filter(or_(
99 User.username.ilike(like_expression),
99 User.username.ilike(like_expression),
100 User._email.ilike(like_expression),
100 User._email.ilike(like_expression),
101 User.name.ilike(like_expression),
101 User.name.ilike(like_expression),
102 User.lastname.ilike(like_expression),
102 User.lastname.ilike(like_expression),
103 ))
103 ))
104
104
105 users_data_total_filtered_count = base_q.count()
105 users_data_total_filtered_count = base_q.count()
106
106
107 sort_col = getattr(User, order_by, None)
107 sort_col = getattr(User, order_by, None)
108 if sort_col:
108 if sort_col:
109 if order_dir == 'asc':
109 if order_dir == 'asc':
110 # handle null values properly to order by NULL last
110 # handle null values properly to order by NULL last
111 if order_by in ['last_activity']:
111 if order_by in ['last_activity']:
112 sort_col = coalesce(sort_col, datetime.date.max)
112 sort_col = coalesce(sort_col, datetime.date.max)
113 sort_col = sort_col.asc()
113 sort_col = sort_col.asc()
114 else:
114 else:
115 # handle null values properly to order by NULL last
115 # handle null values properly to order by NULL last
116 if order_by in ['last_activity']:
116 if order_by in ['last_activity']:
117 sort_col = coalesce(sort_col, datetime.date.min)
117 sort_col = coalesce(sort_col, datetime.date.min)
118 sort_col = sort_col.desc()
118 sort_col = sort_col.desc()
119
119
120 base_q = base_q.order_by(sort_col)
120 base_q = base_q.order_by(sort_col)
121 base_q = base_q.offset(start).limit(limit)
121 base_q = base_q.offset(start).limit(limit)
122
122
123 users_list = base_q.all()
123 users_list = base_q.all()
124
124
125 users_data = []
125 users_data = []
126 for user in users_list:
126 for user in users_list:
127 users_data.append({
127 users_data.append({
128 "username": h.gravatar_with_user(user.username),
128 "username": h.gravatar_with_user(user.username),
129 "email": user.email,
129 "email": user.email,
130 "first_name": h.escape(user.name),
130 "first_name": h.escape(user.name),
131 "last_name": h.escape(user.lastname),
131 "last_name": h.escape(user.lastname),
132 "last_login": h.format_date(user.last_login),
132 "last_login": h.format_date(user.last_login),
133 "last_activity": h.format_date(user.last_activity),
133 "last_activity": h.format_date(user.last_activity),
134 "active": h.bool2icon(user.active),
134 "active": h.bool2icon(user.active),
135 "active_raw": user.active,
135 "active_raw": user.active,
136 "admin": h.bool2icon(user.admin),
136 "admin": h.bool2icon(user.admin),
137 "extern_type": user.extern_type,
137 "extern_type": user.extern_type,
138 "extern_name": user.extern_name,
138 "extern_name": user.extern_name,
139 "action": user_actions(user.user_id, user.username),
139 "action": user_actions(user.user_id, user.username),
140 })
140 })
141
141
142 data = ({
142 data = ({
143 'draw': draw,
143 'draw': draw,
144 'data': users_data,
144 'data': users_data,
145 'recordsTotal': users_data_total_count,
145 'recordsTotal': users_data_total_count,
146 'recordsFiltered': users_data_total_filtered_count,
146 'recordsFiltered': users_data_total_filtered_count,
147 })
147 })
148
148
149 return data
149 return data
150
150
151 @LoginRequired()
151 @LoginRequired()
152 @HasPermissionAllDecorator('hg.admin')
152 @HasPermissionAllDecorator('hg.admin')
153 @view_config(
153 @view_config(
154 route_name='edit_user_auth_tokens', request_method='GET',
154 route_name='edit_user_auth_tokens', request_method='GET',
155 renderer='rhodecode:templates/admin/users/user_edit.mako')
155 renderer='rhodecode:templates/admin/users/user_edit.mako')
156 def auth_tokens(self):
156 def auth_tokens(self):
157 _ = self.request.translate
157 _ = self.request.translate
158 c = self.load_default_context()
158 c = self.load_default_context()
159
159
160 user_id = self.request.matchdict.get('user_id')
160 user_id = self.request.matchdict.get('user_id')
161 c.user = User.get_or_404(user_id, pyramid_exc=True)
161 c.user = User.get_or_404(user_id, pyramid_exc=True)
162 self._redirect_for_default_user(c.user.username)
162 self._redirect_for_default_user(c.user.username)
163
163
164 c.active = 'auth_tokens'
164 c.active = 'auth_tokens'
165
165
166 c.lifetime_values = [
166 c.lifetime_values = [
167 (str(-1), _('forever')),
167 (str(-1), _('forever')),
168 (str(5), _('5 minutes')),
168 (str(5), _('5 minutes')),
169 (str(60), _('1 hour')),
169 (str(60), _('1 hour')),
170 (str(60 * 24), _('1 day')),
170 (str(60 * 24), _('1 day')),
171 (str(60 * 24 * 30), _('1 month')),
171 (str(60 * 24 * 30), _('1 month')),
172 ]
172 ]
173 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
173 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
174 c.role_values = [
174 c.role_values = [
175 (x, AuthTokenModel.cls._get_role_name(x))
175 (x, AuthTokenModel.cls._get_role_name(x))
176 for x in AuthTokenModel.cls.ROLES]
176 for x in AuthTokenModel.cls.ROLES]
177 c.role_options = [(c.role_values, _("Role"))]
177 c.role_options = [(c.role_values, _("Role"))]
178 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
178 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
179 c.user.user_id, show_expired=True)
179 c.user.user_id, show_expired=True)
180 return self._get_template_context(c)
180 return self._get_template_context(c)
181
181
182 def maybe_attach_token_scope(self, token):
182 def maybe_attach_token_scope(self, token):
183 # implemented in EE edition
183 # implemented in EE edition
184 pass
184 pass
185
185
186 @LoginRequired()
186 @LoginRequired()
187 @HasPermissionAllDecorator('hg.admin')
187 @HasPermissionAllDecorator('hg.admin')
188 @CSRFRequired()
188 @CSRFRequired()
189 @view_config(
189 @view_config(
190 route_name='edit_user_auth_tokens_add', request_method='POST')
190 route_name='edit_user_auth_tokens_add', request_method='POST')
191 def auth_tokens_add(self):
191 def auth_tokens_add(self):
192 _ = self.request.translate
192 _ = self.request.translate
193 c = self.load_default_context()
193 c = self.load_default_context()
194
194
195 user_id = self.request.matchdict.get('user_id')
195 user_id = self.request.matchdict.get('user_id')
196 c.user = User.get_or_404(user_id, pyramid_exc=True)
196 c.user = User.get_or_404(user_id, pyramid_exc=True)
197 self._redirect_for_default_user(c.user.username)
197 self._redirect_for_default_user(c.user.username)
198
198
199 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
199 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
200 description = self.request.POST.get('description')
200 description = self.request.POST.get('description')
201 role = self.request.POST.get('role')
201 role = self.request.POST.get('role')
202
202
203 token = AuthTokenModel().create(
203 token = AuthTokenModel().create(
204 c.user.user_id, description, lifetime, role)
204 c.user.user_id, description, lifetime, role)
205 self.maybe_attach_token_scope(token)
205 self.maybe_attach_token_scope(token)
206 Session().commit()
206 Session().commit()
207
207
208 h.flash(_("Auth token successfully created"), category='success')
208 h.flash(_("Auth token successfully created"), category='success')
209 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
209 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
210
210
211 @LoginRequired()
211 @LoginRequired()
212 @HasPermissionAllDecorator('hg.admin')
212 @HasPermissionAllDecorator('hg.admin')
213 @CSRFRequired()
213 @CSRFRequired()
214 @view_config(
214 @view_config(
215 route_name='edit_user_auth_tokens_delete', request_method='POST')
215 route_name='edit_user_auth_tokens_delete', request_method='POST')
216 def auth_tokens_delete(self):
216 def auth_tokens_delete(self):
217 _ = self.request.translate
217 _ = self.request.translate
218 c = self.load_default_context()
218 c = self.load_default_context()
219
219
220 user_id = self.request.matchdict.get('user_id')
220 user_id = self.request.matchdict.get('user_id')
221 c.user = User.get_or_404(user_id, pyramid_exc=True)
221 c.user = User.get_or_404(user_id, pyramid_exc=True)
222 self._redirect_for_default_user(c.user.username)
222 self._redirect_for_default_user(c.user.username)
223
223
224 del_auth_token = self.request.POST.get('del_auth_token')
224 del_auth_token = self.request.POST.get('del_auth_token')
225
225
226 if del_auth_token:
226 if del_auth_token:
227 AuthTokenModel().delete(del_auth_token, c.user.user_id)
227 AuthTokenModel().delete(del_auth_token, c.user.user_id)
228 Session().commit()
228 Session().commit()
229 h.flash(_("Auth token successfully deleted"), category='success')
229 h.flash(_("Auth token successfully deleted"), category='success')
230
230
231 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
231 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
232
232
233 @LoginRequired()
233 @LoginRequired()
234 @HasPermissionAllDecorator('hg.admin')
234 @HasPermissionAllDecorator('hg.admin')
235 @view_config(
235 @view_config(
236 route_name='edit_user_groups_management', request_method='GET',
236 route_name='edit_user_groups_management', request_method='GET',
237 renderer='rhodecode:templates/admin/users/user_edit.mako')
237 renderer='rhodecode:templates/admin/users/user_edit.mako')
238 def groups_management(self):
238 def groups_management(self):
239 c = self.load_default_context()
239 c = self.load_default_context()
240
240
241 user_id = self.request.matchdict.get('user_id')
241 user_id = self.request.matchdict.get('user_id')
242 c.user = User.get_or_404(user_id, pyramid_exc=True)
242 c.user = User.get_or_404(user_id, pyramid_exc=True)
243 c.data = c.user.group_member
243 c.data = c.user.group_member
244 self._redirect_for_default_user(c.user.username)
244 self._redirect_for_default_user(c.user.username)
245 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
245 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
246 for group in c.user.group_member]
246 for group in c.user.group_member]
247 c.groups = json.dumps(groups)
247 c.groups = json.dumps(groups)
248 c.active = 'groups'
248 c.active = 'groups'
249
249
250 return self._get_template_context(c)
250 return self._get_template_context(c)
251
251
252 @LoginRequired()
252 @LoginRequired()
253 @HasPermissionAllDecorator('hg.admin')
253 @HasPermissionAllDecorator('hg.admin')
254 @CSRFRequired()
254 @view_config(
255 @view_config(
255 route_name='edit_user_groups_management_updates', request_method='POST')
256 route_name='edit_user_groups_management_updates', request_method='POST')
256 def groups_management_updates(self):
257 def groups_management_updates(self):
257 _ = self.request.translate
258 _ = self.request.translate
258 c = self.load_default_context()
259 c = self.load_default_context()
259
260
260 user_id = self.request.matchdict.get('user_id')
261 user_id = self.request.matchdict.get('user_id')
261 c.user = User.get_or_404(user_id, pyramid_exc=True)
262 c.user = User.get_or_404(user_id, pyramid_exc=True)
262 self._redirect_for_default_user(c.user.username)
263 self._redirect_for_default_user(c.user.username)
263
264
264 users_groups = set(self.request.POST.getall('users_group_id'))
265 users_groups = set(self.request.POST.getall('users_group_id'))
265 users_groups_model = []
266 users_groups_model = []
266
267
267 for ugid in users_groups:
268 for ugid in users_groups:
268 users_groups_model.append(UserGroupModel().get_group(safe_int(ugid)))
269 users_groups_model.append(UserGroupModel().get_group(safe_int(ugid)))
269 user_group_model = UserGroupModel()
270 user_group_model = UserGroupModel()
270 user_group_model.change_groups(c.user, users_groups_model)
271 user_group_model.change_groups(c.user, users_groups_model)
271
272
272 Session().commit()
273 Session().commit()
273 c.active = 'user_groups_management'
274 c.active = 'user_groups_management'
274 h.flash(_("Groups successfully changed"), category='success')
275 h.flash(_("Groups successfully changed"), category='success')
275
276
276 return HTTPFound(h.route_path(
277 return HTTPFound(h.route_path(
277 'edit_user_groups_management', user_id=user_id))
278 'edit_user_groups_management', user_id=user_id))
278
279
279 @LoginRequired()
280 @LoginRequired()
280 @HasPermissionAllDecorator('hg.admin')
281 @HasPermissionAllDecorator('hg.admin')
281 @view_config(
282 @view_config(
282 route_name='edit_user_audit_logs', request_method='GET',
283 route_name='edit_user_audit_logs', request_method='GET',
283 renderer='rhodecode:templates/admin/users/user_edit.mako')
284 renderer='rhodecode:templates/admin/users/user_edit.mako')
284 def user_audit_logs(self):
285 def user_audit_logs(self):
285 _ = self.request.translate
286 _ = self.request.translate
286 c = self.load_default_context()
287 c = self.load_default_context()
287
288
288 user_id = self.request.matchdict.get('user_id')
289 user_id = self.request.matchdict.get('user_id')
289 c.user = User.get_or_404(user_id, pyramid_exc=True)
290 c.user = User.get_or_404(user_id, pyramid_exc=True)
290 self._redirect_for_default_user(c.user.username)
291 self._redirect_for_default_user(c.user.username)
291 c.active = 'audit'
292 c.active = 'audit'
292
293
293 p = safe_int(self.request.GET.get('page', 1), 1)
294 p = safe_int(self.request.GET.get('page', 1), 1)
294
295
295 filter_term = self.request.GET.get('filter')
296 filter_term = self.request.GET.get('filter')
296 user_log = UserModel().get_user_log(c.user, filter_term)
297 user_log = UserModel().get_user_log(c.user, filter_term)
297
298
298 def url_generator(**kw):
299 def url_generator(**kw):
299 if filter_term:
300 if filter_term:
300 kw['filter'] = filter_term
301 kw['filter'] = filter_term
301 return self.request.current_route_path(_query=kw)
302 return self.request.current_route_path(_query=kw)
302
303
303 c.audit_logs = Page(user_log, page=p, items_per_page=10,
304 c.audit_logs = Page(user_log, page=p, items_per_page=10,
304 url=url_generator)
305 url=url_generator)
305 c.filter_term = filter_term
306 c.filter_term = filter_term
306 return self._get_template_context(c)
307 return self._get_template_context(c)
307
308
@@ -1,76 +1,78 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from pyramid.httpexceptions import HTTPFound
23 from pyramid.httpexceptions import HTTPFound
24 from pyramid.view import view_config
24 from pyramid.view import view_config
25
25
26 from rhodecode.apps._base import RepoAppView
26 from rhodecode.apps._base import RepoAppView
27 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
27 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \
28 CSRFRequired
28 from rhodecode.lib import helpers as h
29 from rhodecode.lib import helpers as h
29 from rhodecode.model.meta import Session
30 from rhodecode.model.meta import Session
30 from rhodecode.model.scm import ScmModel
31 from rhodecode.model.scm import ScmModel
31
32
32 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
33
34
34
35
35 class RepoCachesView(RepoAppView):
36 class RepoCachesView(RepoAppView):
36 def load_default_context(self):
37 def load_default_context(self):
37 c = self._get_local_tmpl_context()
38 c = self._get_local_tmpl_context()
38
39
39 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
40 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
40 c.repo_info = self.db_repo
41 c.repo_info = self.db_repo
41
42
42 self._register_global_c(c)
43 self._register_global_c(c)
43 return c
44 return c
44
45
45 @LoginRequired()
46 @LoginRequired()
46 @HasRepoPermissionAnyDecorator('repository.admin')
47 @HasRepoPermissionAnyDecorator('repository.admin')
47 @view_config(
48 @view_config(
48 route_name='edit_repo_caches', request_method='GET',
49 route_name='edit_repo_caches', request_method='GET',
49 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
50 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
50 def repo_caches(self):
51 def repo_caches(self):
51 c = self.load_default_context()
52 c = self.load_default_context()
52 c.active = 'caches'
53 c.active = 'caches'
53
54
54 return self._get_template_context(c)
55 return self._get_template_context(c)
55
56
56 @LoginRequired()
57 @LoginRequired()
57 @HasRepoPermissionAnyDecorator('repository.admin')
58 @HasRepoPermissionAnyDecorator('repository.admin')
59 @CSRFRequired()
58 @view_config(
60 @view_config(
59 route_name='edit_repo_caches', request_method='POST')
61 route_name='edit_repo_caches', request_method='POST')
60 def repo_caches_purge(self):
62 def repo_caches_purge(self):
61 _ = self.request.translate
63 _ = self.request.translate
62 c = self.load_default_context()
64 c = self.load_default_context()
63 c.active = 'caches'
65 c.active = 'caches'
64
66
65 try:
67 try:
66 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
68 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
67 Session().commit()
69 Session().commit()
68 h.flash(_('Cache invalidation successful'),
70 h.flash(_('Cache invalidation successful'),
69 category='success')
71 category='success')
70 except Exception:
72 except Exception:
71 log.exception("Exception during cache invalidation")
73 log.exception("Exception during cache invalidation")
72 h.flash(_('An error occurred during cache invalidation'),
74 h.flash(_('An error occurred during cache invalidation'),
73 category='error')
75 category='error')
74
76
75 raise HTTPFound(h.route_path(
77 raise HTTPFound(h.route_path(
76 'edit_repo_caches', repo_name=self.db_repo_name)) No newline at end of file
78 'edit_repo_caches', repo_name=self.db_repo_name))
@@ -1,226 +1,227 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from pyramid.view import view_config
23 from pyramid.view import view_config
24 from pyramid.httpexceptions import HTTPFound
24 from pyramid.httpexceptions import HTTPFound
25
25
26 from rhodecode.apps._base import RepoAppView
26 from rhodecode.apps._base import RepoAppView
27 from rhodecode.lib import helpers as h
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib import audit_logger
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import (
29 from rhodecode.lib.auth import (
30 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
30 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
31 from rhodecode.lib.exceptions import AttachedForksError
31 from rhodecode.lib.exceptions import AttachedForksError
32 from rhodecode.lib.utils2 import safe_int
32 from rhodecode.lib.utils2 import safe_int
33 from rhodecode.lib.vcs import RepositoryError
33 from rhodecode.lib.vcs import RepositoryError
34 from rhodecode.model.db import Session, UserFollowing, User, Repository
34 from rhodecode.model.db import Session, UserFollowing, User, Repository
35 from rhodecode.model.repo import RepoModel
35 from rhodecode.model.repo import RepoModel
36 from rhodecode.model.scm import ScmModel
36 from rhodecode.model.scm import ScmModel
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40
40
41 class RepoSettingsView(RepoAppView):
41 class RepoSettingsView(RepoAppView):
42
42
43 def load_default_context(self):
43 def load_default_context(self):
44 c = self._get_local_tmpl_context()
44 c = self._get_local_tmpl_context()
45
45
46 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
46 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
47 c.repo_info = self.db_repo
47 c.repo_info = self.db_repo
48
48
49 self._register_global_c(c)
49 self._register_global_c(c)
50 return c
50 return c
51
51
52 @LoginRequired()
52 @LoginRequired()
53 @HasRepoPermissionAnyDecorator('repository.admin')
53 @HasRepoPermissionAnyDecorator('repository.admin')
54 @view_config(
54 @view_config(
55 route_name='edit_repo_advanced', request_method='GET',
55 route_name='edit_repo_advanced', request_method='GET',
56 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
56 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
57 def edit_advanced(self):
57 def edit_advanced(self):
58 c = self.load_default_context()
58 c = self.load_default_context()
59 c.active = 'advanced'
59 c.active = 'advanced'
60
60
61 c.default_user_id = User.get_default_user().user_id
61 c.default_user_id = User.get_default_user().user_id
62 c.in_public_journal = UserFollowing.query() \
62 c.in_public_journal = UserFollowing.query() \
63 .filter(UserFollowing.user_id == c.default_user_id) \
63 .filter(UserFollowing.user_id == c.default_user_id) \
64 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
64 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
65
65
66 c.has_origin_repo_read_perm = False
66 c.has_origin_repo_read_perm = False
67 if self.db_repo.fork:
67 if self.db_repo.fork:
68 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
68 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
69 'repository.write', 'repository.read', 'repository.admin')(
69 'repository.write', 'repository.read', 'repository.admin')(
70 self.db_repo.fork.repo_name, 'repo set as fork page')
70 self.db_repo.fork.repo_name, 'repo set as fork page')
71
71
72 return self._get_template_context(c)
72 return self._get_template_context(c)
73
73
74 @LoginRequired()
74 @LoginRequired()
75 @HasRepoPermissionAnyDecorator('repository.admin')
75 @HasRepoPermissionAnyDecorator('repository.admin')
76 @CSRFRequired()
76 @view_config(
77 @view_config(
77 route_name='edit_repo_advanced_delete', request_method='POST',
78 route_name='edit_repo_advanced_delete', request_method='POST',
78 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
79 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
79 def edit_advanced_delete(self):
80 def edit_advanced_delete(self):
80 """
81 """
81 Deletes the repository, or shows warnings if deletion is not possible
82 Deletes the repository, or shows warnings if deletion is not possible
82 because of attached forks or other errors.
83 because of attached forks or other errors.
83 """
84 """
84 _ = self.request.translate
85 _ = self.request.translate
85 handle_forks = self.request.POST.get('forks', None)
86 handle_forks = self.request.POST.get('forks', None)
86
87
87 try:
88 try:
88 _forks = self.db_repo.forks.count()
89 _forks = self.db_repo.forks.count()
89 if _forks and handle_forks:
90 if _forks and handle_forks:
90 if handle_forks == 'detach_forks':
91 if handle_forks == 'detach_forks':
91 handle_forks = 'detach'
92 handle_forks = 'detach'
92 h.flash(_('Detached %s forks') % _forks, category='success')
93 h.flash(_('Detached %s forks') % _forks, category='success')
93 elif handle_forks == 'delete_forks':
94 elif handle_forks == 'delete_forks':
94 handle_forks = 'delete'
95 handle_forks = 'delete'
95 h.flash(_('Deleted %s forks') % _forks, category='success')
96 h.flash(_('Deleted %s forks') % _forks, category='success')
96
97
97 repo_data = self.db_repo.get_api_data()
98 repo_data = self.db_repo.get_api_data()
98 RepoModel().delete(self.db_repo, forks=handle_forks)
99 RepoModel().delete(self.db_repo, forks=handle_forks)
99
100
100 repo = audit_logger.RepoWrap(repo_id=None,
101 repo = audit_logger.RepoWrap(repo_id=None,
101 repo_name=self.db_repo.repo_name)
102 repo_name=self.db_repo.repo_name)
102 audit_logger.store_web(
103 audit_logger.store_web(
103 action='repo.delete',
104 action='repo.delete',
104 action_data={'data': repo_data},
105 action_data={'data': repo_data},
105 user=self._rhodecode_user, repo=repo)
106 user=self._rhodecode_user, repo=repo)
106
107
107 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
108 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
108 h.flash(
109 h.flash(
109 _('Deleted repository `%s`') % self.db_repo_name,
110 _('Deleted repository `%s`') % self.db_repo_name,
110 category='success')
111 category='success')
111 Session().commit()
112 Session().commit()
112 except AttachedForksError:
113 except AttachedForksError:
113 repo_advanced_url = h.route_path(
114 repo_advanced_url = h.route_path(
114 'edit_repo_advanced', repo_name=self.db_repo_name,
115 'edit_repo_advanced', repo_name=self.db_repo_name,
115 _anchor='advanced-delete')
116 _anchor='advanced-delete')
116 delete_anchor = h.link_to(_('detach or delete'), repo_advanced_url)
117 delete_anchor = h.link_to(_('detach or delete'), repo_advanced_url)
117 h.flash(_('Cannot delete `{repo}` it still contains attached forks. '
118 h.flash(_('Cannot delete `{repo}` it still contains attached forks. '
118 'Try using {delete_or_detach} option.')
119 'Try using {delete_or_detach} option.')
119 .format(repo=self.db_repo_name, delete_or_detach=delete_anchor),
120 .format(repo=self.db_repo_name, delete_or_detach=delete_anchor),
120 category='warning')
121 category='warning')
121
122
122 # redirect to advanced for forks handle action ?
123 # redirect to advanced for forks handle action ?
123 raise HTTPFound(repo_advanced_url)
124 raise HTTPFound(repo_advanced_url)
124
125
125 except Exception:
126 except Exception:
126 log.exception("Exception during deletion of repository")
127 log.exception("Exception during deletion of repository")
127 h.flash(_('An error occurred during deletion of `%s`')
128 h.flash(_('An error occurred during deletion of `%s`')
128 % self.db_repo_name, category='error')
129 % self.db_repo_name, category='error')
129 # redirect to advanced for more deletion options
130 # redirect to advanced for more deletion options
130 raise HTTPFound(
131 raise HTTPFound(
131 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name),
132 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name),
132 _anchor='advanced-delete')
133 _anchor='advanced-delete')
133
134
134 raise HTTPFound(h.route_path('home'))
135 raise HTTPFound(h.route_path('home'))
135
136
136 @LoginRequired()
137 @LoginRequired()
137 @HasRepoPermissionAnyDecorator('repository.admin')
138 @HasRepoPermissionAnyDecorator('repository.admin')
138 @CSRFRequired()
139 @CSRFRequired()
139 @view_config(
140 @view_config(
140 route_name='edit_repo_advanced_journal', request_method='POST',
141 route_name='edit_repo_advanced_journal', request_method='POST',
141 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
142 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
142 def edit_advanced_journal(self):
143 def edit_advanced_journal(self):
143 """
144 """
144 Set's this repository to be visible in public journal,
145 Set's this repository to be visible in public journal,
145 in other words making default user to follow this repo
146 in other words making default user to follow this repo
146 """
147 """
147 _ = self.request.translate
148 _ = self.request.translate
148
149
149 try:
150 try:
150 user_id = User.get_default_user().user_id
151 user_id = User.get_default_user().user_id
151 ScmModel().toggle_following_repo(self.db_repo.repo_id, user_id)
152 ScmModel().toggle_following_repo(self.db_repo.repo_id, user_id)
152 h.flash(_('Updated repository visibility in public journal'),
153 h.flash(_('Updated repository visibility in public journal'),
153 category='success')
154 category='success')
154 Session().commit()
155 Session().commit()
155 except Exception:
156 except Exception:
156 h.flash(_('An error occurred during setting this '
157 h.flash(_('An error occurred during setting this '
157 'repository in public journal'),
158 'repository in public journal'),
158 category='error')
159 category='error')
159
160
160 raise HTTPFound(
161 raise HTTPFound(
161 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
162 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
162
163
163 @LoginRequired()
164 @LoginRequired()
164 @HasRepoPermissionAnyDecorator('repository.admin')
165 @HasRepoPermissionAnyDecorator('repository.admin')
165 @CSRFRequired()
166 @CSRFRequired()
166 @view_config(
167 @view_config(
167 route_name='edit_repo_advanced_fork', request_method='POST',
168 route_name='edit_repo_advanced_fork', request_method='POST',
168 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
169 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
169 def edit_advanced_fork(self):
170 def edit_advanced_fork(self):
170 """
171 """
171 Mark given repository as a fork of another
172 Mark given repository as a fork of another
172 """
173 """
173 _ = self.request.translate
174 _ = self.request.translate
174
175
175 new_fork_id = self.request.POST.get('id_fork_of')
176 new_fork_id = self.request.POST.get('id_fork_of')
176 try:
177 try:
177
178
178 if new_fork_id and not new_fork_id.isdigit():
179 if new_fork_id and not new_fork_id.isdigit():
179 log.error('Given fork id %s is not an INT', new_fork_id)
180 log.error('Given fork id %s is not an INT', new_fork_id)
180
181
181 fork_id = safe_int(new_fork_id)
182 fork_id = safe_int(new_fork_id)
182 repo = ScmModel().mark_as_fork(
183 repo = ScmModel().mark_as_fork(
183 self.db_repo_name, fork_id, self._rhodecode_user.user_id)
184 self.db_repo_name, fork_id, self._rhodecode_user.user_id)
184 fork = repo.fork.repo_name if repo.fork else _('Nothing')
185 fork = repo.fork.repo_name if repo.fork else _('Nothing')
185 Session().commit()
186 Session().commit()
186 h.flash(_('Marked repo %s as fork of %s') % (self.db_repo_name, fork),
187 h.flash(_('Marked repo %s as fork of %s') % (self.db_repo_name, fork),
187 category='success')
188 category='success')
188 except RepositoryError as e:
189 except RepositoryError as e:
189 log.exception("Repository Error occurred")
190 log.exception("Repository Error occurred")
190 h.flash(str(e), category='error')
191 h.flash(str(e), category='error')
191 except Exception as e:
192 except Exception as e:
192 log.exception("Exception while editing fork")
193 log.exception("Exception while editing fork")
193 h.flash(_('An error occurred during this operation'),
194 h.flash(_('An error occurred during this operation'),
194 category='error')
195 category='error')
195
196
196 raise HTTPFound(
197 raise HTTPFound(
197 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
198 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
198
199
199 @LoginRequired()
200 @LoginRequired()
200 @HasRepoPermissionAnyDecorator('repository.admin')
201 @HasRepoPermissionAnyDecorator('repository.admin')
201 @CSRFRequired()
202 @CSRFRequired()
202 @view_config(
203 @view_config(
203 route_name='edit_repo_advanced_locking', request_method='POST',
204 route_name='edit_repo_advanced_locking', request_method='POST',
204 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
205 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
205 def edit_advanced_locking(self):
206 def edit_advanced_locking(self):
206 """
207 """
207 Toggle locking of repository
208 Toggle locking of repository
208 """
209 """
209 _ = self.request.translate
210 _ = self.request.translate
210 set_lock = self.request.POST.get('set_lock')
211 set_lock = self.request.POST.get('set_lock')
211 set_unlock = self.request.POST.get('set_unlock')
212 set_unlock = self.request.POST.get('set_unlock')
212
213
213 try:
214 try:
214 if set_lock:
215 if set_lock:
215 Repository.lock(self.db_repo, self._rhodecode_user.user_id,
216 Repository.lock(self.db_repo, self._rhodecode_user.user_id,
216 lock_reason=Repository.LOCK_WEB)
217 lock_reason=Repository.LOCK_WEB)
217 h.flash(_('Locked repository'), category='success')
218 h.flash(_('Locked repository'), category='success')
218 elif set_unlock:
219 elif set_unlock:
219 Repository.unlock(self.db_repo)
220 Repository.unlock(self.db_repo)
220 h.flash(_('Unlocked repository'), category='success')
221 h.flash(_('Unlocked repository'), category='success')
221 except Exception as e:
222 except Exception as e:
222 log.exception("Exception during unlocking")
223 log.exception("Exception during unlocking")
223 h.flash(_('An error occurred during unlocking'), category='error')
224 h.flash(_('An error occurred during unlocking'), category='error')
224
225
225 raise HTTPFound(
226 raise HTTPFound(
226 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
227 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
@@ -1,116 +1,118 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2017-2017 RhodeCode GmbH
3 # Copyright (C) 2017-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 from pyramid.view import view_config
22 from pyramid.view import view_config
23
23
24 from rhodecode.apps._base import RepoAppView
24 from rhodecode.apps._base import RepoAppView
25 from rhodecode.lib import audit_logger
25 from rhodecode.lib import audit_logger
26 from rhodecode.lib import helpers as h
26 from rhodecode.lib import helpers as h
27 from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator,
27 from rhodecode.lib.auth import (LoginRequired, HasRepoPermissionAnyDecorator,
28 NotAnonymous)
28 NotAnonymous, CSRFRequired)
29 from rhodecode.lib.ext_json import json
29 from rhodecode.lib.ext_json import json
30
30
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33
33
34 class StripView(RepoAppView):
34 class StripView(RepoAppView):
35 def load_default_context(self):
35 def load_default_context(self):
36 c = self._get_local_tmpl_context()
36 c = self._get_local_tmpl_context()
37
37
38 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
38 # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead
39 c.repo_info = self.db_repo
39 c.repo_info = self.db_repo
40
40
41 self._register_global_c(c)
41 self._register_global_c(c)
42 return c
42 return c
43
43
44 @LoginRequired()
44 @LoginRequired()
45 @HasRepoPermissionAnyDecorator('repository.admin')
45 @HasRepoPermissionAnyDecorator('repository.admin')
46 @view_config(
46 @view_config(
47 route_name='strip', request_method='GET',
47 route_name='strip', request_method='GET',
48 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
48 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
49 def strip(self):
49 def strip(self):
50 c = self.load_default_context()
50 c = self.load_default_context()
51 c.active = 'strip'
51 c.active = 'strip'
52 c.strip_limit = 10
52 c.strip_limit = 10
53
53
54 return self._get_template_context(c)
54 return self._get_template_context(c)
55
55
56 @LoginRequired()
56 @LoginRequired()
57 @HasRepoPermissionAnyDecorator('repository.admin')
57 @HasRepoPermissionAnyDecorator('repository.admin')
58 @CSRFRequired()
58 @view_config(
59 @view_config(
59 route_name='strip_check', request_method='POST',
60 route_name='strip_check', request_method='POST',
60 renderer='json', xhr=True)
61 renderer='json', xhr=True)
61 def strip_check(self):
62 def strip_check(self):
62 from rhodecode.lib.vcs.backends.base import EmptyCommit
63 from rhodecode.lib.vcs.backends.base import EmptyCommit
63 data = {}
64 data = {}
64 rp = self.request.POST
65 rp = self.request.POST
65 for i in range(1, 11):
66 for i in range(1, 11):
66 chset = 'changeset_id-%d' % (i,)
67 chset = 'changeset_id-%d' % (i,)
67 check = rp.get(chset)
68 check = rp.get(chset)
68
69
69 if check:
70 if check:
70 data[i] = self.db_repo.get_changeset(rp[chset])
71 data[i] = self.db_repo.get_changeset(rp[chset])
71 if isinstance(data[i], EmptyCommit):
72 if isinstance(data[i], EmptyCommit):
72 data[i] = {'rev': None, 'commit': h.escape(rp[chset])}
73 data[i] = {'rev': None, 'commit': h.escape(rp[chset])}
73 else:
74 else:
74 data[i] = {'rev': data[i].raw_id, 'branch': data[i].branch,
75 data[i] = {'rev': data[i].raw_id, 'branch': data[i].branch,
75 'author': data[i].author,
76 'author': data[i].author,
76 'comment': data[i].message}
77 'comment': data[i].message}
77 else:
78 else:
78 break
79 break
79 return data
80 return data
80
81
81 @LoginRequired()
82 @LoginRequired()
82 @HasRepoPermissionAnyDecorator('repository.admin')
83 @HasRepoPermissionAnyDecorator('repository.admin')
84 @CSRFRequired()
83 @view_config(
85 @view_config(
84 route_name='strip_execute', request_method='POST',
86 route_name='strip_execute', request_method='POST',
85 renderer='json', xhr=True)
87 renderer='json', xhr=True)
86 def strip_execute(self):
88 def strip_execute(self):
87 from rhodecode.model.scm import ScmModel
89 from rhodecode.model.scm import ScmModel
88
90
89 c = self.load_default_context()
91 c = self.load_default_context()
90 user = self._rhodecode_user
92 user = self._rhodecode_user
91 rp = self.request.POST
93 rp = self.request.POST
92 data = {}
94 data = {}
93 for idx in rp:
95 for idx in rp:
94 commit = json.loads(rp[idx])
96 commit = json.loads(rp[idx])
95 # If someone put two times the same branch
97 # If someone put two times the same branch
96 if commit['branch'] in data.keys():
98 if commit['branch'] in data.keys():
97 continue
99 continue
98 try:
100 try:
99 ScmModel().strip(
101 ScmModel().strip(
100 repo=c.repo_info,
102 repo=c.repo_info,
101 commit_id=commit['rev'], branch=commit['branch'])
103 commit_id=commit['rev'], branch=commit['branch'])
102 log.info('Stripped commit %s from repo `%s` by %s' % (
104 log.info('Stripped commit %s from repo `%s` by %s' % (
103 commit['rev'], c.repo_info.repo_name, user))
105 commit['rev'], c.repo_info.repo_name, user))
104 data[commit['rev']] = True
106 data[commit['rev']] = True
105
107
106 audit_logger.store_web(
108 audit_logger.store_web(
107 action='repo.commit.strip',
109 action='repo.commit.strip',
108 action_data={'commit_id': commit['rev']},
110 action_data={'commit_id': commit['rev']},
109 repo=self.db_repo,
111 repo=self.db_repo,
110 user=self._rhodecode_user, commit=True)
112 user=self._rhodecode_user, commit=True)
111
113
112 except Exception as e:
114 except Exception as e:
113 data[commit['rev']] = False
115 data[commit['rev']] = False
114 log.debug('Stripped commit %s from repo `%s` failed by %s, exeption %s' % (
116 log.debug('Stripped commit %s from repo `%s` failed by %s, exeption %s' % (
115 commit['rev'], self.db_repo_name, user, e.message))
117 commit['rev'], self.db_repo_name, user, e.message))
116 return data
118 return data
@@ -1,193 +1,197 b''
1 <div class="panel panel-default">
1 <div class="panel panel-default">
2 <div class="panel-heading">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('Strip commits from repository')}</h3>
3 <h3 class="panel-title">${_('Strip commits from repository')}</h3>
4 </div>
4 </div>
5 <div class="panel-body">
5 <div class="panel-body">
6 %if c.repo_info.repo_type != 'svn':
6 %if c.repo_info.repo_type != 'svn':
7 <h4>${_('Please provide up to %d commits commits to strip') % c.strip_limit}</h4>
7 <h4>${_('Please provide up to %d commits commits to strip') % c.strip_limit}</h4>
8 <p>
8 <p>
9 ${_('In the first step commits will be verified for existance in the repository')}. </br>
9 ${_('In the first step commits will be verified for existance in the repository')}. </br>
10 ${_('In the second step, correct commits will be available for stripping')}.
10 ${_('In the second step, correct commits will be available for stripping')}.
11 </p>
11 </p>
12 ${h.secure_form(h.route_path('strip_check', repo_name=c.repo_info.repo_name), method='post')}
12 ${h.secure_form(h.route_path('strip_check', repo_name=c.repo_info.repo_name), method='post')}
13 <div id="change_body" class="field">
13 <div id="change_body" class="field">
14 <div id="box-1" class="inputx locked_input">
14 <div id="box-1" class="inputx locked_input">
15 <input class="text" id="changeset_id-1" name="changeset_id-1" size="59"
15 <input class="text" id="changeset_id-1" name="changeset_id-1" size="59"
16 placeholder="${_('Enter full 40 character commit sha')}" type="text" value="">
16 placeholder="${_('Enter full 40 character commit sha')}" type="text" value="">
17 <div id="plus_icon-1" class="btn btn-default plus_input_button" onclick="addNew(1);return false">
17 <div id="plus_icon-1" class="btn btn-default plus_input_button" onclick="addNew(1);return false">
18 <i class="icon-plus">${_('Add another commit')}</i>
18 <i class="icon-plus">${_('Add another commit')}</i>
19 </div>
19 </div>
20 </div>
20 </div>
21 </div>
21 </div>
22
22
23 <div id="results" style="display:none; padding: 10px 0px;"></div>
23 <div id="results" style="display:none; padding: 10px 0px;"></div>
24
24
25 <div class="buttons">
25 <div class="buttons">
26 <button id="strip_action" class="btn btn-small btn-primary" onclick="checkCommits();return false">
26 <button id="strip_action" class="btn btn-small btn-primary" onclick="checkCommits();return false">
27 ${_('Check commits')}
27 ${_('Check commits')}
28 </button>
28 </button>
29 </div>
29 </div>
30
30
31 ${h.end_form()}
31 ${h.end_form()}
32 %else:
32 %else:
33 <h4>${_('Sorry this functionality is not available for SVN repository')}</h4>
33 <h4>${_('Sorry this functionality is not available for SVN repository')}</h4>
34 %endif
34 %endif
35 </div>
35 </div>
36 </div>
36 </div>
37
37
38
38
39 <script>
39 <script>
40 var plus_leaf = 1;
40 var plus_leaf = 1;
41
41
42 addNew = function(number){
42 addNew = function(number){
43 if (number >= ${c.strip_limit}){
43 if (number >= ${c.strip_limit}){
44 return;
44 return;
45 }
45 }
46 var minus = '<i class="icon-minus">${_('Remove')}</i>';
46 var minus = '<i class="icon-minus">${_('Remove')}</i>';
47 $('#plus_icon-'+number).detach();
47 $('#plus_icon-'+number).detach();
48 number++;
48 number++;
49
49
50 var input = '<div id="box-'+number+'" class="inputx locked_input">'+
50 var input = '<div id="box-'+number+'" class="inputx locked_input">'+
51 '<input class="text" id="changeset_id-'+number+'" name="changeset_id-'+number+'" size="59" type="text" value=""' +
51 '<input class="text" id="changeset_id-'+number+'" name="changeset_id-'+number+'" size="59" type="text" value=""' +
52 'placeholder="${_('Enter full 40 character commit sha')}">'+
52 'placeholder="${_('Enter full 40 character commit sha')}">'+
53 '<div id="plus_icon-'+number+'" class="btn btn-default plus_input_button" onclick="addNew('+number+');return false">'+
53 '<div id="plus_icon-'+number+'" class="btn btn-default plus_input_button" onclick="addNew('+number+');return false">'+
54 '<i class="icon-plus">${_('Add another commit')}</i>'+
54 '<i class="icon-plus">${_('Add another commit')}</i>'+
55 '</div>'+
55 '</div>'+
56 '<div id="minus_icon-'+number+'" class="btn btn-default minus_input_button" onclick="delOld('+(number)+');return false">'+
56 '<div id="minus_icon-'+number+'" class="btn btn-default minus_input_button" onclick="delOld('+(number)+');return false">'+
57 minus +
57 minus +
58 '</div>' +
58 '</div>' +
59 '</div>';
59 '</div>';
60 $('#change_body').append(input);
60 $('#change_body').append(input);
61 plus_leaf++;
61 plus_leaf++;
62 };
62 };
63
63
64 reIndex = function(number){
64 reIndex = function(number){
65 for(var i=number;i<=plus_leaf;i++){
65 for(var i=number;i<=plus_leaf;i++){
66 var check = $('#box-'+i);
66 var check = $('#box-'+i);
67 if (check.length == 0){
67 if (check.length == 0){
68 var change = $('#box-'+(i+1));
68 var change = $('#box-'+(i+1));
69 change.attr('id','box-'+i);
69 change.attr('id','box-'+i);
70 var plus = $('#plus_icon-'+(i+1));
70 var plus = $('#plus_icon-'+(i+1));
71
71
72 if (plus.length != 0){
72 if (plus.length != 0){
73 plus.attr('id','plus_icon-'+i);
73 plus.attr('id','plus_icon-'+i);
74 plus.attr('onclick','addNew('+i+');return false');
74 plus.attr('onclick','addNew('+i+');return false');
75 plus_leaf--;
75 plus_leaf--;
76 }
76 }
77 var minus = $('#minus_icon-'+(i+1));
77 var minus = $('#minus_icon-'+(i+1));
78
78
79 minus.attr('id','minus_icon-'+i);
79 minus.attr('id','minus_icon-'+i);
80
80
81 minus.attr('onclick','delOld('+i+');re' +
81 minus.attr('onclick','delOld('+i+');re' +
82 'turn false');
82 'turn false');
83 var input = $('input#changeset_id-'+(i+1));
83 var input = $('input#changeset_id-'+(i+1));
84 input.attr('name','changeset_id-'+i);
84 input.attr('name','changeset_id-'+i);
85 input.attr('id','changeset_id-'+i);
85 input.attr('id','changeset_id-'+i);
86 }
86 }
87 }
87 }
88 };
88 };
89
89
90 delOld = function(number){
90 delOld = function(number){
91 $('#box-'+number).remove();
91 $('#box-'+number).remove();
92 number = number - 1;
92 number = number - 1;
93 var box = $('#box-'+number);
93 var box = $('#box-'+number);
94 var plus = '<div id="plus_icon-'+number+'" class="btn btn-default plus_input_button" onclick="addNew('+number +');return false">'+
94 var plus = '<div id="plus_icon-'+number+'" class="btn btn-default plus_input_button" onclick="addNew('+number +');return false">'+
95 '<i id="i_plus_icon-'+number+'" class="icon-plus">${_('Add another commit')}</i></div>';
95 '<i id="i_plus_icon-'+number+'" class="icon-plus">${_('Add another commit')}</i></div>';
96 var minus = $('#minus_icon-'+number);
96 var minus = $('#minus_icon-'+number);
97 if(number +1 == plus_leaf){
97 if(number +1 == plus_leaf){
98 minus.detach();
98 minus.detach();
99 box.append(plus);
99 box.append(plus);
100 box.append(minus);
100 box.append(minus);
101 plus_leaf --;
101 plus_leaf --;
102 }
102 }
103 reIndex(number+1);
103 reIndex(number+1);
104
104
105 };
105 };
106
106
107 var result_data;
107 var resultData = {
108 'csrf_token': CSRF_TOKEN
109 };
108
110
109 checkCommits = function() {
111 checkCommits = function() {
110 var postData = $('form').serialize();
112 var postData = $('form').serialize();
111 $('#results').show();
113 $('#results').show();
112 $('#results').html('<h4>${_('Checking commits')}...</h4>');
114 $('#results').html('<h4>${_('Checking commits')}...</h4>');
113 var url = "${h.route_path('strip_check', repo_name=c.repo_info.repo_name)}";
115 var url = "${h.route_path('strip_check', repo_name=c.repo_info.repo_name)}";
114 var btn = $('#strip_action');
116 var btn = $('#strip_action');
115 btn.attr('disabled', 'disabled');
117 btn.attr('disabled', 'disabled');
116 btn.addClass('disabled');
118 btn.addClass('disabled');
117
119
118 var success = function (data) {
120 var success = function (data) {
119 result_data = {};
121 resultData = {
122 'csrf_token': CSRF_TOKEN
123 };
120 var i = 0;
124 var i = 0;
121 var result = '<ol>';
125 var result = '<ol>';
122 $.each(data, function(index, value){
126 $.each(data, function(index, value){
123 i= index;
127 i= index;
124 var box = $('#box-'+index);
128 var box = $('#box-'+index);
125 if (value.rev){
129 if (value.rev){
126 result_data[index] = JSON.stringify(value);
130 resultData[index] = JSON.stringify(value);
127
131
128 var verifiedHtml = (
132 var verifiedHtml = (
129 '<li style="line-height:1.2em">' +
133 '<li style="line-height:1.2em">' +
130 '<code>{0}</code>' +
134 '<code>{0}</code>' +
131 '{1}' +
135 '{1}' +
132 '<div style="white-space:pre">' +
136 '<div style="white-space:pre">' +
133 'author: {2}\n' +
137 'author: {2}\n' +
134 'description: {3}' +
138 'description: {3}' +
135 '</div>' +
139 '</div>' +
136 '</li>').format(
140 '</li>').format(
137 value.rev,
141 value.rev,
138 "${_(' commit verified positive')}",
142 "${_(' commit verified positive')}",
139 value.author, value.comment
143 value.author, value.comment
140 );
144 );
141 result += verifiedHtml;
145 result += verifiedHtml;
142 }
146 }
143 else {
147 else {
144 var verifiedHtml = (
148 var verifiedHtml = (
145 '<li style="line-height:1.2em">' +
149 '<li style="line-height:1.2em">' +
146 '<code><strike>{0}</strike></code>' +
150 '<code><strike>{0}</strike></code>' +
147 '{1}' +
151 '{1}' +
148 '</li>').format(
152 '</li>').format(
149 value.commit,
153 value.commit,
150 "${_(' commit verified negative')}"
154 "${_(' commit verified negative')}"
151 );
155 );
152 result += verifiedHtml;
156 result += verifiedHtml;
153 }
157 }
154 box.remove();
158 box.remove();
155 });
159 });
156 result += '</ol>';
160 result += '</ol>';
157 var box = $('#box-'+(parseInt(i)+1));
161 var box = $('#box-'+(parseInt(i)+1));
158 box.remove();
162 box.remove();
159 $('#results').html(result);
163 $('#results').html(result);
160 };
164 };
161
165
162 btn.html('Strip');
166 btn.html('Strip');
163 btn.removeAttr('disabled');
167 btn.removeAttr('disabled');
164 btn.removeClass('disabled');
168 btn.removeClass('disabled');
165 btn.attr('onclick','strip();return false;');
169 btn.attr('onclick','strip();return false;');
166 ajaxPOST(url, postData, success, null);
170 ajaxPOST(url, postData, success, null);
167 };
171 };
168
172
169 strip = function() {
173 strip = function() {
170 var url = "${h.route_path('strip_execute', repo_name=c.repo_info.repo_name)}";
174 var url = "${h.route_path('strip_execute', repo_name=c.repo_info.repo_name)}";
171 var success = function(data) {
175 var success = function(data) {
172 var result = '<h4>Strip executed</h4><ol>';
176 var result = '<h4>Strip executed</h4><ol>';
173 $.each(data, function(index, value){
177 $.each(data, function(index, value){
174 if(data[index]) {
178 if(data[index]) {
175 result += '<li><code>' +index+ '</code> ${_(' commit striped successfully')}' + '</li>';
179 result += '<li><code>' +index+ '</code> ${_(' commit striped successfully')}' + '</li>';
176 }
180 }
177 else {
181 else {
178 result += '<li><code>' +index+ '</code> ${_(' commit strip failed')}' + '</li>';
182 result += '<li><code>' +index+ '</code> ${_(' commit strip failed')}' + '</li>';
179 }
183 }
180 });
184 });
181 if ($.isEmptyObject(data)) {
185 if ($.isEmptyObject(data)) {
182 result += '<li>Nothing done...</li>'
186 result += '<li>Nothing done...</li>'
183 }
187 }
184 result += '</ol>';
188 result += '</ol>';
185 $('#results').html(result);
189 $('#results').html(result);
186
190
187 };
191 };
188 ajaxPOST(url, result_data, success, null);
192 ajaxPOST(url, resultData, success, null);
189 var btn = $('#strip_action');
193 var btn = $('#strip_action');
190 btn.remove();
194 btn.remove();
191
195
192 };
196 };
193 </script>
197 </script>
General Comments 0
You need to be logged in to leave comments. Login now