Show More
@@ -178,13 +178,14 b' class ChangesetStatusModel(BaseModel):' | |||||
178 | """ |
|
178 | """ | |
179 |
|
179 | |||
180 | def group_rule(element): |
|
180 | def group_rule(element): | |
181 | review_obj = element[0] |
|
181 | _review_obj = element[0] | |
182 | rule_data = review_obj.rule_user_group_data() |
|
182 | rule_data = _review_obj.rule_user_group_data() | |
183 | if rule_data and rule_data['id']: |
|
183 | if rule_data and rule_data['id']: | |
184 | return rule_data['id'] |
|
184 | return rule_data['id'] | |
|
185 | # don't return None, as we cant compare this | |||
|
186 | return 0 | |||
185 |
|
187 | |||
186 | voting_groups = itertools.groupby( |
|
188 | voting_groups = itertools.groupby(sorted(statuses_by_reviewers, key=group_rule), group_rule) | |
187 | sorted(statuses_by_reviewers, key=group_rule), group_rule) |
|
|||
188 |
|
189 | |||
189 | voting_by_groups = [(x, list(y)) for x, y in voting_groups] |
|
190 | voting_by_groups = [(x, list(y)) for x, y in voting_groups] | |
190 |
|
191 |
@@ -296,9 +296,6 b' class CommentsModel(BaseModel):' | |||||
296 | :param extra_recipients: list of extra users to be added to recipients |
|
296 | :param extra_recipients: list of extra users to be added to recipients | |
297 | """ |
|
297 | """ | |
298 |
|
298 | |||
299 | if not text: |
|
|||
300 | log.warning('Missing text for comment, skipping...') |
|
|||
301 | return |
|
|||
302 | request = get_current_request() |
|
299 | request = get_current_request() | |
303 | _ = request.translate |
|
300 | _ = request.translate | |
304 |
|
301 |
@@ -31,7 +31,7 b' import shutil' | |||||
31 | from pyramid.threadlocal import get_current_request |
|
31 | from pyramid.threadlocal import get_current_request | |
32 |
|
32 | |||
33 | from rhodecode.lib.utils2 import ( |
|
33 | from rhodecode.lib.utils2 import ( | |
34 |
|
|
34 | unique_id, safe_int, safe_str, time_to_datetime, AttributeDict) | |
35 | from rhodecode.lib.ext_json import json |
|
35 | from rhodecode.lib.ext_json import json | |
36 | from rhodecode.lib.vcs import VCSError |
|
36 | from rhodecode.lib.vcs import VCSError | |
37 | from rhodecode.model import BaseModel |
|
37 | from rhodecode.model import BaseModel | |
@@ -121,7 +121,7 b' class GistModel(BaseModel):' | |||||
121 | :param gist_acl_level: acl level for this gist |
|
121 | :param gist_acl_level: acl level for this gist | |
122 | """ |
|
122 | """ | |
123 | owner = self._get_user(owner) |
|
123 | owner = self._get_user(owner) | |
124 |
gist_id = safe_ |
|
124 | gist_id = safe_str(gist_id or unique_id(20)) | |
125 | lifetime = safe_int(lifetime, -1) |
|
125 | lifetime = safe_int(lifetime, -1) | |
126 | gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1 |
|
126 | gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1 | |
127 | expiration = (time_to_datetime(gist_expires) |
|
127 | expiration = (time_to_datetime(gist_expires) | |
@@ -133,13 +133,13 b' class GistModel(BaseModel):' | |||||
133 | gist.gist_access_id = gist_id |
|
133 | gist.gist_access_id = gist_id | |
134 | gist.gist_owner = owner.user_id |
|
134 | gist.gist_owner = owner.user_id | |
135 | gist.gist_expires = gist_expires |
|
135 | gist.gist_expires = gist_expires | |
136 |
gist.gist_type = safe_ |
|
136 | gist.gist_type = safe_str(gist_type) | |
137 | gist.acl_level = gist_acl_level |
|
137 | gist.acl_level = gist_acl_level | |
138 | self.sa.add(gist) |
|
138 | self.sa.add(gist) | |
139 | self.sa.flush() |
|
139 | self.sa.flush() | |
140 | if gist_type == Gist.GIST_PUBLIC: |
|
140 | if gist_type == Gist.GIST_PUBLIC: | |
141 | # use DB ID for easy to use GIST ID |
|
141 | # use DB ID for easy to use GIST ID | |
142 |
gist_id = safe_ |
|
142 | gist_id = safe_str(gist.gist_id) | |
143 | gist.gist_access_id = gist_id |
|
143 | gist.gist_access_id = gist_id | |
144 | self.sa.add(gist) |
|
144 | self.sa.add(gist) | |
145 |
|
145 | |||
@@ -152,7 +152,7 b' class GistModel(BaseModel):' | |||||
152 | # now create single multifile commit |
|
152 | # now create single multifile commit | |
153 | message = 'added file' |
|
153 | message = 'added file' | |
154 | message += 's: ' if len(gist_mapping) > 1 else ': ' |
|
154 | message += 's: ' if len(gist_mapping) > 1 else ': ' | |
155 | message += ', '.join([x for x in gist_mapping]) |
|
155 | message += ', '.join([safe_str(x) for x in gist_mapping]) | |
156 |
|
156 | |||
157 | # fake RhodeCode Repository object |
|
157 | # fake RhodeCode Repository object | |
158 | fake_repo = AttributeDict({ |
|
158 | fake_repo = AttributeDict({ | |
@@ -218,7 +218,7 b' class GistModel(BaseModel):' | |||||
218 |
|
218 | |||
219 | message = 'updated file' |
|
219 | message = 'updated file' | |
220 | message += 's: ' if len(gist_mapping) > 1 else ': ' |
|
220 | message += 's: ' if len(gist_mapping) > 1 else ': ' | |
221 | message += ', '.join([x for x in gist_mapping]) |
|
221 | message += ', '.join([safe_str(x) for x in gist_mapping]) | |
222 |
|
222 | |||
223 | # fake RhodeCode Repository object |
|
223 | # fake RhodeCode Repository object | |
224 | fake_repo = AttributeDict({ |
|
224 | fake_repo = AttributeDict({ |
@@ -28,12 +28,11 b' import logging' | |||||
28 |
|
28 | |||
29 | from sqlalchemy import or_, and_ |
|
29 | from sqlalchemy import or_, and_ | |
30 |
|
30 | |||
31 | import rhodecode |
|
|||
32 | from rhodecode import events |
|
31 | from rhodecode import events | |
33 | from rhodecode.integrations.types.base import EEIntegration |
|
32 | from rhodecode.integrations.types.base import EEIntegration | |
34 | from rhodecode.lib.caching_query import FromCache |
|
33 | from rhodecode.lib.caching_query import FromCache | |
35 | from rhodecode.model import BaseModel |
|
34 | from rhodecode.model import BaseModel | |
36 | from rhodecode.model.db import Integration, Repository, RepoGroup, true, false, case |
|
35 | from rhodecode.model.db import Integration, Repository, RepoGroup, true, false, case, null | |
37 | from rhodecode.integrations import integration_type_registry |
|
36 | from rhodecode.integrations import integration_type_registry | |
38 |
|
37 | |||
39 | log = logging.getLogger(__name__) |
|
38 | log = logging.getLogger(__name__) | |
@@ -53,8 +52,7 b' class IntegrationModel(BaseModel):' | |||||
53 | raise Exception('integration must be int or Instance' |
|
52 | raise Exception('integration must be int or Instance' | |
54 | ' of Integration got %s' % type(integration)) |
|
53 | ' of Integration got %s' % type(integration)) | |
55 |
|
54 | |||
56 | def create(self, IntegrationType, name, enabled, repo, repo_group, |
|
55 | def create(self, IntegrationType, name, enabled, repo, repo_group, child_repos_only, settings): | |
57 | child_repos_only, settings): |
|
|||
58 | """ Create an IntegrationType integration """ |
|
56 | """ Create an IntegrationType integration """ | |
59 | integration = Integration() |
|
57 | integration = Integration() | |
60 | integration.integration_type = IntegrationType.key |
|
58 | integration.integration_type = IntegrationType.key | |
@@ -163,15 +161,15 b' class IntegrationModel(BaseModel):' | |||||
163 | ) |
|
161 | ) | |
164 |
|
162 | |||
165 | global_integrations_filter = and_( |
|
163 | global_integrations_filter = and_( | |
166 |
Integration.repo_id == |
|
164 | Integration.repo_id == null(), | |
167 |
Integration.repo_group_id == |
|
165 | Integration.repo_group_id == null(), | |
168 | Integration.child_repos_only == false(), |
|
166 | Integration.child_repos_only == false(), | |
169 | ) |
|
167 | ) | |
170 |
|
168 | |||
171 | if isinstance(event, events.RepoEvent): |
|
169 | if isinstance(event, events.RepoEvent): | |
172 | root_repos_integrations_filter = and_( |
|
170 | root_repos_integrations_filter = and_( | |
173 |
Integration.repo_id == |
|
171 | Integration.repo_id == null(), | |
174 |
Integration.repo_group_id == |
|
172 | Integration.repo_group_id == null(), | |
175 | Integration.child_repos_only == true(), |
|
173 | Integration.child_repos_only == true(), | |
176 | ) |
|
174 | ) | |
177 |
|
175 | |||
@@ -225,7 +223,7 b' class IntegrationModel(BaseModel):' | |||||
225 | query = query.order_by(order_by_criterion) |
|
223 | query = query.order_by(order_by_criterion) | |
226 |
|
224 | |||
227 | if cache: |
|
225 | if cache: | |
228 |
cache_key = "get_enabled_repo_integrations_ |
|
226 | cache_key = f"get_enabled_repo_integrations_{event.repo.repo_id}" | |
229 | query = query.options( |
|
227 | query = query.options( | |
230 | FromCache("sql_cache_short", cache_key)) |
|
228 | FromCache("sql_cache_short", cache_key)) | |
231 | else: # only global integrations |
|
229 | else: # only global integrations |
@@ -332,6 +332,7 b" EMAIL_COMMENT_FILE_SUBJECT_TEMPLATE = ''" | |||||
332 | import cssutils |
|
332 | import cssutils | |
333 | # hijack css utils logger and replace with ours |
|
333 | # hijack css utils logger and replace with ours | |
334 | log = logging.getLogger('rhodecode.cssutils.premailer') |
|
334 | log = logging.getLogger('rhodecode.cssutils.premailer') | |
|
335 | log.setLevel(logging.INFO) | |||
335 | cssutils.log.setLog(log) |
|
336 | cssutils.log.setLog(log) | |
336 |
|
337 | |||
337 |
|
338 | |||
@@ -377,7 +378,10 b' class EmailNotificationModel(BaseModel):' | |||||
377 | 'rhodecode:templates/email_templates/pull_request_update.mako', |
|
378 | 'rhodecode:templates/email_templates/pull_request_update.mako', | |
378 | } |
|
379 | } | |
379 |
|
380 | |||
380 |
premailer_instance = premailer.Premailer( |
|
381 | premailer_instance = premailer.Premailer( | |
|
382 | #cssutils_logging_handler=log.handlers[0], | |||
|
383 | #cssutils_logging_level=logging.INFO | |||
|
384 | ) | |||
381 |
|
385 | |||
382 | def __init__(self): |
|
386 | def __init__(self): | |
383 | """ |
|
387 | """ |
@@ -180,16 +180,24 b' class PermissionModel(BaseModel):' | |||||
180 |
|
180 | |||
181 | def _make_new_user_perm(self, user, perm_name): |
|
181 | def _make_new_user_perm(self, user, perm_name): | |
182 | log.debug('Creating new user permission:%s', perm_name) |
|
182 | log.debug('Creating new user permission:%s', perm_name) | |
|
183 | new_perm = Permission.get_by_key(perm_name) | |||
|
184 | if not new_perm: | |||
|
185 | raise ValueError(f'permission with name {perm_name} not found') | |||
|
186 | ||||
183 | new = UserToPerm() |
|
187 | new = UserToPerm() | |
184 | new.user = user |
|
188 | new.user = user | |
185 |
new.permission = |
|
189 | new.permission = new_perm | |
186 | return new |
|
190 | return new | |
187 |
|
191 | |||
188 | def _make_new_user_group_perm(self, user_group, perm_name): |
|
192 | def _make_new_user_group_perm(self, user_group, perm_name): | |
189 | log.debug('Creating new user group permission:%s', perm_name) |
|
193 | log.debug('Creating new user group permission:%s', perm_name) | |
|
194 | new_perm = Permission.get_by_key(perm_name) | |||
|
195 | if not new_perm: | |||
|
196 | raise ValueError(f'permission with name {perm_name} not found') | |||
|
197 | ||||
190 | new = UserGroupToPerm() |
|
198 | new = UserGroupToPerm() | |
191 | new.users_group = user_group |
|
199 | new.users_group = user_group | |
192 |
new.permission = |
|
200 | new.permission = new_perm | |
193 | return new |
|
201 | return new | |
194 |
|
202 | |||
195 | def _keep_perm(self, perm_name, keep_fields): |
|
203 | def _keep_perm(self, perm_name, keep_fields): | |
@@ -278,10 +286,10 b' class PermissionModel(BaseModel):' | |||||
278 | raise ValueError('Missing permission for %s' % (_perm_key,)) |
|
286 | raise ValueError('Missing permission for %s' % (_perm_key,)) | |
279 |
|
287 | |||
280 | if obj_type == 'user': |
|
288 | if obj_type == 'user': | |
281 | p = self._make_new_user_perm(object, perm_value) |
|
289 | p = self._make_new_user_perm(to_object, perm_value) | |
282 | self.sa.add(p) |
|
290 | self.sa.add(p) | |
283 | if obj_type == 'user_group': |
|
291 | if obj_type == 'user_group': | |
284 | p = self._make_new_user_group_perm(object, perm_value) |
|
292 | p = self._make_new_user_group_perm(to_object, perm_value) | |
285 | self.sa.add(p) |
|
293 | self.sa.add(p) | |
286 |
|
294 | |||
287 | def _set_new_user_perms(self, user, form_result, preserve=None): |
|
295 | def _set_new_user_perms(self, user, form_result, preserve=None): | |
@@ -321,8 +329,8 b' class PermissionModel(BaseModel):' | |||||
321 | def _get_group(perm_name): |
|
329 | def _get_group(perm_name): | |
322 | return '.'.join(perm_name.split('.')[:1]) |
|
330 | return '.'.join(perm_name.split('.')[:1]) | |
323 |
|
331 | |||
324 | defined_perms_groups = map( |
|
332 | defined_perms_groups = list(map( | |
325 | _get_group, (x.permission.permission_name for x in obj_perms)) |
|
333 | _get_group, (x.permission.permission_name for x in obj_perms))) | |
326 | log.debug('GOT ALREADY DEFINED:%s', obj_perms) |
|
334 | log.debug('GOT ALREADY DEFINED:%s', obj_perms) | |
327 |
|
335 | |||
328 | if force: |
|
336 | if force: |
@@ -23,15 +23,16 b'' | |||||
23 | pull request model for RhodeCode |
|
23 | pull request model for RhodeCode | |
24 | """ |
|
24 | """ | |
25 |
|
25 | |||
26 |
|
||||
27 | import json |
|
|||
28 | import logging |
|
26 | import logging | |
29 | import os |
|
27 | import os | |
30 |
|
28 | |||
31 | import datetime |
|
29 | import datetime | |
32 |
import urllib.request |
|
30 | import urllib.request | |
|
31 | import urllib.parse | |||
|
32 | import urllib.error | |||
33 | import collections |
|
33 | import collections | |
34 |
|
34 | |||
|
35 | import dataclasses as dataclasses | |||
35 | from pyramid.threadlocal import get_current_request |
|
36 | from pyramid.threadlocal import get_current_request | |
36 |
|
37 | |||
37 | from rhodecode.lib.vcs.nodes import FileNode |
|
38 | from rhodecode.lib.vcs.nodes import FileNode | |
@@ -40,11 +41,12 b' from rhodecode.lib import helpers as h, ' | |||||
40 | from rhodecode.lib import audit_logger |
|
41 | from rhodecode.lib import audit_logger | |
41 | from collections import OrderedDict |
|
42 | from collections import OrderedDict | |
42 | from rhodecode.lib.hooks_daemon import prepare_callback_daemon |
|
43 | from rhodecode.lib.hooks_daemon import prepare_callback_daemon | |
|
44 | from rhodecode.lib.ext_json import sjson as json | |||
43 | from rhodecode.lib.markup_renderer import ( |
|
45 | from rhodecode.lib.markup_renderer import ( | |
44 | DEFAULT_COMMENTS_RENDERER, RstTemplateRenderer) |
|
46 | DEFAULT_COMMENTS_RENDERER, RstTemplateRenderer) | |
45 |
from rhodecode.lib.utils |
|
47 | from rhodecode.lib.hash_utils import md5_safe | |
46 | safe_unicode, safe_str, md5_safe, AttributeDict, safe_int, |
|
48 | from rhodecode.lib.str_utils import safe_str | |
47 | get_current_rhodecode_user) |
|
49 | from rhodecode.lib.utils2 import AttributeDict, get_current_rhodecode_user | |
48 | from rhodecode.lib.vcs.backends.base import ( |
|
50 | from rhodecode.lib.vcs.backends.base import ( | |
49 | Reference, MergeResponse, MergeFailureReason, UpdateFailureReason, |
|
51 | Reference, MergeResponse, MergeFailureReason, UpdateFailureReason, | |
50 | TargetRefMissing, SourceRefMissing) |
|
52 | TargetRefMissing, SourceRefMissing) | |
@@ -55,7 +57,7 b' from rhodecode.model import BaseModel' | |||||
55 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
57 | from rhodecode.model.changeset_status import ChangesetStatusModel | |
56 | from rhodecode.model.comment import CommentsModel |
|
58 | from rhodecode.model.comment import CommentsModel | |
57 | from rhodecode.model.db import ( |
|
59 | from rhodecode.model.db import ( | |
58 | aliased, null, lazyload, and_, or_, func, String, cast, PullRequest, PullRequestReviewers, ChangesetStatus, |
|
60 | aliased, null, lazyload, and_, or_, select, func, String, cast, PullRequest, PullRequestReviewers, ChangesetStatus, | |
59 | PullRequestVersion, ChangesetComment, Repository, RepoReviewRule, User) |
|
61 | PullRequestVersion, ChangesetComment, Repository, RepoReviewRule, User) | |
60 | from rhodecode.model.meta import Session |
|
62 | from rhodecode.model.meta import Session | |
61 | from rhodecode.model.notification import NotificationModel, \ |
|
63 | from rhodecode.model.notification import NotificationModel, \ | |
@@ -116,9 +118,8 b' def get_diff_info(' | |||||
116 | source_scm.get_diff(commit1=source_commit, commit2=target_commit, |
|
118 | source_scm.get_diff(commit1=source_commit, commit2=target_commit, | |
117 | ignore_whitespace=False, context=3) |
|
119 | ignore_whitespace=False, context=3) | |
118 |
|
120 | |||
119 | diff_processor = diffs.DiffProcessor( |
|
121 | diff_processor = diffs.DiffProcessor(vcs_diff, diff_format='newdiff', | |
120 | vcs_diff, format='newdiff', diff_limit=None, |
|
122 | diff_limit=0, file_limit=0, show_full_diff=True) | |
121 | file_limit=None, show_full_diff=True) |
|
|||
122 |
|
123 | |||
123 | _parsed = diff_processor.prepare() |
|
124 | _parsed = diff_processor.prepare() | |
124 |
|
125 | |||
@@ -317,7 +318,7 b' class PullRequestModel(BaseModel):' | |||||
317 | q = PullRequest.query() |
|
318 | q = PullRequest.query() | |
318 |
|
319 | |||
319 | if search_q: |
|
320 | if search_q: | |
320 |
like_expression = u'%{}%'.format(safe_ |
|
321 | like_expression = u'%{}%'.format(safe_str(search_q)) | |
321 | q = q.join(User, User.user_id == PullRequest.user_id) |
|
322 | q = q.join(User, User.user_id == PullRequest.user_id) | |
322 | q = q.filter(or_( |
|
323 | q = q.filter(or_( | |
323 | cast(PullRequest.pull_request_id, String).ilike(like_expression), |
|
324 | cast(PullRequest.pull_request_id, String).ilike(like_expression), | |
@@ -489,7 +490,7 b' class PullRequestModel(BaseModel):' | |||||
489 | q = q.filter(pull_request_alias.status.in_(statuses)) |
|
490 | q = q.filter(pull_request_alias.status.in_(statuses)) | |
490 |
|
491 | |||
491 | if search_q: |
|
492 | if search_q: | |
492 |
like_expression = u'%{}%'.format(safe_ |
|
493 | like_expression = u'%{}%'.format(safe_str(search_q)) | |
493 | q = q.join(User, User.user_id == pull_request_alias.user_id) |
|
494 | q = q.join(User, User.user_id == pull_request_alias.user_id) | |
494 | q = q.filter(or_( |
|
495 | q = q.filter(or_( | |
495 | cast(pull_request_alias.pull_request_id, String).ilike(like_expression), |
|
496 | cast(pull_request_alias.pull_request_id, String).ilike(like_expression), | |
@@ -562,12 +563,14 b' class PullRequestModel(BaseModel):' | |||||
562 | """ |
|
563 | """ | |
563 | q = PullRequest.query() |
|
564 | q = PullRequest.query() | |
564 | if user_id: |
|
565 | if user_id: | |
565 | reviewers_subquery = Session().query( |
|
566 | ||
566 |
|
|
567 | base_query = select(PullRequestReviewers)\ | |
567 |
PullRequestReviewers.user_id == user_id) |
|
568 | .where(PullRequestReviewers.user_id == user_id)\ | |
|
569 | .with_only_columns(PullRequestReviewers.pull_request_id) | |||
|
570 | ||||
568 | user_filter = or_( |
|
571 | user_filter = or_( | |
569 | PullRequest.user_id == user_id, |
|
572 | PullRequest.user_id == user_id, | |
570 |
PullRequest.pull_request_id.in_( |
|
573 | PullRequest.pull_request_id.in_(base_query) | |
571 | ) |
|
574 | ) | |
572 | q = PullRequest.query().filter(user_filter) |
|
575 | q = PullRequest.query().filter(user_filter) | |
573 |
|
576 | |||
@@ -576,7 +579,7 b' class PullRequestModel(BaseModel):' | |||||
576 | q = q.filter(PullRequest.status.in_(statuses)) |
|
579 | q = q.filter(PullRequest.status.in_(statuses)) | |
577 |
|
580 | |||
578 | if query: |
|
581 | if query: | |
579 |
like_expression = u'%{}%'.format(safe_ |
|
582 | like_expression = u'%{}%'.format(safe_str(query)) | |
580 | q = q.join(User, User.user_id == PullRequest.user_id) |
|
583 | q = q.join(User, User.user_id == PullRequest.user_id) | |
581 | q = q.filter(or_( |
|
584 | q = q.filter(or_( | |
582 | cast(PullRequest.pull_request_id, String).ilike(like_expression), |
|
585 | cast(PullRequest.pull_request_id, String).ilike(like_expression), | |
@@ -656,7 +659,7 b' class PullRequestModel(BaseModel):' | |||||
656 | q = q.filter(pull_request_alias.status.in_(statuses)) |
|
659 | q = q.filter(pull_request_alias.status.in_(statuses)) | |
657 |
|
660 | |||
658 | if query: |
|
661 | if query: | |
659 |
like_expression = u'%{}%'.format(safe_ |
|
662 | like_expression = u'%{}%'.format(safe_str(query)) | |
660 | q = q.join(User, User.user_id == pull_request_alias.user_id) |
|
663 | q = q.join(User, User.user_id == pull_request_alias.user_id) | |
661 | q = q.filter(or_( |
|
664 | q = q.filter(or_( | |
662 | cast(pull_request_alias.pull_request_id, String).ilike(like_expression), |
|
665 | cast(pull_request_alias.pull_request_id, String).ilike(like_expression), | |
@@ -939,7 +942,8 b' class PullRequestModel(BaseModel):' | |||||
939 |
|
942 | |||
940 | def merge_repo(self, pull_request, user, extras): |
|
943 | def merge_repo(self, pull_request, user, extras): | |
941 | repo_type = pull_request.source_repo.repo_type |
|
944 | repo_type = pull_request.source_repo.repo_type | |
942 |
log.debug("Merging pull request %s", pull_request |
|
945 | log.debug("Merging pull request %s", pull_request) | |
|
946 | ||||
943 | extras['user_agent'] = '{}/internal-merge'.format(repo_type) |
|
947 | extras['user_agent'] = '{}/internal-merge'.format(repo_type) | |
944 | merge_state = self._merge_pull_request(pull_request, user, extras) |
|
948 | merge_state = self._merge_pull_request(pull_request, user, extras) | |
945 | if merge_state.executed: |
|
949 | if merge_state.executed: | |
@@ -952,14 +956,14 b' class PullRequestModel(BaseModel):' | |||||
952 | user, pull_request) |
|
956 | user, pull_request) | |
953 |
|
957 | |||
954 | else: |
|
958 | else: | |
955 | log.warn("Merge failed, not updating the pull request.") |
|
959 | log.warning("Merge failed, not updating the pull request.") | |
956 | return merge_state |
|
960 | return merge_state | |
957 |
|
961 | |||
958 | def _merge_pull_request(self, pull_request, user, extras, merge_msg=None): |
|
962 | def _merge_pull_request(self, pull_request, user, extras, merge_msg=None): | |
959 | target_vcs = pull_request.target_repo.scm_instance() |
|
963 | target_vcs = pull_request.target_repo.scm_instance() | |
960 | source_vcs = pull_request.source_repo.scm_instance() |
|
964 | source_vcs = pull_request.source_repo.scm_instance() | |
961 |
|
965 | |||
962 |
message = safe_ |
|
966 | message = safe_str(merge_msg or vcs_settings.MERGE_MESSAGE_TMPL).format( | |
963 | pr_id=pull_request.pull_request_id, |
|
967 | pr_id=pull_request.pull_request_id, | |
964 | pr_title=pull_request.title, |
|
968 | pr_title=pull_request.title, | |
965 | pr_desc=pull_request.description, |
|
969 | pr_desc=pull_request.description, | |
@@ -995,6 +999,7 b' class PullRequestModel(BaseModel):' | |||||
995 | user_name=user_name, user_email=user.email, |
|
999 | user_name=user_name, user_email=user.email, | |
996 | message=message, use_rebase=use_rebase, |
|
1000 | message=message, use_rebase=use_rebase, | |
997 | close_branch=close_branch) |
|
1001 | close_branch=close_branch) | |
|
1002 | ||||
998 | return merge_state |
|
1003 | return merge_state | |
999 |
|
1004 | |||
1000 | def _comment_and_close_pr(self, pull_request, user, merge_state, close_msg=None): |
|
1005 | def _comment_and_close_pr(self, pull_request, user, merge_state, close_msg=None): | |
@@ -1003,7 +1008,7 b' class PullRequestModel(BaseModel):' | |||||
1003 | close_msg = close_msg or 'Pull request merged and closed' |
|
1008 | close_msg = close_msg or 'Pull request merged and closed' | |
1004 |
|
1009 | |||
1005 | CommentsModel().create( |
|
1010 | CommentsModel().create( | |
1006 |
text=safe_ |
|
1011 | text=safe_str(close_msg), | |
1007 | repo=pull_request.target_repo.repo_id, |
|
1012 | repo=pull_request.target_repo.repo_id, | |
1008 | user=user.user_id, |
|
1013 | user=user.user_id, | |
1009 | pull_request=pull_request.pull_request_id, |
|
1014 | pull_request=pull_request.pull_request_id, | |
@@ -1289,9 +1294,10 b' class PullRequestModel(BaseModel):' | |||||
1289 | source_repo, source_ref_id, target_ref_id, |
|
1294 | source_repo, source_ref_id, target_ref_id, | |
1290 | hide_whitespace_changes=hide_whitespace_changes, diff_context=diff_context) |
|
1295 | hide_whitespace_changes=hide_whitespace_changes, diff_context=diff_context) | |
1291 |
|
1296 | |||
1292 | old_diff_data = diffs.DiffProcessor(old_diff) |
|
1297 | # NOTE: this was using diff_format='gitdiff' | |
|
1298 | old_diff_data = diffs.DiffProcessor(old_diff, diff_format='newdiff') | |||
1293 | old_diff_data.prepare() |
|
1299 | old_diff_data.prepare() | |
1294 | new_diff_data = diffs.DiffProcessor(new_diff) |
|
1300 | new_diff_data = diffs.DiffProcessor(new_diff, diff_format='newdiff') | |
1295 | new_diff_data.prepare() |
|
1301 | new_diff_data.prepare() | |
1296 |
|
1302 | |||
1297 | return old_diff_data, new_diff_data |
|
1303 | return old_diff_data, new_diff_data | |
@@ -1598,7 +1604,7 b' class PullRequestModel(BaseModel):' | |||||
1598 | return None |
|
1604 | return None | |
1599 | else: |
|
1605 | else: | |
1600 | pr_url = urllib.parse.unquote(self.get_url(pull_request, request=request)) |
|
1606 | pr_url = urllib.parse.unquote(self.get_url(pull_request, request=request)) | |
1601 |
return safe_ |
|
1607 | return safe_str('{pr_url}/repository'.format(pr_url=pr_url)) | |
1602 |
|
1608 | |||
1603 | def _notify_reviewers(self, pull_request, user_ids, role, user): |
|
1609 | def _notify_reviewers(self, pull_request, user_ids, role, user): | |
1604 | # notification to reviewers/observers |
|
1610 | # notification to reviewers/observers | |
@@ -2032,8 +2038,8 b' class PullRequestModel(BaseModel):' | |||||
2032 | _ = translator or get_current_request().translate |
|
2038 | _ = translator or get_current_request().translate | |
2033 |
|
2039 | |||
2034 | commit_id = safe_str(commit_id) if commit_id else None |
|
2040 | commit_id = safe_str(commit_id) if commit_id else None | |
2035 |
branch = safe_ |
|
2041 | branch = safe_str(branch) if branch else None | |
2036 |
bookmark = safe_ |
|
2042 | bookmark = safe_str(bookmark) if bookmark else None | |
2037 |
|
2043 | |||
2038 | selected = None |
|
2044 | selected = None | |
2039 |
|
2045 | |||
@@ -2072,8 +2078,8 b' class PullRequestModel(BaseModel):' | |||||
2072 | u'No commit refs could be found matching: {}'.format(ref)) |
|
2078 | u'No commit refs could be found matching: {}'.format(ref)) | |
2073 | elif repo.DEFAULT_BRANCH_NAME in repo.branches: |
|
2079 | elif repo.DEFAULT_BRANCH_NAME in repo.branches: | |
2074 | selected = u'branch:{}:{}'.format( |
|
2080 | selected = u'branch:{}:{}'.format( | |
2075 |
safe_ |
|
2081 | safe_str(repo.DEFAULT_BRANCH_NAME), | |
2076 |
safe_ |
|
2082 | safe_str(repo.branches[repo.DEFAULT_BRANCH_NAME]) | |
2077 | ) |
|
2083 | ) | |
2078 | elif repo.commit_ids: |
|
2084 | elif repo.commit_ids: | |
2079 | # make the user select in this case |
|
2085 | # make the user select in this case | |
@@ -2113,7 +2119,7 b' class PullRequestModel(BaseModel):' | |||||
2113 | log.debug('calculating diff between ' |
|
2119 | log.debug('calculating diff between ' | |
2114 | 'source_ref:%s and target_ref:%s for repo `%s`', |
|
2120 | 'source_ref:%s and target_ref:%s for repo `%s`', | |
2115 | target_ref_id, source_ref_id, |
|
2121 | target_ref_id, source_ref_id, | |
2116 |
safe_ |
|
2122 | safe_str(vcs_repo.path)) | |
2117 |
|
2123 | |||
2118 | vcs_diff = vcs_repo.get_diff( |
|
2124 | vcs_diff = vcs_repo.get_diff( | |
2119 | commit1=target_commit, commit2=source_commit, |
|
2125 | commit1=target_commit, commit2=source_commit, | |
@@ -2373,8 +2379,16 b' class MergeCheck(object):' | |||||
2373 | return merge_details |
|
2379 | return merge_details | |
2374 |
|
2380 | |||
2375 |
|
2381 | |||
2376 | ChangeTuple = collections.namedtuple( |
|
2382 | @dataclasses.dataclass | |
2377 | 'ChangeTuple', ['added', 'common', 'removed', 'total']) |
|
2383 | class ChangeTuple: | |
|
2384 | added: list | |||
|
2385 | common: list | |||
|
2386 | removed: list | |||
|
2387 | total: list | |||
2378 |
|
2388 | |||
2379 | FileChangeTuple = collections.namedtuple( |
|
2389 | ||
2380 | 'FileChangeTuple', ['added', 'modified', 'removed']) |
|
2390 | @dataclasses.dataclass | |
|
2391 | class FileChangeTuple: | |||
|
2392 | added: list | |||
|
2393 | modified: list | |||
|
2394 | removed: list |
@@ -26,6 +26,7 b' import traceback' | |||||
26 | import datetime |
|
26 | import datetime | |
27 |
|
27 | |||
28 | from pyramid.threadlocal import get_current_request |
|
28 | from pyramid.threadlocal import get_current_request | |
|
29 | from sqlalchemy.orm import aliased | |||
29 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
30 | from zope.cachedescriptors.property import Lazy as LazyProperty | |
30 |
|
31 | |||
31 | from rhodecode import events |
|
32 | from rhodecode import events | |
@@ -36,7 +37,7 b' from rhodecode.lib import hooks_base' | |||||
36 | from rhodecode.lib.user_log_filter import user_log_filter |
|
37 | from rhodecode.lib.user_log_filter import user_log_filter | |
37 | from rhodecode.lib.utils import make_db_config |
|
38 | from rhodecode.lib.utils import make_db_config | |
38 | from rhodecode.lib.utils2 import ( |
|
39 | from rhodecode.lib.utils2 import ( | |
39 |
safe_str |
|
40 | safe_str, remove_prefix, obfuscate_url_pw, | |
40 | get_current_rhodecode_user, safe_int, action_logger_generic) |
|
41 | get_current_rhodecode_user, safe_int, action_logger_generic) | |
41 | from rhodecode.lib.vcs.backends import get_backend |
|
42 | from rhodecode.lib.vcs.backends import get_backend | |
42 | from rhodecode.model import BaseModel |
|
43 | from rhodecode.model import BaseModel | |
@@ -78,7 +79,7 b' class RepoModel(BaseModel):' | |||||
78 | repo_to_perm.permission = Permission.get_by_key(default_perm) |
|
79 | repo_to_perm.permission = Permission.get_by_key(default_perm) | |
79 |
|
80 | |||
80 | repo_to_perm.repository = repository |
|
81 | repo_to_perm.repository = repository | |
81 |
repo_to_perm.user |
|
82 | repo_to_perm.user = def_user | |
82 |
|
83 | |||
83 | return repo_to_perm |
|
84 | return repo_to_perm | |
84 |
|
85 | |||
@@ -112,7 +113,7 b' class RepoModel(BaseModel):' | |||||
112 | def _extract_id_from_repo_name(self, repo_name): |
|
113 | def _extract_id_from_repo_name(self, repo_name): | |
113 | if repo_name.startswith('/'): |
|
114 | if repo_name.startswith('/'): | |
114 | repo_name = repo_name.lstrip('/') |
|
115 | repo_name = repo_name.lstrip('/') | |
115 |
by_id_match = re.match(r'^_(\d |
|
116 | by_id_match = re.match(r'^_(\d+)', repo_name) | |
116 | if by_id_match: |
|
117 | if by_id_match: | |
117 | return by_id_match.groups()[0] |
|
118 | return by_id_match.groups()[0] | |
118 |
|
119 | |||
@@ -138,7 +139,7 b' class RepoModel(BaseModel):' | |||||
138 |
|
139 | |||
139 | def get_repos_for_root(self, root, traverse=False): |
|
140 | def get_repos_for_root(self, root, traverse=False): | |
140 | if traverse: |
|
141 | if traverse: | |
141 |
like_expression = u'{}%'.format(safe_ |
|
142 | like_expression = u'{}%'.format(safe_str(root)) | |
142 | repos = Repository.query().filter( |
|
143 | repos = Repository.query().filter( | |
143 | Repository.repo_name.like(like_expression)).all() |
|
144 | Repository.repo_name.like(like_expression)).all() | |
144 | else: |
|
145 | else: | |
@@ -209,12 +210,12 b' class RepoModel(BaseModel):' | |||||
209 | def quick_menu(repo_name): |
|
210 | def quick_menu(repo_name): | |
210 | return _render('quick_menu', repo_name) |
|
211 | return _render('quick_menu', repo_name) | |
211 |
|
212 | |||
212 |
def repo_lnk(name, rtype, rstate, private, archived, fork_ |
|
213 | def repo_lnk(name, rtype, rstate, private, archived, fork_repo_name): | |
213 | if short_name is not None: |
|
214 | if short_name is not None: | |
214 | short_name_var = short_name |
|
215 | short_name_var = short_name | |
215 | else: |
|
216 | else: | |
216 | short_name_var = not admin |
|
217 | short_name_var = not admin | |
217 |
return _render('repo_name', name, rtype, rstate, private, archived, fork_ |
|
218 | return _render('repo_name', name, rtype, rstate, private, archived, fork_repo_name, | |
218 | short_name=short_name_var, admin=False) |
|
219 | short_name=short_name_var, admin=False) | |
219 |
|
220 | |||
220 | def last_change(last_change): |
|
221 | def last_change(last_change): | |
@@ -259,7 +260,7 b' class RepoModel(BaseModel):' | |||||
259 | "menu": quick_menu(repo.repo_name), |
|
260 | "menu": quick_menu(repo.repo_name), | |
260 |
|
261 | |||
261 | "name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state, |
|
262 | "name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state, | |
262 | repo.private, repo.archived, repo.fork), |
|
263 | repo.private, repo.archived, repo.fork_repo_name), | |
263 |
|
264 | |||
264 | "desc": desc(h.escape(repo.description)), |
|
265 | "desc": desc(h.escape(repo.description)), | |
265 |
|
266 | |||
@@ -268,7 +269,7 b' class RepoModel(BaseModel):' | |||||
268 | "last_changeset": last_rev(repo.repo_name, changeset_cache), |
|
269 | "last_changeset": last_rev(repo.repo_name, changeset_cache), | |
269 | "last_changeset_raw": changeset_cache.get('revision'), |
|
270 | "last_changeset_raw": changeset_cache.get('revision'), | |
270 |
|
271 | |||
271 |
"owner": user_profile(repo. |
|
272 | "owner": user_profile(repo.owner_username), | |
272 |
|
273 | |||
273 | "state": state(repo.repo_state), |
|
274 | "state": state(repo.repo_state), | |
274 | "rss": rss_lnk(repo.repo_name), |
|
275 | "rss": rss_lnk(repo.repo_name), | |
@@ -309,6 +310,8 b' class RepoModel(BaseModel):' | |||||
309 | ) \ |
|
310 | ) \ | |
310 | .count() |
|
311 | .count() | |
311 |
|
312 | |||
|
313 | RepoFork = aliased(Repository) | |||
|
314 | OwnerUser = aliased(User) | |||
312 | base_q = Session.query( |
|
315 | base_q = Session.query( | |
313 | Repository.repo_id, |
|
316 | Repository.repo_id, | |
314 | Repository.repo_name, |
|
317 | Repository.repo_name, | |
@@ -317,18 +320,18 b' class RepoModel(BaseModel):' | |||||
317 | Repository.repo_state, |
|
320 | Repository.repo_state, | |
318 | Repository.private, |
|
321 | Repository.private, | |
319 | Repository.archived, |
|
322 | Repository.archived, | |
320 | Repository.fork, |
|
|||
321 | Repository.updated_on, |
|
323 | Repository.updated_on, | |
322 | Repository._changeset_cache, |
|
324 | Repository._changeset_cache, | |
323 | User, |
|
325 | RepoFork.repo_name.label('fork_repo_name'), | |
|
326 | OwnerUser.username.label('owner_username'), | |||
324 | ) \ |
|
327 | ) \ | |
325 | .filter(Repository.group_id == repo_group_id) \ |
|
328 | .filter(Repository.group_id == repo_group_id) \ | |
326 | .filter(or_( |
|
329 | .filter(or_( | |
327 | # generate multiple IN to fix limitation problems |
|
330 | # generate multiple IN to fix limitation problems | |
328 | *in_filter_generator(Repository.repo_id, allowed_ids)) |
|
331 | *in_filter_generator(Repository.repo_id, allowed_ids)) | |
329 | ) \ |
|
332 | ) \ | |
330 |
.join( |
|
333 | .outerjoin(RepoFork, Repository.fork_id == RepoFork.repo_id) \ | |
331 | .group_by(Repository, User) |
|
334 | .join(OwnerUser, Repository.user_id == OwnerUser.user_id) | |
332 |
|
335 | |||
333 | repos_data_total_filtered_count = base_q.count() |
|
336 | repos_data_total_filtered_count = base_q.count() | |
334 |
|
337 | |||
@@ -515,8 +518,8 b' class RepoModel(BaseModel):' | |||||
515 | landing_rev = landing_rev or default_landing_ref |
|
518 | landing_rev = landing_rev or default_landing_ref | |
516 |
|
519 | |||
517 | try: |
|
520 | try: | |
518 |
repo_name = safe_ |
|
521 | repo_name = safe_str(repo_name) | |
519 |
description = safe_ |
|
522 | description = safe_str(description) | |
520 | # repo name is just a name of repository |
|
523 | # repo name is just a name of repository | |
521 | # while repo_name_full is a full qualified name that is combined |
|
524 | # while repo_name_full is a full qualified name that is combined | |
522 | # with name and path of group |
|
525 | # with name and path of group | |
@@ -979,14 +982,14 b' class RepoModel(BaseModel):' | |||||
979 |
|
982 | |||
980 | # check if this path is not a repository |
|
983 | # check if this path is not a repository | |
981 | if is_valid_repo(repo_path, self.repos_path): |
|
984 | if is_valid_repo(repo_path, self.repos_path): | |
982 |
raise Exception('This path |
|
985 | raise Exception(f'This path {repo_path} is a valid repository') | |
983 |
|
986 | |||
984 | # check if this path is a group |
|
987 | # check if this path is a group | |
985 | if is_valid_repo_group(repo_path, self.repos_path): |
|
988 | if is_valid_repo_group(repo_path, self.repos_path): | |
986 |
raise Exception('This path |
|
989 | raise Exception(f'This path {repo_path} is a valid group') | |
987 |
|
990 | |||
988 | log.info('creating repo %s in %s from url: `%s`', |
|
991 | log.info('creating repo %s in %s from url: `%s`', | |
989 |
repo_name, safe_ |
|
992 | repo_name, safe_str(repo_path), | |
990 | obfuscate_url_pw(clone_uri)) |
|
993 | obfuscate_url_pw(clone_uri)) | |
991 |
|
994 | |||
992 | backend = get_backend(repo_type) |
|
995 | backend = get_backend(repo_type) | |
@@ -1016,7 +1019,7 b' class RepoModel(BaseModel):' | |||||
1016 | repo.install_hooks() |
|
1019 | repo.install_hooks() | |
1017 |
|
1020 | |||
1018 | log.debug('Created repo %s with %s backend', |
|
1021 | log.debug('Created repo %s with %s backend', | |
1019 |
safe_ |
|
1022 | safe_str(repo_name), safe_str(repo_type)) | |
1020 | return repo |
|
1023 | return repo | |
1021 |
|
1024 | |||
1022 | def _rename_filesystem_repo(self, old, new): |
|
1025 | def _rename_filesystem_repo(self, old, new): | |
@@ -1038,8 +1041,8 b' class RepoModel(BaseModel):' | |||||
1038 |
|
1041 | |||
1039 | def _delete_filesystem_repo(self, repo): |
|
1042 | def _delete_filesystem_repo(self, repo): | |
1040 | """ |
|
1043 | """ | |
1041 |
removes repo from filesystem, the removal is ac |
|
1044 | removes repo from filesystem, the removal is actually made by | |
1042 |
added rm__ prefix into dir, and rename interna |
|
1045 | added rm__ prefix into dir, and rename internal .hg/.git dirs so this | |
1043 | repository is no longer valid for rhodecode, can be undeleted later on |
|
1046 | repository is no longer valid for rhodecode, can be undeleted later on | |
1044 | by reverting the renames on this repository |
|
1047 | by reverting the renames on this repository | |
1045 |
|
1048 | |||
@@ -1047,7 +1050,7 b' class RepoModel(BaseModel):' | |||||
1047 | """ |
|
1050 | """ | |
1048 | rm_path = os.path.join(self.repos_path, repo.repo_name) |
|
1051 | rm_path = os.path.join(self.repos_path, repo.repo_name) | |
1049 | repo_group = repo.group |
|
1052 | repo_group = repo.group | |
1050 |
log.info(" |
|
1053 | log.info("delete_filesystem_repo: removing repository %s", rm_path) | |
1051 | # disable hg/git internal that it doesn't get detected as repo |
|
1054 | # disable hg/git internal that it doesn't get detected as repo | |
1052 | alias = repo.repo_type |
|
1055 | alias = repo.repo_type | |
1053 |
|
1056 | |||
@@ -1094,19 +1097,19 b' class ReadmeFinder:' | |||||
1094 | path_re = re.compile(r'^docs?', re.IGNORECASE) |
|
1097 | path_re = re.compile(r'^docs?', re.IGNORECASE) | |
1095 |
|
1098 | |||
1096 | default_priorities = { |
|
1099 | default_priorities = { | |
1097 | None: 0, |
|
1100 | None: 0, | |
1098 |
'. |
|
1101 | '.rst': 1, | |
1099 |
'. |
|
1102 | '.md': 1, | |
1100 |
'.rst': |
|
1103 | '.rest': 2, | |
1101 |
'. |
|
1104 | '.mkdn': 2, | |
1102 |
'. |
|
1105 | '.text': 2, | |
1103 |
'. |
|
1106 | '.txt': 3, | |
1104 | '.mdown': 3, |
|
1107 | '.mdown': 3, | |
1105 | '.markdown': 4, |
|
1108 | '.markdown': 4, | |
1106 | } |
|
1109 | } | |
1107 |
|
1110 | |||
1108 | path_priority = { |
|
1111 | path_priority = { | |
1109 | 'doc': 0, |
|
1112 | 'doc': 0, | |
1110 | 'docs': 1, |
|
1113 | 'docs': 1, | |
1111 | } |
|
1114 | } | |
1112 |
|
1115 | |||
@@ -1122,7 +1125,7 b' class ReadmeFinder:' | |||||
1122 | self._renderer_extensions = self.RENDERER_TO_EXTENSION.get( |
|
1125 | self._renderer_extensions = self.RENDERER_TO_EXTENSION.get( | |
1123 | default_renderer, []) |
|
1126 | default_renderer, []) | |
1124 |
|
1127 | |||
1125 |
def search(self, commit, path= |
|
1128 | def search(self, commit, path='/'): | |
1126 | """ |
|
1129 | """ | |
1127 | Find a readme in the given `commit`. |
|
1130 | Find a readme in the given `commit`. | |
1128 | """ |
|
1131 | """ |
@@ -131,7 +131,7 b' class RepoGroupModel(BaseModel):' | |||||
131 | repo_group_to_perm.permission = Permission.get_by_key(default_perm) |
|
131 | repo_group_to_perm.permission = Permission.get_by_key(default_perm) | |
132 |
|
132 | |||
133 | repo_group_to_perm.group = new_group |
|
133 | repo_group_to_perm.group = new_group | |
134 |
repo_group_to_perm.user |
|
134 | repo_group_to_perm.user = def_user | |
135 | return repo_group_to_perm |
|
135 | return repo_group_to_perm | |
136 |
|
136 | |||
137 | def _get_group_name_and_parent(self, group_name_full, repo_in_path=False, |
|
137 | def _get_group_name_and_parent(self, group_name_full, repo_in_path=False, | |
@@ -780,10 +780,10 b' class RepoGroupModel(BaseModel):' | |||||
780 | } |
|
780 | } | |
781 | if admin: |
|
781 | if admin: | |
782 | repo_count = group.repositories.count() |
|
782 | repo_count = group.repositories.count() | |
783 | children_groups = map( |
|
783 | children_groups = list(map( | |
784 |
h.safe_ |
|
784 | h.safe_str, | |
785 | itertools.chain((g.name for g in group.parents), |
|
785 | itertools.chain((g.name for g in group.parents), | |
786 | (x.name for x in [group]))) |
|
786 | (x.name for x in [group])))) | |
787 | row.update({ |
|
787 | row.update({ | |
788 | "action": repo_group_actions( |
|
788 | "action": repo_group_actions( | |
789 | group.group_id, group.group_name, repo_count), |
|
789 | group.group_id, group.group_name, repo_count), |
@@ -30,6 +30,7 b' from sqlalchemy import func' | |||||
30 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
30 | from zope.cachedescriptors.property import Lazy as LazyProperty | |
31 |
|
31 | |||
32 | import rhodecode |
|
32 | import rhodecode | |
|
33 | from rhodecode.lib.str_utils import safe_bytes | |||
33 | from rhodecode.lib.vcs import get_backend |
|
34 | from rhodecode.lib.vcs import get_backend | |
34 | from rhodecode.lib.vcs.exceptions import RepositoryError, NodeNotChangedError |
|
35 | from rhodecode.lib.vcs.exceptions import RepositoryError, NodeNotChangedError | |
35 | from rhodecode.lib.vcs.nodes import FileNode |
|
36 | from rhodecode.lib.vcs.nodes import FileNode | |
@@ -42,7 +43,7 b' from rhodecode.lib.exceptions import Non' | |||||
42 | from rhodecode.lib import hooks_utils |
|
43 | from rhodecode.lib import hooks_utils | |
43 | from rhodecode.lib.utils import ( |
|
44 | from rhodecode.lib.utils import ( | |
44 | get_filesystem_repos, make_db_config) |
|
45 | get_filesystem_repos, make_db_config) | |
45 |
from rhodecode.lib.utils |
|
46 | from rhodecode.lib.str_utils import safe_str | |
46 | from rhodecode.lib.system_info import get_system_info |
|
47 | from rhodecode.lib.system_info import get_system_info | |
47 | from rhodecode.model import BaseModel |
|
48 | from rhodecode.model import BaseModel | |
48 | from rhodecode.model.db import ( |
|
49 | from rhodecode.model.db import ( | |
@@ -284,8 +285,7 b' class ScmModel(BaseModel):' | |||||
284 | repo.update_commit_cache(config=config, cs_cache=None) |
|
285 | repo.update_commit_cache(config=config, cs_cache=None) | |
285 | if delete: |
|
286 | if delete: | |
286 | cache_namespace_uid = 'cache_repo.{}'.format(repo_id) |
|
287 | cache_namespace_uid = 'cache_repo.{}'.format(repo_id) | |
287 | rc_cache.clear_cache_namespace( |
|
288 | rc_cache.clear_cache_namespace('cache_repo', cache_namespace_uid, method=rc_cache.CLEAR_INVALIDATE) | |
288 | 'cache_repo', cache_namespace_uid, invalidate=True) |
|
|||
289 |
|
289 | |||
290 | def toggle_following_repo(self, follow_repo_id, user_id): |
|
290 | def toggle_following_repo(self, follow_repo_id, user_id): | |
291 |
|
291 | |||
@@ -443,25 +443,18 b' class ScmModel(BaseModel):' | |||||
443 | raise |
|
443 | raise | |
444 |
|
444 | |||
445 | def commit_change(self, repo, repo_name, commit, user, author, message, |
|
445 | def commit_change(self, repo, repo_name, commit, user, author, message, | |
446 | content, f_path): |
|
446 | content: bytes, f_path: bytes): | |
447 | """ |
|
447 | """ | |
448 | Commits changes |
|
448 | Commits changes | |
449 |
|
||||
450 | :param repo: SCM instance |
|
|||
451 |
|
||||
452 | """ |
|
449 | """ | |
453 | user = self._get_user(user) |
|
450 | user = self._get_user(user) | |
454 |
|
451 | |||
455 | # decoding here will force that we have proper encoded values |
|
|||
456 | # in any other case this will throw exceptions and deny commit |
|
|||
457 | content = safe_str(content) |
|
|||
458 | path = safe_str(f_path) |
|
|||
459 | # message and author needs to be unicode |
|
452 | # message and author needs to be unicode | |
460 | # proper backend should then translate that into required type |
|
453 | # proper backend should then translate that into required type | |
461 |
message = safe_ |
|
454 | message = safe_str(message) | |
462 |
author = safe_ |
|
455 | author = safe_str(author) | |
463 | imc = repo.in_memory_commit |
|
456 | imc = repo.in_memory_commit | |
464 | imc.change(FileNode(path, content, mode=commit.get_file_mode(f_path))) |
|
457 | imc.change(FileNode(f_path, content, mode=commit.get_file_mode(f_path))) | |
465 | try: |
|
458 | try: | |
466 | # TODO: handle pre-push action ! |
|
459 | # TODO: handle pre-push action ! | |
467 | tip = imc.commit( |
|
460 | tip = imc.commit( | |
@@ -480,9 +473,9 b' class ScmModel(BaseModel):' | |||||
480 | repo_name=repo_name, repo_type=repo.alias, commit_ids=[tip.raw_id]) |
|
473 | repo_name=repo_name, repo_type=repo.alias, commit_ids=[tip.raw_id]) | |
481 | return tip |
|
474 | return tip | |
482 |
|
475 | |||
483 | def _sanitize_path(self, f_path): |
|
476 | def _sanitize_path(self, f_path: bytes): | |
484 | if f_path.startswith('/') or f_path.startswith('./') or '../' in f_path: |
|
477 | if f_path.startswith(b'/') or f_path.startswith(b'./') or b'../' in f_path: | |
485 |
raise NonRelativePathError('% |
|
478 | raise NonRelativePathError(b'%b is not an relative path' % f_path) | |
486 | if f_path: |
|
479 | if f_path: | |
487 | f_path = os.path.normpath(f_path) |
|
480 | f_path = os.path.normpath(f_path) | |
488 | return f_path |
|
481 | return f_path | |
@@ -531,15 +524,24 b' class ScmModel(BaseModel):' | |||||
531 | """ |
|
524 | """ | |
532 | _files = list() |
|
525 | _files = list() | |
533 | _dirs = list() |
|
526 | _dirs = list() | |
|
527 | ||||
534 | try: |
|
528 | try: | |
535 | _repo = self._get_repo(repo_name) |
|
529 | _repo = self._get_repo(repo_name) | |
536 | commit = _repo.scm_instance().get_commit(commit_id=commit_id) |
|
530 | commit = _repo.scm_instance().get_commit(commit_id=commit_id) | |
537 | root_path = root_path.lstrip('/') |
|
531 | root_path = root_path.lstrip('/') | |
538 | for __, dirs, files in commit.walk(root_path): |
|
532 | ||
|
533 | # get RootNode, inject pre-load options before walking | |||
|
534 | top_node = commit.get_node(root_path) | |||
|
535 | extended_info_pre_load = [] | |||
|
536 | if extended_info: | |||
|
537 | extended_info_pre_load += ['md5'] | |||
|
538 | top_node.default_pre_load = ['is_binary', 'size'] + extended_info_pre_load | |||
|
539 | ||||
|
540 | for __, dirs, files in commit.walk(top_node): | |||
539 |
|
541 | |||
540 | for f in files: |
|
542 | for f in files: | |
541 | _content = None |
|
543 | _content = None | |
542 |
_data = f_name = f. |
|
544 | _data = f_name = f.str_path | |
543 |
|
545 | |||
544 | if not flat: |
|
546 | if not flat: | |
545 | _data = { |
|
547 | _data = { | |
@@ -561,7 +563,7 b' class ScmModel(BaseModel):' | |||||
561 | and f.size > max_file_bytes) |
|
563 | and f.size > max_file_bytes) | |
562 | full_content = None |
|
564 | full_content = None | |
563 | if not f.is_binary and not over_size_limit: |
|
565 | if not f.is_binary and not over_size_limit: | |
564 |
full_content = |
|
566 | full_content = f.str_content | |
565 |
|
567 | |||
566 | _data.update({ |
|
568 | _data.update({ | |
567 | "content": full_content, |
|
569 | "content": full_content, | |
@@ -569,7 +571,7 b' class ScmModel(BaseModel):' | |||||
569 | _files.append(_data) |
|
571 | _files.append(_data) | |
570 |
|
572 | |||
571 | for d in dirs: |
|
573 | for d in dirs: | |
572 |
_data = d_name = d. |
|
574 | _data = d_name = d.str_path | |
573 | if not flat: |
|
575 | if not flat: | |
574 | _data = { |
|
576 | _data = { | |
575 | "name": h.escape(d_name), |
|
577 | "name": h.escape(d_name), | |
@@ -577,10 +579,10 b' class ScmModel(BaseModel):' | |||||
577 | } |
|
579 | } | |
578 | if extended_info: |
|
580 | if extended_info: | |
579 | _data.update({ |
|
581 | _data.update({ | |
580 |
"md5": |
|
582 | "md5": "", | |
581 |
"binary": |
|
583 | "binary": False, | |
582 |
"size": |
|
584 | "size": 0, | |
583 |
"extension": |
|
585 | "extension": "", | |
584 | }) |
|
586 | }) | |
585 | if content: |
|
587 | if content: | |
586 | _data.update({ |
|
588 | _data.update({ | |
@@ -609,7 +611,7 b' class ScmModel(BaseModel):' | |||||
609 | for f in files: |
|
611 | for f in files: | |
610 |
|
612 | |||
611 | _data = { |
|
613 | _data = { | |
612 |
"name": h.escape(f. |
|
614 | "name": h.escape(f.str_path), | |
613 | "type": "file", |
|
615 | "type": "file", | |
614 | } |
|
616 | } | |
615 |
|
617 | |||
@@ -618,7 +620,7 b' class ScmModel(BaseModel):' | |||||
618 | for d in dirs: |
|
620 | for d in dirs: | |
619 |
|
621 | |||
620 | _data = { |
|
622 | _data = { | |
621 |
"name": h.escape(d. |
|
623 | "name": h.escape(d.str_path), | |
622 | "type": "dir", |
|
624 | "type": "dir", | |
623 | } |
|
625 | } | |
624 |
|
626 | |||
@@ -634,6 +636,7 b' class ScmModel(BaseModel):' | |||||
634 | """ |
|
636 | """ | |
635 | retrieve single node from commit |
|
637 | retrieve single node from commit | |
636 | """ |
|
638 | """ | |
|
639 | ||||
637 | try: |
|
640 | try: | |
638 |
|
641 | |||
639 | _repo = self._get_repo(repo_name) |
|
642 | _repo = self._get_repo(repo_name) | |
@@ -644,7 +647,7 b' class ScmModel(BaseModel):' | |||||
644 | raise RepositoryError('The given path is a directory') |
|
647 | raise RepositoryError('The given path is a directory') | |
645 |
|
648 | |||
646 | _content = None |
|
649 | _content = None | |
647 |
f_name = file_node. |
|
650 | f_name = file_node.str_path | |
648 |
|
651 | |||
649 | file_data = { |
|
652 | file_data = { | |
650 | "name": h.escape(f_name), |
|
653 | "name": h.escape(f_name), | |
@@ -677,7 +680,7 b' class ScmModel(BaseModel):' | |||||
677 | full_content = None |
|
680 | full_content = None | |
678 | all_lines = 0 |
|
681 | all_lines = 0 | |
679 | if not file_node.is_binary and not over_size_limit: |
|
682 | if not file_node.is_binary and not over_size_limit: | |
680 |
full_content = safe_ |
|
683 | full_content = safe_str(file_node.content) | |
681 | all_lines, empty_lines = file_node.count_lines(full_content) |
|
684 | all_lines, empty_lines = file_node.count_lines(full_content) | |
682 |
|
685 | |||
683 | file_data.update({ |
|
686 | file_data.update({ | |
@@ -693,7 +696,7 b' class ScmModel(BaseModel):' | |||||
693 | full_content = None |
|
696 | full_content = None | |
694 | all_lines = 0 |
|
697 | all_lines = 0 | |
695 | if not is_binary and not over_size_limit: |
|
698 | if not is_binary and not over_size_limit: | |
696 |
full_content = safe_ |
|
699 | full_content = safe_str(_content) | |
697 | all_lines, empty_lines = file_node.count_lines(full_content) |
|
700 | all_lines, empty_lines = file_node.count_lines(full_content) | |
698 |
|
701 | |||
699 | file_data.update({ |
|
702 | file_data.update({ | |
@@ -718,12 +721,15 b' class ScmModel(BaseModel):' | |||||
718 | _repo = self._get_repo(repo_name) |
|
721 | _repo = self._get_repo(repo_name) | |
719 | commit = _repo.scm_instance().get_commit(commit_id=commit_id) |
|
722 | commit = _repo.scm_instance().get_commit(commit_id=commit_id) | |
720 | root_path = root_path.lstrip('/') |
|
723 | root_path = root_path.lstrip('/') | |
721 |
|
|
724 | top_node = commit.get_node(root_path) | |
|
725 | top_node.default_pre_load = [] | |||
|
726 | ||||
|
727 | for __, dirs, files in commit.walk(top_node): | |||
722 |
|
728 | |||
723 | for f in files: |
|
729 | for f in files: | |
724 | is_binary, md5, size, _content = f.metadata_uncached() |
|
730 | is_binary, md5, size, _content = f.metadata_uncached() | |
725 | _data = { |
|
731 | _data = { | |
726 |
"name": f. |
|
732 | "name": f.str_path, | |
727 | "md5": md5, |
|
733 | "md5": md5, | |
728 | "extension": f.extension, |
|
734 | "extension": f.extension, | |
729 | "binary": is_binary, |
|
735 | "binary": is_binary, | |
@@ -759,26 +765,9 b' class ScmModel(BaseModel):' | |||||
759 | user = self._get_user(user) |
|
765 | user = self._get_user(user) | |
760 | scm_instance = repo.scm_instance(cache=False) |
|
766 | scm_instance = repo.scm_instance(cache=False) | |
761 |
|
767 | |||
762 | processed_nodes = [] |
|
768 | message = safe_str(message) | |
763 | for f_path in nodes: |
|
|||
764 | f_path = self._sanitize_path(f_path) |
|
|||
765 | content = nodes[f_path]['content'] |
|
|||
766 | f_path = safe_str(f_path) |
|
|||
767 | # decoding here will force that we have proper encoded values |
|
|||
768 | # in any other case this will throw exceptions and deny commit |
|
|||
769 | if isinstance(content, (str,)): |
|
|||
770 | content = safe_str(content) |
|
|||
771 | elif isinstance(content, (file, cStringIO.OutputType,)): |
|
|||
772 | content = content.read() |
|
|||
773 | else: |
|
|||
774 | raise Exception('Content is of unrecognized type %s' % ( |
|
|||
775 | type(content) |
|
|||
776 | )) |
|
|||
777 | processed_nodes.append((f_path, content)) |
|
|||
778 |
|
||||
779 | message = safe_unicode(message) |
|
|||
780 | commiter = user.full_contact |
|
769 | commiter = user.full_contact | |
781 |
author = safe_ |
|
770 | author = safe_str(author) if author else commiter | |
782 |
|
771 | |||
783 | imc = scm_instance.in_memory_commit |
|
772 | imc = scm_instance.in_memory_commit | |
784 |
|
773 | |||
@@ -786,13 +775,39 b' class ScmModel(BaseModel):' | |||||
786 | parent_commit = EmptyCommit(alias=scm_instance.alias) |
|
775 | parent_commit = EmptyCommit(alias=scm_instance.alias) | |
787 |
|
776 | |||
788 | if isinstance(parent_commit, EmptyCommit): |
|
777 | if isinstance(parent_commit, EmptyCommit): | |
789 |
# EmptyCommit means we |
|
778 | # EmptyCommit means we're editing empty repository | |
790 | parents = None |
|
779 | parents = None | |
791 | else: |
|
780 | else: | |
792 | parents = [parent_commit] |
|
781 | parents = [parent_commit] | |
|
782 | ||||
|
783 | upload_file_types = (io.BytesIO, io.BufferedRandom) | |||
|
784 | processed_nodes = [] | |||
|
785 | for filename, content_dict in nodes.items(): | |||
|
786 | if not isinstance(filename, bytes): | |||
|
787 | raise ValueError(f'filename key in nodes needs to be bytes , or {upload_file_types}') | |||
|
788 | content = content_dict['content'] | |||
|
789 | if not isinstance(content, upload_file_types + (bytes,)): | |||
|
790 | raise ValueError('content key value in nodes needs to be bytes') | |||
|
791 | ||||
|
792 | for f_path in nodes: | |||
|
793 | f_path = self._sanitize_path(f_path) | |||
|
794 | content = nodes[f_path]['content'] | |||
|
795 | ||||
|
796 | # decoding here will force that we have proper encoded values | |||
|
797 | # in any other case this will throw exceptions and deny commit | |||
|
798 | ||||
|
799 | if isinstance(content, bytes): | |||
|
800 | pass | |||
|
801 | elif isinstance(content, upload_file_types): | |||
|
802 | content = content.read() | |||
|
803 | else: | |||
|
804 | raise Exception(f'Content is of unrecognized type {type(content)}, expected {upload_file_types}') | |||
|
805 | processed_nodes.append((f_path, content)) | |||
|
806 | ||||
793 | # add multiple nodes |
|
807 | # add multiple nodes | |
794 | for path, content in processed_nodes: |
|
808 | for path, content in processed_nodes: | |
795 | imc.add(FileNode(path, content=content)) |
|
809 | imc.add(FileNode(path, content=content)) | |
|
810 | ||||
796 | # TODO: handle pre push scenario |
|
811 | # TODO: handle pre push scenario | |
797 | tip = imc.commit(message=message, |
|
812 | tip = imc.commit(message=message, | |
798 | author=author, |
|
813 | author=author, | |
@@ -813,9 +828,9 b' class ScmModel(BaseModel):' | |||||
813 | user = self._get_user(user) |
|
828 | user = self._get_user(user) | |
814 | scm_instance = repo.scm_instance(cache=False) |
|
829 | scm_instance = repo.scm_instance(cache=False) | |
815 |
|
830 | |||
816 |
message = safe_ |
|
831 | message = safe_str(message) | |
817 | commiter = user.full_contact |
|
832 | commiter = user.full_contact | |
818 |
author = safe_ |
|
833 | author = safe_str(author) if author else commiter | |
819 |
|
834 | |||
820 | imc = scm_instance.in_memory_commit |
|
835 | imc = scm_instance.in_memory_commit | |
821 |
|
836 | |||
@@ -897,14 +912,14 b' class ScmModel(BaseModel):' | |||||
897 | processed_nodes = [] |
|
912 | processed_nodes = [] | |
898 | for f_path in nodes: |
|
913 | for f_path in nodes: | |
899 | f_path = self._sanitize_path(f_path) |
|
914 | f_path = self._sanitize_path(f_path) | |
900 |
# content can be empty but for compat |
|
915 | # content can be empty but for compatibility it allows same dicts | |
901 | # structure as add_nodes |
|
916 | # structure as add_nodes | |
902 | content = nodes[f_path].get('content') |
|
917 | content = nodes[f_path].get('content') | |
903 | processed_nodes.append((f_path, content)) |
|
918 | processed_nodes.append((safe_bytes(f_path), content)) | |
904 |
|
919 | |||
905 |
message = safe_ |
|
920 | message = safe_str(message) | |
906 | commiter = user.full_contact |
|
921 | commiter = user.full_contact | |
907 |
author = safe_ |
|
922 | author = safe_str(author) if author else commiter | |
908 |
|
923 | |||
909 | imc = scm_instance.in_memory_commit |
|
924 | imc = scm_instance.in_memory_commit | |
910 |
|
925 | |||
@@ -994,7 +1009,7 b' class ScmModel(BaseModel):' | |||||
994 | choices = [default_landing_ref] |
|
1009 | choices = [default_landing_ref] | |
995 |
|
1010 | |||
996 | # branches |
|
1011 | # branches | |
997 |
branch_group = [( |
|
1012 | branch_group = [(f'branch:{safe_str(b)}', safe_str(b)) for b in repo.branches] | |
998 | if not branch_group: |
|
1013 | if not branch_group: | |
999 | # new repo, or without maybe a branch? |
|
1014 | # new repo, or without maybe a branch? | |
1000 | branch_group = default_ref_options |
|
1015 | branch_group = default_ref_options | |
@@ -1006,7 +1021,7 b' class ScmModel(BaseModel):' | |||||
1006 | # bookmarks for HG |
|
1021 | # bookmarks for HG | |
1007 | if repo.alias == 'hg': |
|
1022 | if repo.alias == 'hg': | |
1008 | bookmarks_group = ( |
|
1023 | bookmarks_group = ( | |
1009 |
[( |
|
1024 | [(f'book:{safe_str(b)}', safe_str(b)) | |
1010 | for b in repo.bookmarks], |
|
1025 | for b in repo.bookmarks], | |
1011 | _("Bookmarks")) |
|
1026 | _("Bookmarks")) | |
1012 | ref_options.append(bookmarks_group) |
|
1027 | ref_options.append(bookmarks_group) | |
@@ -1014,7 +1029,7 b' class ScmModel(BaseModel):' | |||||
1014 |
|
1029 | |||
1015 | # tags |
|
1030 | # tags | |
1016 | tags_group = ( |
|
1031 | tags_group = ( | |
1017 |
[( |
|
1032 | [(f'tag:{safe_str(t)}', safe_str(t)) | |
1018 | for t in repo.tags], |
|
1033 | for t in repo.tags], | |
1019 | _("Tags")) |
|
1034 | _("Tags")) | |
1020 | ref_options.append(tags_group) |
|
1035 | ref_options.append(tags_group) |
@@ -19,16 +19,16 b'' | |||||
19 |
|
19 | |||
20 | import os |
|
20 | import os | |
21 | import re |
|
21 | import re | |
22 | import hashlib |
|
|||
23 | import logging |
|
22 | import logging | |
24 | import time |
|
23 | import time | |
25 | import functools |
|
24 | import functools | |
26 | import bleach |
|
25 | import bleach | |
27 | from collections import namedtuple |
|
26 | from collections import namedtuple | |
28 |
|
27 | |||
29 |
from pyramid.threadlocal import get_current_request |
|
28 | from pyramid.threadlocal import get_current_request | |
30 |
|
29 | |||
31 | from rhodecode.lib import rc_cache |
|
30 | from rhodecode.lib import rc_cache | |
|
31 | from rhodecode.lib.hash_utils import sha1_safe | |||
32 | from rhodecode.lib.utils2 import ( |
|
32 | from rhodecode.lib.utils2 import ( | |
33 | Optional, AttributeDict, safe_str, remove_prefix, str2bool) |
|
33 | Optional, AttributeDict, safe_str, remove_prefix, str2bool) | |
34 | from rhodecode.lib.vcs.backends import base |
|
34 | from rhodecode.lib.vcs.backends import base | |
@@ -132,10 +132,9 b' class SettingsModel(BaseModel):' | |||||
132 | if not key: |
|
132 | if not key: | |
133 | # keys are unique so they need appended info |
|
133 | # keys are unique so they need appended info | |
134 | if self.repo: |
|
134 | if self.repo: | |
135 | key = hashlib.sha1( |
|
135 | key = sha1_safe(f'{section}{val}{repository_id}') | |
136 | '{}{}{}'.format(section, val, repository_id)).hexdigest() |
|
|||
137 | else: |
|
136 | else: | |
138 |
key = |
|
137 | key = sha1_safe(f'{section}{val}') | |
139 |
|
138 | |||
140 | new_ui.ui_key = key |
|
139 | new_ui.ui_key = key | |
141 |
|
140 | |||
@@ -212,30 +211,20 b' class SettingsModel(BaseModel):' | |||||
212 |
|
211 | |||
213 | def get_cache_region(self): |
|
212 | def get_cache_region(self): | |
214 | repo = self._get_repo(self.repo) if self.repo else None |
|
213 | repo = self._get_repo(self.repo) if self.repo else None | |
215 |
cache_key = "repo.{ |
|
214 | cache_key = f"repo.{repo.repo_id}" if repo else "repo.ALL" | |
216 |
cache_namespace_uid = 'cache_settings.{}' |
|
215 | cache_namespace_uid = f'cache_settings.{cache_key}' | |
217 | region = rc_cache.get_or_create_region('cache_general', cache_namespace_uid) |
|
216 | region = rc_cache.get_or_create_region('cache_general', cache_namespace_uid) | |
218 |
return region, cache_ |
|
217 | return region, cache_namespace_uid | |
219 |
|
||||
220 | def invalidate_settings_cache(self): |
|
|||
221 | region, cache_key = self.get_cache_region() |
|
|||
222 | log.debug('Invalidation cache region %s for cache_key: %s', region, cache_key) |
|
|||
223 | region.invalidate() |
|
|||
224 |
|
218 | |||
225 |
def |
|
219 | def invalidate_settings_cache(self, hard=False): | |
226 | # defines if we use GLOBAL, or PER_REPO |
|
220 | region, namespace_key = self.get_cache_region() | |
227 | repo = self._get_repo(self.repo) if self.repo else None |
|
221 | log.debug('Invalidation cache [%s] region %s for cache_key: %s', | |
|
222 | 'invalidate_settings_cache', region, namespace_key) | |||
228 |
|
223 | |||
229 | # initially try the requests context, this is the fastest |
|
224 | # we use hard cleanup if invalidation is sent | |
230 | # we only fetch global config |
|
225 | rc_cache.clear_cache_namespace(region, namespace_key, method=rc_cache.CLEAR_DELETE) | |
231 | if from_request: |
|
|||
232 | request = get_current_request() |
|
|||
233 |
|
226 | |||
234 | if request and not repo and hasattr(request, 'call_context') and hasattr(request.call_context, 'rc_config'): |
|
227 | def get_cache_call_method(self, cache=True): | |
235 | rc_config = request.call_context.rc_config |
|
|||
236 | if rc_config: |
|
|||
237 | return rc_config |
|
|||
238 |
|
||||
239 | region, cache_key = self.get_cache_region() |
|
228 | region, cache_key = self.get_cache_region() | |
240 |
|
229 | |||
241 | @region.conditional_cache_on_arguments(condition=cache) |
|
230 | @region.conditional_cache_on_arguments(condition=cache) | |
@@ -245,10 +234,28 b' class SettingsModel(BaseModel):' | |||||
245 | raise Exception('Could not get application settings !') |
|
234 | raise Exception('Could not get application settings !') | |
246 |
|
235 | |||
247 | settings = { |
|
236 | settings = { | |
248 |
'rhodecode_ |
|
237 | f'rhodecode_{res.app_settings_name}': res.app_settings_value | |
249 | for res in q |
|
238 | for res in q | |
250 | } |
|
239 | } | |
251 | return settings |
|
240 | return settings | |
|
241 | return _get_all_settings | |||
|
242 | ||||
|
243 | def get_all_settings(self, cache=False, from_request=True): | |||
|
244 | # defines if we use GLOBAL, or PER_REPO | |||
|
245 | repo = self._get_repo(self.repo) if self.repo else None | |||
|
246 | ||||
|
247 | # initially try the requests context, this is the fastest | |||
|
248 | # we only fetch global config, NOT for repo-specific | |||
|
249 | if from_request and not repo: | |||
|
250 | request = get_current_request() | |||
|
251 | ||||
|
252 | if request and hasattr(request, 'call_context') and hasattr(request.call_context, 'rc_config'): | |||
|
253 | rc_config = request.call_context.rc_config | |||
|
254 | if rc_config: | |||
|
255 | return rc_config | |||
|
256 | ||||
|
257 | _region, cache_key = self.get_cache_region() | |||
|
258 | _get_all_settings = self.get_cache_call_method(cache=cache) | |||
252 |
|
259 | |||
253 | start = time.time() |
|
260 | start = time.time() | |
254 | result = _get_all_settings('rhodecode_settings', cache_key) |
|
261 | result = _get_all_settings('rhodecode_settings', cache_key) | |
@@ -318,8 +325,7 b' class SettingsModel(BaseModel):' | |||||
318 | def list_enabled_social_plugins(self, settings): |
|
325 | def list_enabled_social_plugins(self, settings): | |
319 | enabled = [] |
|
326 | enabled = [] | |
320 | for plug in SOCIAL_PLUGINS_LIST: |
|
327 | for plug in SOCIAL_PLUGINS_LIST: | |
321 |
if str2bool(settings.get('rhodecode_auth_{}_enabled' |
|
328 | if str2bool(settings.get(f'rhodecode_auth_{plug}_enabled')): | |
322 | )): |
|
|||
323 | enabled.append(plug) |
|
329 | enabled.append(plug) | |
324 | return enabled |
|
330 | return enabled | |
325 |
|
331 |
@@ -28,6 +28,7 b' from cryptography.hazmat.primitives.asym' | |||||
28 | from cryptography.hazmat.primitives import serialization as crypto_serialization |
|
28 | from cryptography.hazmat.primitives import serialization as crypto_serialization | |
29 | from cryptography.hazmat.backends import default_backend as crypto_default_backend |
|
29 | from cryptography.hazmat.backends import default_backend as crypto_default_backend | |
30 |
|
30 | |||
|
31 | from rhodecode.lib.str_utils import safe_bytes, safe_str | |||
31 | from rhodecode.model import BaseModel |
|
32 | from rhodecode.model import BaseModel | |
32 | from rhodecode.model.db import UserSshKeys |
|
33 | from rhodecode.model.db import UserSshKeys | |
33 | from rhodecode.model.meta import Session |
|
34 | from rhodecode.model.meta import Session | |
@@ -85,10 +86,13 b' class SshKeyModel(BaseModel):' | |||||
85 | crypto_serialization.Encoding.PEM, |
|
86 | crypto_serialization.Encoding.PEM, | |
86 | private_format, |
|
87 | private_format, | |
87 | crypto_serialization.NoEncryption()) |
|
88 | crypto_serialization.NoEncryption()) | |
|
89 | private_key = safe_str(private_key) | |||
|
90 | ||||
88 | public_key = key.public_key().public_bytes( |
|
91 | public_key = key.public_key().public_bytes( | |
89 | crypto_serialization.Encoding.OpenSSH, |
|
92 | crypto_serialization.Encoding.OpenSSH, | |
90 | crypto_serialization.PublicFormat.OpenSSH |
|
93 | crypto_serialization.PublicFormat.OpenSSH | |
91 | ) |
|
94 | ) | |
|
95 | public_key = safe_str(public_key) | |||
92 |
|
96 | |||
93 | if comment: |
|
97 | if comment: | |
94 | public_key = public_key + " " + comment |
|
98 | public_key = public_key + " " + comment |
@@ -19,7 +19,9 b'' | |||||
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 urllib.request |
|
22 | import urllib.request | |
|
23 | import urllib.error | |||
|
24 | import urllib.parse | |||
23 | from packaging.version import Version |
|
25 | from packaging.version import Version | |
24 |
|
26 | |||
25 | import rhodecode |
|
27 | import rhodecode |
@@ -32,8 +32,9 b' from sqlalchemy.exc import DatabaseError' | |||||
32 | from rhodecode import events |
|
32 | from rhodecode import events | |
33 | from rhodecode.lib.user_log_filter import user_log_filter |
|
33 | from rhodecode.lib.user_log_filter import user_log_filter | |
34 | from rhodecode.lib.utils2 import ( |
|
34 | from rhodecode.lib.utils2 import ( | |
35 |
|
|
35 | get_current_rhodecode_user, action_logger_generic, | |
36 | AttributeDict, str2bool) |
|
36 | AttributeDict, str2bool) | |
|
37 | from rhodecode.lib.str_utils import safe_str | |||
37 | from rhodecode.lib.exceptions import ( |
|
38 | from rhodecode.lib.exceptions import ( | |
38 | DefaultUserException, UserOwnsReposException, UserOwnsRepoGroupsException, |
|
39 | DefaultUserException, UserOwnsReposException, UserOwnsRepoGroupsException, | |
39 | UserOwnsUserGroupsException, NotAllowedToCreateUserError, |
|
40 | UserOwnsUserGroupsException, NotAllowedToCreateUserError, | |
@@ -87,7 +88,7 b' class UserModel(BaseModel):' | |||||
87 | query = query.filter(User.active == true()) |
|
88 | query = query.filter(User.active == true()) | |
88 |
|
89 | |||
89 | if name_contains: |
|
90 | if name_contains: | |
90 |
ilike_expression = u'%{}%'.format(safe_ |
|
91 | ilike_expression = u'%{}%'.format(safe_str(name_contains)) | |
91 | query = query.filter( |
|
92 | query = query.filter( | |
92 | or_( |
|
93 | or_( | |
93 | User.name.ilike(ilike_expression), |
|
94 | User.name.ilike(ilike_expression), | |
@@ -358,8 +359,8 b' class UserModel(BaseModel):' | |||||
358 | new_user.admin = admin |
|
359 | new_user.admin = admin | |
359 | new_user.email = email |
|
360 | new_user.email = email | |
360 | new_user.active = active |
|
361 | new_user.active = active | |
361 |
new_user.extern_name = safe_ |
|
362 | new_user.extern_name = safe_str(extern_name) | |
362 |
new_user.extern_type = safe_ |
|
363 | new_user.extern_type = safe_str(extern_type) | |
363 | new_user.name = firstname |
|
364 | new_user.name = firstname | |
364 | new_user.lastname = lastname |
|
365 | new_user.lastname = lastname | |
365 | new_user.description = description |
|
366 | new_user.description = description | |
@@ -533,7 +534,7 b' class UserModel(BaseModel):' | |||||
533 |
|
534 | |||
534 | left_overs = False |
|
535 | left_overs = False | |
535 |
|
536 | |||
536 |
# if nothing is done we have left |
|
537 | # if nothing is done we have leftovers left | |
537 | return left_overs |
|
538 | return left_overs | |
538 |
|
539 | |||
539 | def _handle_user_artifacts(self, username, artifacts, handle_user, |
|
540 | def _handle_user_artifacts(self, username, artifacts, handle_user, | |
@@ -909,8 +910,8 b' class UserModel(BaseModel):' | |||||
909 | ip_range = ip_range.strip() |
|
910 | ip_range = ip_range.strip() | |
910 | if '-' in ip_range: |
|
911 | if '-' in ip_range: | |
911 | start_ip, end_ip = ip_range.split('-', 1) |
|
912 | start_ip, end_ip = ip_range.split('-', 1) | |
912 |
start_ip = ipaddress.ip_address(safe_ |
|
913 | start_ip = ipaddress.ip_address(safe_str(start_ip.strip())) | |
913 |
end_ip = ipaddress.ip_address(safe_ |
|
914 | end_ip = ipaddress.ip_address(safe_str(end_ip.strip())) | |
914 | parsed_ip_range = [] |
|
915 | parsed_ip_range = [] | |
915 |
|
916 | |||
916 | for index in range(int(start_ip), int(end_ip) + 1): |
|
917 | for index in range(int(start_ip), int(end_ip) + 1): |
@@ -21,7 +21,7 b'' | |||||
21 | import logging |
|
21 | import logging | |
22 | import traceback |
|
22 | import traceback | |
23 |
|
23 | |||
24 |
from rhodecode.lib.utils2 import safe_str |
|
24 | from rhodecode.lib.utils2 import safe_str | |
25 | from rhodecode.lib.exceptions import ( |
|
25 | from rhodecode.lib.exceptions import ( | |
26 | UserGroupAssignedException, RepoGroupAssignmentError) |
|
26 | UserGroupAssignedException, RepoGroupAssignmentError) | |
27 | from rhodecode.lib.utils2 import ( |
|
27 | from rhodecode.lib.utils2 import ( | |
@@ -58,7 +58,7 b' class UserGroupModel(BaseModel):' | |||||
58 | user_group_to_perm.permission = Permission.get_by_key(default_perm) |
|
58 | user_group_to_perm.permission = Permission.get_by_key(default_perm) | |
59 |
|
59 | |||
60 | user_group_to_perm.user_group = user_group |
|
60 | user_group_to_perm.user_group = user_group | |
61 |
user_group_to_perm.user |
|
61 | user_group_to_perm.user = def_user | |
62 | return user_group_to_perm |
|
62 | return user_group_to_perm | |
63 |
|
63 | |||
64 | def update_permissions( |
|
64 | def update_permissions( | |
@@ -710,7 +710,7 b' class UserGroupModel(BaseModel):' | |||||
710 | query = query.filter(UserGroup.users_group_active == true()) |
|
710 | query = query.filter(UserGroup.users_group_active == true()) | |
711 |
|
711 | |||
712 | if name_contains: |
|
712 | if name_contains: | |
713 |
ilike_expression = u'%{}%'.format(safe_ |
|
713 | ilike_expression = u'%{}%'.format(safe_str(name_contains)) | |
714 | query = query.filter( |
|
714 | query = query.filter( | |
715 | UserGroup.users_group_name.ilike(ilike_expression))\ |
|
715 | UserGroup.users_group_name.ilike(ilike_expression))\ | |
716 | .order_by(func.length(UserGroup.users_group_name))\ |
|
716 | .order_by(func.length(UserGroup.users_group_name))\ |
General Comments 0
You need to be logged in to leave comments.
Login now