Show More
@@ -0,0 +1,39 | |||||
|
1 | |RCE| 5.5.1 |RNS| | |||
|
2 | ----------------- | |||
|
3 | ||||
|
4 | Release Date | |||
|
5 | ^^^^^^^^^^^^ | |||
|
6 | ||||
|
7 | - TBD | |||
|
8 | ||||
|
9 | New Features | |||
|
10 | ^^^^^^^^^^^^ | |||
|
11 | ||||
|
12 | ||||
|
13 | ||||
|
14 | General | |||
|
15 | ^^^^^^^ | |||
|
16 | ||||
|
17 | ||||
|
18 | Security | |||
|
19 | ^^^^^^^^ | |||
|
20 | ||||
|
21 | - API: changed impersonate features to only be allowed by super-admins instead of repo admins. | |||
|
22 | This applies better practices to this feature of API. | |||
|
23 | ||||
|
24 | Performance | |||
|
25 | ^^^^^^^^^^^ | |||
|
26 | ||||
|
27 | ||||
|
28 | ||||
|
29 | Fixes | |||
|
30 | ^^^^^ | |||
|
31 | ||||
|
32 | - Fixed issues with caches key on windows WSL that were over 255 characters | |||
|
33 | ||||
|
34 | ||||
|
35 | Upgrade notes | |||
|
36 | ^^^^^^^^^^^^^ | |||
|
37 | ||||
|
38 | - RhodeCode 5.5.1 is a planned bugfix release. | |||
|
39 |
@@ -9,6 +9,7 Release Notes | |||||
9 | .. toctree:: |
|
9 | .. toctree:: | |
10 | :maxdepth: 1 |
|
10 | :maxdepth: 1 | |
11 |
|
11 | |||
|
12 | release-notes-5.5.1.rst | |||
12 | release-notes-5.5.0.rst |
|
13 | release-notes-5.5.0.rst | |
13 | release-notes-5.4.2.rst |
|
14 | release-notes-5.4.2.rst | |
14 | release-notes-5.4.1.rst |
|
15 | release-notes-5.4.1.rst |
@@ -91,7 +91,7 class TestClosePullRequest(object): | |||||
91 | ) |
|
91 | ) | |
92 | response = api_call(self.app, params) |
|
92 | response = api_call(self.app, params) | |
93 |
|
93 | |||
94 |
expected = "userid is not the same |
|
94 | expected = "Provided userid is not the same the user calling this function" | |
95 | assert_error(id_, expected, given=response.body) |
|
95 | assert_error(id_, expected, given=response.body) | |
96 |
|
96 | |||
97 | @pytest.mark.backends("git", "hg") |
|
97 | @pytest.mark.backends("git", "hg") |
@@ -234,7 +234,7 class TestCommentPullRequest(object): | |||||
234 | ) |
|
234 | ) | |
235 | response = api_call(self.app, params) |
|
235 | response = api_call(self.app, params) | |
236 |
|
236 | |||
237 |
expected = "userid is not the same |
|
237 | expected = "Provided userid is not the same the user calling this function" | |
238 | assert_error(id_, expected, given=response.body) |
|
238 | assert_error(id_, expected, given=response.body) | |
239 |
|
239 | |||
240 | @pytest.mark.backends("git", "hg") |
|
240 | @pytest.mark.backends("git", "hg") | |
@@ -360,7 +360,7 class TestCommentPullRequest(object): | |||||
360 | userid=TEST_USER_ADMIN_LOGIN, |
|
360 | userid=TEST_USER_ADMIN_LOGIN, | |
361 | ) |
|
361 | ) | |
362 | response = api_call(self.app, params) |
|
362 | response = api_call(self.app, params) | |
363 |
expected = "userid is not the same |
|
363 | expected = "Provided userid is not the same the user calling this function" | |
364 | assert_error(id_, expected, given=response.body) |
|
364 | assert_error(id_, expected, given=response.body) | |
365 |
|
365 | |||
366 | @pytest.mark.backends("git", "hg") |
|
366 | @pytest.mark.backends("git", "hg") |
@@ -263,5 +263,5 class TestMergePullRequest(object): | |||||
263 | ) |
|
263 | ) | |
264 | response = api_call(self.app, params) |
|
264 | response = api_call(self.app, params) | |
265 |
|
265 | |||
266 |
expected = "userid is not the same |
|
266 | expected = "Provided userid is not the same the user calling this function" | |
267 | assert_error(id_, expected, given=response.body) |
|
267 | assert_error(id_, expected, given=response.body) |
@@ -147,7 +147,7 def get_pull_request(request, apiuser, pullrequestid, repoid=Optional(None), mer | |||||
147 | repo = pull_request.target_repo |
|
147 | repo = pull_request.target_repo | |
148 |
|
148 | |||
149 | if not PullRequestModel().check_user_read(pull_request, apiuser, api=True): |
|
149 | if not PullRequestModel().check_user_read(pull_request, apiuser, api=True): | |
150 |
raise JSONRPCError("repository ` |
|
150 | raise JSONRPCError(f"repository `{repoid}` or pull request `{pullrequestid}` does not exist") | |
151 |
|
151 | |||
152 | # NOTE(marcink): only calculate and return merge state if the pr state is 'created' |
|
152 | # NOTE(marcink): only calculate and return merge state if the pr state is 'created' | |
153 | # otherwise we can lock the repo on calculation of merge state while update/merge |
|
153 | # otherwise we can lock the repo on calculation of merge state while update/merge | |
@@ -302,21 +302,19 def merge_pull_request(request, apiuser, pullrequestid, repoid=Optional(None), u | |||||
302 | repo = get_repo_or_error(repoid) |
|
302 | repo = get_repo_or_error(repoid) | |
303 | else: |
|
303 | else: | |
304 | repo = pull_request.target_repo |
|
304 | repo = pull_request.target_repo | |
305 | auth_user = apiuser |
|
|||
306 |
|
305 | |||
|
306 | auth_user = apiuser | |||
307 | if not isinstance(userid, Optional): |
|
307 | if not isinstance(userid, Optional): | |
308 | is_repo_admin = HasRepoPermissionAnyApi("repository.admin")(user=apiuser, repo_name=repo.repo_name) |
|
308 | # super-admin can impersonate other users | |
309 |
if has_superadmin_permission(apiuser) |
|
309 | if has_superadmin_permission(apiuser): | |
310 | apiuser = get_user_or_error(userid) |
|
310 | apiuser = get_user_or_error(userid) | |
311 | auth_user = apiuser.AuthUser() |
|
311 | auth_user = apiuser.AuthUser() | |
312 | else: |
|
312 | else: | |
313 |
raise JSONRPCError("userid is not the same |
|
313 | raise JSONRPCError("Provided userid is not the same the user calling this function") | |
314 |
|
314 | |||
315 | if pull_request.pull_request_state != PullRequest.STATE_CREATED: |
|
315 | if pull_request.pull_request_state != PullRequest.STATE_CREATED: | |
316 | raise JSONRPCError( |
|
316 | raise JSONRPCError( | |
317 |
"Operation forbidden because pull request is in state {}, only state {} is allowed." |
|
317 | f"Operation forbidden because pull request is in state {pull_request.pull_request_state}, only state {PullRequest.STATE_CREATED} is allowed." | |
318 | pull_request.pull_request_state, PullRequest.STATE_CREATED |
|
|||
319 | ) |
|
|||
320 | ) |
|
318 | ) | |
321 |
|
319 | |||
322 | with pull_request.set_state(PullRequest.STATE_UPDATING): |
|
320 | with pull_request.set_state(PullRequest.STATE_UPDATING): | |
@@ -533,20 +531,26 def comment_pull_request( | |||||
533 | repo = pull_request.target_repo |
|
531 | repo = pull_request.target_repo | |
534 |
|
532 | |||
535 | db_repo_name = repo.repo_name |
|
533 | db_repo_name = repo.repo_name | |
|
534 | ||||
536 | auth_user = apiuser |
|
535 | auth_user = apiuser | |
537 |
if |
|
536 | if isinstance(userid, Optional): | |
538 | is_repo_admin = HasRepoPermissionAnyApi("repository.admin")(user=apiuser, repo_name=db_repo_name) |
|
537 | userid = apiuser.user_id | |
539 | if has_superadmin_permission(apiuser) or is_repo_admin: |
|
538 | else: | |
|
539 | # super-admin can impersonate other users | |||
|
540 | if has_superadmin_permission(apiuser): | |||
540 | apiuser = get_user_or_error(userid) |
|
541 | apiuser = get_user_or_error(userid) | |
|
542 | userid = apiuser.user_id | |||
541 | auth_user = apiuser.AuthUser() |
|
543 | auth_user = apiuser.AuthUser() | |
542 | else: |
|
544 | else: | |
543 |
raise JSONRPCError("userid is not the same |
|
545 | raise JSONRPCError("Provided userid is not the same the user calling this function") | |
544 |
|
546 | |||
545 | if pull_request.is_closed(): |
|
547 | if pull_request.is_closed(): | |
546 | raise JSONRPCError(f"pull request `{pullrequestid}` comment failed, pull request is closed") |
|
548 | raise JSONRPCError(f"pull request `{pullrequestid}` comment failed, pull request is closed") | |
547 |
|
549 | |||
548 | if not PullRequestModel().check_user_read(pull_request, apiuser, api=True): |
|
550 | if not PullRequestModel().check_user_read(pull_request, apiuser, api=True): | |
549 | raise JSONRPCError(f"repository `{repoid}` does not exist") |
|
551 | raise JSONRPCError(f"repository `{repoid}` does not exist") | |
|
552 | ||||
|
553 | user = get_user_or_error(userid) | |||
550 | message = Optional.extract(message) |
|
554 | message = Optional.extract(message) | |
551 | status = Optional.extract(status) |
|
555 | status = Optional.extract(status) | |
552 | commit_id = Optional.extract(commit_id) |
|
556 | commit_id = Optional.extract(commit_id) | |
@@ -594,7 +598,7 def comment_pull_request( | |||||
594 | comment = CommentsModel().create( |
|
598 | comment = CommentsModel().create( | |
595 | text=text, |
|
599 | text=text, | |
596 | repo=pull_request.target_repo.repo_id, |
|
600 | repo=pull_request.target_repo.repo_id, | |
597 |
user= |
|
601 | user=user, | |
598 | pull_request=pull_request.pull_request_id, |
|
602 | pull_request=pull_request.pull_request_id, | |
599 | f_path=None, |
|
603 | f_path=None, | |
600 | line_no=None, |
|
604 | line_no=None, | |
@@ -928,9 +932,9 def update_pull_request( | |||||
928 | repo = pull_request.target_repo |
|
932 | repo = pull_request.target_repo | |
929 |
|
933 | |||
930 | if not PullRequestModel().check_user_update(pull_request, apiuser, api=True): |
|
934 | if not PullRequestModel().check_user_update(pull_request, apiuser, api=True): | |
931 |
raise JSONRPCError("pull request `{}` update failed, no permission to update." |
|
935 | raise JSONRPCError(f"pull request `{pullrequestid}` update failed, no permission to update.") | |
932 | if pull_request.is_closed(): |
|
936 | if pull_request.is_closed(): | |
933 |
raise JSONRPCError("pull request `{}` update failed, pull request is closed" |
|
937 | raise JSONRPCError(f"pull request `{pullrequestid}` update failed, pull request is closed") | |
934 |
|
938 | |||
935 | reviewer_objects = Optional.extract(reviewers) or [] |
|
939 | reviewer_objects = Optional.extract(reviewers) or [] | |
936 | observer_objects = Optional.extract(observers) or [] |
|
940 | observer_objects = Optional.extract(observers) or [] | |
@@ -959,9 +963,7 def update_pull_request( | |||||
959 | if str2bool(Optional.extract(update_commits)): |
|
963 | if str2bool(Optional.extract(update_commits)): | |
960 | if pull_request.pull_request_state != PullRequest.STATE_CREATED: |
|
964 | if pull_request.pull_request_state != PullRequest.STATE_CREATED: | |
961 | raise JSONRPCError( |
|
965 | raise JSONRPCError( | |
962 |
"Operation forbidden because pull request is in state {}, only state {} is allowed." |
|
966 | f"Operation forbidden because pull request is in state {pull_request.pull_request_state}, only state {PullRequest.STATE_CREATED} is allowed." | |
963 | pull_request.pull_request_state, PullRequest.STATE_CREATED |
|
|||
964 | ) |
|
|||
965 | ) |
|
967 | ) | |
966 |
|
968 | |||
967 | with pull_request.set_state(PullRequest.STATE_UPDATING): |
|
969 | with pull_request.set_state(PullRequest.STATE_UPDATING): | |
@@ -1092,12 +1094,13 def close_pull_request( | |||||
1092 | else: |
|
1094 | else: | |
1093 | repo = pull_request.target_repo |
|
1095 | repo = pull_request.target_repo | |
1094 |
|
1096 | |||
1095 | is_repo_admin = HasRepoPermissionAnyApi("repository.admin")(user=apiuser, repo_name=repo.repo_name) |
|
1097 | auth_user = apiuser | |
1096 | if not isinstance(userid, Optional): |
|
1098 | if not isinstance(userid, Optional): | |
1097 |
if has_superadmin_permission(apiuser) |
|
1099 | if has_superadmin_permission(apiuser): | |
1098 | apiuser = get_user_or_error(userid) |
|
1100 | # super-admin can impersonate other users | |
|
1101 | auth_user = get_user_or_error(userid) | |||
1099 | else: |
|
1102 | else: | |
1100 |
raise JSONRPCError("userid is not the same |
|
1103 | raise JSONRPCError("Provided userid is not the same the user calling this function") | |
1101 |
|
1104 | |||
1102 | if pull_request.is_closed(): |
|
1105 | if pull_request.is_closed(): | |
1103 | raise JSONRPCError(f"pull request `{pullrequestid}` is already closed") |
|
1106 | raise JSONRPCError(f"pull request `{pullrequestid}` is already closed") | |
@@ -1106,14 +1109,14 def close_pull_request( | |||||
1106 | allowed_to_close = PullRequestModel().check_user_update(pull_request, apiuser, api=True) |
|
1109 | allowed_to_close = PullRequestModel().check_user_update(pull_request, apiuser, api=True) | |
1107 |
|
1110 | |||
1108 | if not allowed_to_close: |
|
1111 | if not allowed_to_close: | |
1109 |
raise JSONRPCError("pull request `{}` close failed, no permission to close." |
|
1112 | raise JSONRPCError(f"pull request `{pullrequestid}` close failed, no permission to close.") | |
1110 |
|
1113 | |||
1111 | # message we're using to close the PR, else it's automatically generated |
|
1114 | # message we're using to close the PR, else it's automatically generated | |
1112 | message = Optional.extract(message) |
|
1115 | message = Optional.extract(message) | |
1113 |
|
1116 | |||
1114 | # finally close the PR, with proper message comment |
|
1117 | # finally close the PR, with proper message comment | |
1115 | comment, status = PullRequestModel().close_pull_request_with_comment( |
|
1118 | comment, status = PullRequestModel().close_pull_request_with_comment( | |
1116 |
pull_request, apiuser, repo, message=message, auth_user=a |
|
1119 | pull_request, apiuser, repo, message=message, auth_user=auth_user | |
1117 | ) |
|
1120 | ) | |
1118 | status_lbl = ChangesetStatus.get_status_lbl(status) |
|
1121 | status_lbl = ChangesetStatus.get_status_lbl(status) | |
1119 |
|
1122 |
@@ -600,7 +600,7 def get_repo_file( | |||||
600 | _extended_types = ["minimal", "minimal+search", "basic", "full"] |
|
600 | _extended_types = ["minimal", "minimal+search", "basic", "full"] | |
601 | if details not in _extended_types: |
|
601 | if details not in _extended_types: | |
602 | ret_types = ",".join(_extended_types) |
|
602 | ret_types = ",".join(_extended_types) | |
603 |
raise JSONRPCError(f"ret_type must be one of |
|
603 | raise JSONRPCError(f"ret_type must be one of {_extended_types}, got {ret_types}", details) | |
604 | extended_info = False |
|
604 | extended_info = False | |
605 | content = False |
|
605 | content = False | |
606 |
|
606 | |||
@@ -695,7 +695,7 def get_repo_fts_tree(request, apiuser, repoid, commit_id, root_path): | |||||
695 |
|
695 | |||
696 | except Exception: |
|
696 | except Exception: | |
697 | log.exception("Exception occurred while trying to get repo nodes") |
|
697 | log.exception("Exception occurred while trying to get repo nodes") | |
698 |
raise JSONRPCError("failed to get repo: ` |
|
698 | raise JSONRPCError(f"failed to get repo: `{repo.repo_name}` nodes") | |
699 |
|
699 | |||
700 |
|
700 | |||
701 | @jsonrpc_method() |
|
701 | @jsonrpc_method() | |
@@ -755,7 +755,7 def get_repo_refs(request, apiuser, repoid): | |||||
755 | return refs |
|
755 | return refs | |
756 | except Exception: |
|
756 | except Exception: | |
757 | log.exception("Exception occurred while trying to get repo refs") |
|
757 | log.exception("Exception occurred while trying to get repo refs") | |
758 |
raise JSONRPCError("failed to get repo: ` |
|
758 | raise JSONRPCError(f"failed to get repo: `{repo.repo_name}` references") | |
759 |
|
759 | |||
760 |
|
760 | |||
761 | @jsonrpc_method() |
|
761 | @jsonrpc_method() | |
@@ -918,14 +918,14 def create_repo( | |||||
918 | task_id = get_task_id(task) |
|
918 | task_id = get_task_id(task) | |
919 | # no commit, it's done in RepoModel, or async via celery |
|
919 | # no commit, it's done in RepoModel, or async via celery | |
920 | return { |
|
920 | return { | |
921 |
"msg": "Created new repository `{}`" |
|
921 | "msg": f"Created new repository `{schema_data['repo_name']}`", | |
922 | "success": True, # cannot return the repo data here since fork |
|
922 | "success": True, # cannot return the repo data here since fork | |
923 | # can be done async |
|
923 | # can be done async | |
924 | "task": task_id, |
|
924 | "task": task_id, | |
925 | } |
|
925 | } | |
926 | except Exception: |
|
926 | except Exception: | |
927 | log.exception("Exception while trying to create the repository %s", schema_data["repo_name"]) |
|
927 | log.exception("Exception while trying to create the repository %s", schema_data["repo_name"]) | |
928 |
raise JSONRPCError("failed to create repository `{}`" |
|
928 | raise JSONRPCError(f"failed to create repository `{schema_data['repo_name']}`") | |
929 |
|
929 | |||
930 |
|
930 | |||
931 | @jsonrpc_method() |
|
931 | @jsonrpc_method() | |
@@ -994,7 +994,7 def remove_field_from_repo(request, apiuser, repoid, key): | |||||
994 |
|
994 | |||
995 | field = RepositoryField.get_by_key_name(key, repo) |
|
995 | field = RepositoryField.get_by_key_name(key, repo) | |
996 | if not field: |
|
996 | if not field: | |
997 |
raise JSONRPCError("Field with key ` |
|
997 | raise JSONRPCError(f"Field with key `{key}` does not exists for repo `{repoid}`") | |
998 |
|
998 | |||
999 | try: |
|
999 | try: | |
1000 | RepoModel().delete_repo_field(repo, field_key=key) |
|
1000 | RepoModel().delete_repo_field(repo, field_key=key) | |
@@ -1165,7 +1165,7 def update_repo( | |||||
1165 | } |
|
1165 | } | |
1166 | except Exception: |
|
1166 | except Exception: | |
1167 | log.exception("Exception while trying to update the repository %s", repoid) |
|
1167 | log.exception("Exception while trying to update the repository %s", repoid) | |
1168 |
raise JSONRPCError("failed to update repo ` |
|
1168 | raise JSONRPCError(f"failed to update repo `{repoid}`") | |
1169 |
|
1169 | |||
1170 |
|
1170 | |||
1171 | @jsonrpc_method() |
|
1171 | @jsonrpc_method() | |
@@ -1310,14 +1310,14 def fork_repo( | |||||
1310 | task_id = get_task_id(task) |
|
1310 | task_id = get_task_id(task) | |
1311 |
|
1311 | |||
1312 | return { |
|
1312 | return { | |
1313 |
"msg": "Created fork of `{ |
|
1313 | "msg": f"Created fork of `{repo.repo_name}` as `{schema_data['repo_name']}`", | |
1314 | "success": True, # cannot return the repo data here since fork |
|
1314 | "success": True, # cannot return the repo data here since fork | |
1315 | # can be done async |
|
1315 | # can be done async | |
1316 | "task": task_id, |
|
1316 | "task": task_id, | |
1317 | } |
|
1317 | } | |
1318 | except Exception: |
|
1318 | except Exception: | |
1319 | log.exception("Exception while trying to create fork %s", schema_data["repo_name"]) |
|
1319 | log.exception("Exception while trying to create fork %s", schema_data["repo_name"]) | |
1320 |
raise JSONRPCError("failed to fork repository `{}` as `{}`" |
|
1320 | raise JSONRPCError(f"failed to fork repository `{repo_name}` as `{schema_data['repo_name']}`") | |
1321 |
|
1321 | |||
1322 |
|
1322 | |||
1323 | @jsonrpc_method() |
|
1323 | @jsonrpc_method() | |
@@ -1361,11 +1361,11 def delete_repo(request, apiuser, repoid, forks=Optional("")): | |||||
1361 | _forks_msg = "" |
|
1361 | _forks_msg = "" | |
1362 | _forks = [f for f in repo.forks] |
|
1362 | _forks = [f for f in repo.forks] | |
1363 | if handle_forks == "detach": |
|
1363 | if handle_forks == "detach": | |
1364 |
_forks_msg = " " + "Detached |
|
1364 | _forks_msg = " " + f"Detached {len(_forks)} forks" | |
1365 | elif handle_forks == "delete": |
|
1365 | elif handle_forks == "delete": | |
1366 |
_forks_msg = " " + "Deleted |
|
1366 | _forks_msg = " " + f"Deleted {len(_forks)} forks" | |
1367 | elif _forks: |
|
1367 | elif _forks: | |
1368 |
raise JSONRPCError("Cannot delete ` |
|
1368 | raise JSONRPCError(f"Cannot delete `{repo.repo_name}` it still contains attached forks") | |
1369 | old_data = repo.get_api_data() |
|
1369 | old_data = repo.get_api_data() | |
1370 | RepoModel().delete(repo, forks=forks) |
|
1370 | RepoModel().delete(repo, forks=forks) | |
1371 |
|
1371 | |||
@@ -1509,7 +1509,7 def lock(request, apiuser, repoid, locked=Optional(None), userid=Optional(OAttr( | |||||
1509 | # make sure normal user does not pass someone else userid, |
|
1509 | # make sure normal user does not pass someone else userid, | |
1510 | # he is not allowed to do that |
|
1510 | # he is not allowed to do that | |
1511 | if not isinstance(userid, Optional) and userid != apiuser.user_id: |
|
1511 | if not isinstance(userid, Optional) and userid != apiuser.user_id: | |
1512 |
raise JSONRPCError("userid is not the same |
|
1512 | raise JSONRPCError("Provided userid is not the same the user calling this function") | |
1513 |
|
1513 | |||
1514 | if isinstance(userid, Optional): |
|
1514 | if isinstance(userid, Optional): | |
1515 | userid = apiuser.user_id |
|
1515 | userid = apiuser.user_id | |
@@ -1527,7 +1527,7 def lock(request, apiuser, repoid, locked=Optional(None), userid=Optional(OAttr( | |||||
1527 | "locked_by": None, |
|
1527 | "locked_by": None, | |
1528 | "lock_reason": None, |
|
1528 | "lock_reason": None, | |
1529 | "lock_state_changed": False, |
|
1529 | "lock_state_changed": False, | |
1530 |
"msg": "Repo ` |
|
1530 | "msg": f"Repo `{repo.repo_name}` not locked.", | |
1531 | } |
|
1531 | } | |
1532 | return _d |
|
1532 | return _d | |
1533 | else: |
|
1533 | else: | |
@@ -1541,8 +1541,7 def lock(request, apiuser, repoid, locked=Optional(None), userid=Optional(OAttr( | |||||
1541 | "lock_reason": _reason, |
|
1541 | "lock_reason": _reason, | |
1542 | "lock_state_changed": False, |
|
1542 | "lock_state_changed": False, | |
1543 | "msg": ( |
|
1543 | "msg": ( | |
1544 | "Repo `%s` locked by `%s` on `%s`." |
|
1544 | f"Repo `{repo.repo_name}` locked by `{lock_user.username}` on `{json.dumps(time_to_datetime(_time))}`." | |
1545 | % (repo.repo_name, lock_user.username, json.dumps(time_to_datetime(_time))) |
|
|||
1546 | ), |
|
1545 | ), | |
1547 | } |
|
1546 | } | |
1548 | return _d |
|
1547 | return _d | |
@@ -1565,12 +1564,12 def lock(request, apiuser, repoid, locked=Optional(None), userid=Optional(OAttr( | |||||
1565 | "locked_by": user.username, |
|
1564 | "locked_by": user.username, | |
1566 | "lock_reason": lock_reason, |
|
1565 | "lock_reason": lock_reason, | |
1567 | "lock_state_changed": True, |
|
1566 | "lock_state_changed": True, | |
1568 |
"msg": |
|
1567 | "msg": f"User `{user.username}` set lock state for repo `{repo.repo_name}` to `{locked}`", | |
1569 | } |
|
1568 | } | |
1570 | return _d |
|
1569 | return _d | |
1571 | except Exception: |
|
1570 | except Exception: | |
1572 | log.exception("Exception occurred while trying to lock repository") |
|
1571 | log.exception("Exception occurred while trying to lock repository") | |
1573 |
raise JSONRPCError("Error occurred locking repository ` |
|
1572 | raise JSONRPCError(f"Error occurred locking repository `{repo.repo_name}`") | |
1574 |
|
1573 | |||
1575 |
|
1574 | |||
1576 | @jsonrpc_method() |
|
1575 | @jsonrpc_method() | |
@@ -1643,8 +1642,17 def comment_commit( | |||||
1643 | log.exception("Failed to fetch commit") |
|
1642 | log.exception("Failed to fetch commit") | |
1644 | raise JSONRPCError(safe_str(e)) |
|
1643 | raise JSONRPCError(safe_str(e)) | |
1645 |
|
1644 | |||
|
1645 | auth_user = apiuser | |||
1646 | if isinstance(userid, Optional): |
|
1646 | if isinstance(userid, Optional): | |
1647 | userid = apiuser.user_id |
|
1647 | userid = apiuser.user_id | |
|
1648 | else: | |||
|
1649 | # super-admin can impersonate other users | |||
|
1650 | if has_superadmin_permission(apiuser): | |||
|
1651 | apiuser = get_user_or_error(userid) | |||
|
1652 | userid = apiuser.user_id | |||
|
1653 | auth_user = apiuser.AuthUser() | |||
|
1654 | else: | |||
|
1655 | raise JSONRPCError("Provided userid is not the same the user calling this function") | |||
1648 |
|
1656 | |||
1649 | user = get_user_or_error(userid) |
|
1657 | user = get_user_or_error(userid) | |
1650 | status = Optional.extract(status) |
|
1658 | status = Optional.extract(status) | |
@@ -1655,21 +1663,14 def comment_commit( | |||||
1655 |
|
1663 | |||
1656 | allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES] |
|
1664 | allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES] | |
1657 | if status and status not in allowed_statuses: |
|
1665 | if status and status not in allowed_statuses: | |
1658 | raise JSONRPCError( |
|
1666 | raise JSONRPCError(f"Bad status, must be on of {allowed_statuses} got {status}") | |
1659 | "Bad status, must be on " |
|
|||
1660 | "of %s got %s" |
|
|||
1661 | % ( |
|
|||
1662 | allowed_statuses, |
|
|||
1663 | status, |
|
|||
1664 | ) |
|
|||
1665 | ) |
|
|||
1666 |
|
1667 | |||
1667 | if resolves_comment_id: |
|
1668 | if resolves_comment_id: | |
1668 | comment = ChangesetComment.get(resolves_comment_id) |
|
1669 | comment = ChangesetComment.get(resolves_comment_id) | |
1669 | if not comment: |
|
1670 | if not comment: | |
1670 |
raise JSONRPCError("Invalid resolves_comment_id ` |
|
1671 | raise JSONRPCError(f"Invalid resolves_comment_id `{resolves_comment_id}` for this commit.") | |
1671 | if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO: |
|
1672 | if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO: | |
1672 |
raise JSONRPCError("Comment ` |
|
1673 | raise JSONRPCError(f"Comment `{resolves_comment_id}` is wrong type for setting status to resolved.") | |
1673 |
|
1674 | |||
1674 | try: |
|
1675 | try: | |
1675 | rc_config = SettingsModel().get_all_settings() |
|
1676 | rc_config = SettingsModel().get_all_settings() | |
@@ -1685,7 +1686,7 def comment_commit( | |||||
1685 | renderer=renderer, |
|
1686 | renderer=renderer, | |
1686 | comment_type=comment_type, |
|
1687 | comment_type=comment_type, | |
1687 | resolves_comment_id=resolves_comment_id, |
|
1688 | resolves_comment_id=resolves_comment_id, | |
1688 |
auth_user=a |
|
1689 | auth_user=auth_user, | |
1689 | extra_recipients=extra_recipients, |
|
1690 | extra_recipients=extra_recipients, | |
1690 | send_email=send_email, |
|
1691 | send_email=send_email, | |
1691 | ) |
|
1692 | ) | |
@@ -1721,7 +1722,7 def comment_commit( | |||||
1721 | ) |
|
1722 | ) | |
1722 |
|
1723 | |||
1723 | return { |
|
1724 | return { | |
1724 |
"msg": |
|
1725 | "msg": f"Commented on commit `{comment.revision}` for repository `{repo.repo_name}`", | |
1725 | "status_change": status, |
|
1726 | "status_change": status, | |
1726 | "success": True, |
|
1727 | "success": True, | |
1727 | } |
|
1728 | } | |
@@ -1792,9 +1793,7 def get_repo_comments( | |||||
1792 |
|
1793 | |||
1793 | comment_type = Optional.extract(comment_type) |
|
1794 | comment_type = Optional.extract(comment_type) | |
1794 | if comment_type and comment_type not in ChangesetComment.COMMENT_TYPES: |
|
1795 | if comment_type and comment_type not in ChangesetComment.COMMENT_TYPES: | |
1795 | raise JSONRPCError( |
|
1796 | raise JSONRPCError(f"comment_type must be one of `{ChangesetComment.COMMENT_TYPES}` got {comment_type}") | |
1796 | "comment_type must be one of `{}` got {}".format(ChangesetComment.COMMENT_TYPES, comment_type) |
|
|||
1797 | ) |
|
|||
1798 |
|
1797 | |||
1799 | comments = CommentsModel().get_repository_comments( |
|
1798 | comments = CommentsModel().get_repository_comments( | |
1800 | repo=repo, comment_type=comment_type, user=user, commit_id=commit_id |
|
1799 | repo=repo, comment_type=comment_type, user=user, commit_id=commit_id | |
@@ -1886,11 +1885,12 def edit_comment(request, apiuser, message, comment_id, version, userid=Optional | |||||
1886 | is_repo_admin = HasRepoPermissionAnyApi("repository.admin")(user=apiuser, repo_name=comment.repo.repo_name) |
|
1885 | is_repo_admin = HasRepoPermissionAnyApi("repository.admin")(user=apiuser, repo_name=comment.repo.repo_name) | |
1887 |
|
1886 | |||
1888 | if not isinstance(userid, Optional): |
|
1887 | if not isinstance(userid, Optional): | |
1889 |
if is_super_admin |
|
1888 | if is_super_admin: | |
|
1889 | # super-admin can impersonate other users | |||
1890 | apiuser = get_user_or_error(userid) |
|
1890 | apiuser = get_user_or_error(userid) | |
1891 | auth_user = apiuser.AuthUser() |
|
1891 | auth_user = apiuser.AuthUser() | |
1892 | else: |
|
1892 | else: | |
1893 |
raise JSONRPCError("userid is not the same |
|
1893 | raise JSONRPCError("Provided userid is not the same the user calling this function") | |
1894 |
|
1894 | |||
1895 | comment_author = comment.author.user_id == auth_user.user_id |
|
1895 | comment_author = comment.author.user_id == auth_user.user_id | |
1896 |
|
1896 | |||
@@ -2001,14 +2001,12 def grant_user_permission(request, apiuser, repoid, userid, perm): | |||||
2001 | PermissionModel().flush_user_permission_caches(changes) |
|
2001 | PermissionModel().flush_user_permission_caches(changes) | |
2002 |
|
2002 | |||
2003 | return { |
|
2003 | return { | |
2004 |
"msg": "Granted perm: `{}` for user: `{}` in repo: `{}`" |
|
2004 | "msg": f"Granted perm: `{perm.permission_name}` for user: `{user.username}` in repo: `{repo.repo_name}`", | |
2005 | perm.permission_name, user.username, repo.repo_name |
|
|||
2006 | ), |
|
|||
2007 | "success": True, |
|
2005 | "success": True, | |
2008 | } |
|
2006 | } | |
2009 | except Exception: |
|
2007 | except Exception: | |
2010 | log.exception("Exception occurred while trying edit permissions for repo") |
|
2008 | log.exception("Exception occurred while trying edit permissions for repo") | |
2011 |
raise JSONRPCError("failed to edit permission for user: `{}` in repo: `{}`" |
|
2009 | raise JSONRPCError(f"failed to edit permission for user: `{userid}` in repo: `{repoid}`") | |
2012 |
|
2010 | |||
2013 |
|
2011 | |||
2014 | @jsonrpc_method() |
|
2012 | @jsonrpc_method() | |
@@ -2058,12 +2056,12 def revoke_user_permission(request, apiuser, repoid, userid): | |||||
2058 | PermissionModel().flush_user_permission_caches(changes) |
|
2056 | PermissionModel().flush_user_permission_caches(changes) | |
2059 |
|
2057 | |||
2060 | return { |
|
2058 | return { | |
2061 |
"msg": "Revoked perm for user: `{ |
|
2059 | "msg": f"Revoked perm for user: `{user.username}` in repo: `{repo.repo_name}`", | |
2062 | "success": True, |
|
2060 | "success": True, | |
2063 | } |
|
2061 | } | |
2064 | except Exception: |
|
2062 | except Exception: | |
2065 | log.exception("Exception occurred while trying revoke permissions to repo") |
|
2063 | log.exception("Exception occurred while trying revoke permissions to repo") | |
2066 |
raise JSONRPCError("failed to edit permission for user: `{}` in repo: `{}`" |
|
2064 | raise JSONRPCError(f"failed to edit permission for user: `{userid}` in repo: `{repoid}`") | |
2067 |
|
2065 | |||
2068 |
|
2066 | |||
2069 | @jsonrpc_method() |
|
2067 | @jsonrpc_method() | |
@@ -2145,9 +2143,7 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm): | |||||
2145 | } |
|
2143 | } | |
2146 | except Exception: |
|
2144 | except Exception: | |
2147 | log.exception("Exception occurred while trying change permission on repo") |
|
2145 | log.exception("Exception occurred while trying change permission on repo") | |
2148 | raise JSONRPCError( |
|
2146 | raise JSONRPCError(f"failed to edit permission for user group: `{usergroupid}` in repo: `{repo.repo_name}`") | |
2149 | "failed to edit permission for user group: `%s` in repo: `%s`" % (usergroupid, repo.repo_name) |
|
|||
2150 | ) |
|
|||
2151 |
|
2147 | |||
2152 |
|
2148 | |||
2153 | @jsonrpc_method() |
|
2149 | @jsonrpc_method() | |
@@ -2206,16 +2202,13 def revoke_user_group_permission(request, apiuser, repoid, usergroupid): | |||||
2206 | PermissionModel().flush_user_permission_caches(changes) |
|
2202 | PermissionModel().flush_user_permission_caches(changes) | |
2207 |
|
2203 | |||
2208 | return { |
|
2204 | return { | |
2209 |
"msg": "Revoked perm for user group: `{}` in repo: `{}`" |
|
2205 | "msg": f"Revoked perm for user group: `{user_group.users_group_name}` in repo: `{repo.repo_name}`", | |
2210 | user_group.users_group_name, repo.repo_name |
|
|||
2211 | ), |
|
|||
2212 | "success": True, |
|
2206 | "success": True, | |
2213 | } |
|
2207 | } | |
2214 | except Exception: |
|
2208 | except Exception: | |
2215 | log.exception("Exception occurred while trying revoke user group permission on repo") |
|
2209 | log.exception("Exception occurred while trying revoke user group permission on repo") | |
2216 | raise JSONRPCError( |
|
2210 | raise JSONRPCError( | |
2217 |
"failed to edit permission for user group: ` |
|
2211 | f"failed to edit permission for user group: `{user_group.users_group_name}` in repo: `{repo.repo_name}`" | |
2218 | "repo: `%s`" % (user_group.users_group_name, repo.repo_name) |
|
|||
2219 | ) |
|
2212 | ) | |
2220 |
|
2213 | |||
2221 |
|
2214 | |||
@@ -2276,12 +2269,12 def pull(request, apiuser, repoid, remote_uri=Optional(None), sync_large_objects | |||||
2276 | repo.repo_name, apiuser.username, remote_uri=remote_uri, sync_large_objects=sync_large_objects |
|
2269 | repo.repo_name, apiuser.username, remote_uri=remote_uri, sync_large_objects=sync_large_objects | |
2277 | ) |
|
2270 | ) | |
2278 | return { |
|
2271 | return { | |
2279 |
"msg": "Pulled from url `{}` on repo `{ |
|
2272 | "msg": f"Pulled from url `{remote_uri_display}` on repo `{repo.repo_name}`", | |
2280 | "repository": repo.repo_name, |
|
2273 | "repository": repo.repo_name, | |
2281 | } |
|
2274 | } | |
2282 | except Exception: |
|
2275 | except Exception: | |
2283 | log.exception("Exception occurred while trying to pull changes from remote location") |
|
2276 | log.exception("Exception occurred while trying to pull changes from remote location") | |
2284 |
raise JSONRPCError("Unable to pull changes from ` |
|
2277 | raise JSONRPCError(f"Unable to pull changes from `{remote_uri_display}`") | |
2285 |
|
2278 | |||
2286 |
|
2279 | |||
2287 | @jsonrpc_method() |
|
2280 | @jsonrpc_method() | |
@@ -2340,12 +2333,12 def strip(request, apiuser, repoid, revision, branch): | |||||
2340 | ) |
|
2333 | ) | |
2341 |
|
2334 | |||
2342 | return { |
|
2335 | return { | |
2343 |
"msg": "Stripped commit {} from repo `{ |
|
2336 | "msg": f"Stripped commit {revision} from repo `{repo.repo_name}`", | |
2344 | "repository": repo.repo_name, |
|
2337 | "repository": repo.repo_name, | |
2345 | } |
|
2338 | } | |
2346 | except Exception: |
|
2339 | except Exception: | |
2347 | log.exception("Exception while trying to strip") |
|
2340 | log.exception("Exception while trying to strip") | |
2348 |
raise JSONRPCError("Unable to strip commit {} from repo `{ |
|
2341 | raise JSONRPCError(f"Unable to strip commit {revision} from repo `{repo.repo_name}`") | |
2349 |
|
2342 | |||
2350 |
|
2343 | |||
2351 | @jsonrpc_method() |
|
2344 | @jsonrpc_method() | |
@@ -2515,4 +2508,4 def maintenance(request, apiuser, repoid): | |||||
2515 | } |
|
2508 | } | |
2516 | except Exception: |
|
2509 | except Exception: | |
2517 | log.exception("Exception occurred while trying to run maintenance") |
|
2510 | log.exception("Exception occurred while trying to run maintenance") | |
2518 |
raise JSONRPCError("Unable to execute maintenance on ` |
|
2511 | raise JSONRPCError(f"Unable to execute maintenance on `{repo.repo_name}`") |
@@ -60,30 +60,30 def add_renderer_globals(event): | |||||
60 |
|
60 | |||
61 | def auto_merge_pr_if_needed(event): |
|
61 | def auto_merge_pr_if_needed(event): | |
62 | from rhodecode.model.db import PullRequest |
|
62 | from rhodecode.model.db import PullRequest | |
63 |
from rhodecode.model.pull_request import |
|
63 | from rhodecode.model.pull_request import PullRequestModel, ChangesetStatus, MergeCheck | |
64 | PullRequestModel, ChangesetStatus, MergeCheck |
|
|||
65 | ) |
|
|||
66 |
|
64 | |||
67 | pr_event_data = event.as_dict()["pullrequest"] |
|
65 | pr_event_data = event.as_dict()["pullrequest"] | |
68 | pull_request = PullRequest.get(pr_event_data["pull_request_id"]) |
|
66 | pull_request = PullRequest.get(pr_event_data["pull_request_id"]) | |
69 | calculated_status = pr_event_data["status"] |
|
67 | calculated_status = pr_event_data["status"] | |
70 |
if |
|
68 | if calculated_status == ChangesetStatus.STATUS_APPROVED and PullRequestModel().is_automatic_merge_enabled( | |
71 | and PullRequestModel().is_automatic_merge_enabled(pull_request)): |
|
69 | pull_request | |
|
70 | ): | |||
72 | user = pull_request.author.AuthUser() |
|
71 | user = pull_request.author.AuthUser() | |
73 |
|
72 | |||
74 | merge_check = MergeCheck.validate( |
|
73 | merge_check = MergeCheck.validate(pull_request, user, translator=lambda x: x, fail_early=True) | |
75 | pull_request, user, translator=lambda x: x, fail_early=True |
|
|||
76 | ) |
|
|||
77 | if merge_check.merge_possible: |
|
74 | if merge_check.merge_possible: | |
78 | from rhodecode.lib.base import vcs_operation_context |
|
75 | from rhodecode.lib.base import vcs_operation_context | |
|
76 | ||||
79 | extras = vcs_operation_context( |
|
77 | extras = vcs_operation_context( | |
80 |
event.request.environ, |
|
78 | event.request.environ, | |
81 | username=user.username, action="push", |
|
79 | repo_name=pull_request.target_repo.repo_name, | |
82 | scm=pull_request.target_repo.repo_type) |
|
80 | username=user.username, | |
83 | from rc_ee.lib.celerylib.tasks import auto_merge_repo |
|
81 | action="push", | |
84 | auto_merge_repo.apply_async( |
|
82 | scm=pull_request.target_repo.repo_type, | |
85 | args=(pull_request.pull_request_id, extras), countdown=3 |
|
|||
86 | ) |
|
83 | ) | |
|
84 | from rc_ee.lib.celerylib.tasks import auto_merge_repo | |||
|
85 | ||||
|
86 | auto_merge_repo.apply_async(args=(pull_request.pull_request_id, extras), countdown=3) | |||
87 |
|
87 | |||
88 |
|
88 | |||
89 | def set_user_lang(event): |
|
89 | def set_user_lang(event): |
@@ -1111,39 +1111,6 | |||||
1111 | } |
|
1111 | } | |
1112 | }); |
|
1112 | }); | |
1113 |
|
1113 | |||
1114 | var dismissNotice = function(noticeId) { |
|
|||
1115 |
|
||||
1116 | var url = pyroutes.url('user_notice_dismiss', |
|
|||
1117 | {"user_id": templateContext.rhodecode_user.user_id}); |
|
|||
1118 |
|
||||
1119 | var postData = { |
|
|||
1120 | 'csrf_token': CSRF_TOKEN, |
|
|||
1121 | 'notice_id': noticeId, |
|
|||
1122 | }; |
|
|||
1123 |
|
||||
1124 | var success = function(response) { |
|
|||
1125 | $('#notice-message-' + noticeId).remove(); |
|
|||
1126 | return false; |
|
|||
1127 | }; |
|
|||
1128 | var failure = function(data, textStatus, xhr) { |
|
|||
1129 | alert("error processing request: " + textStatus); |
|
|||
1130 | return false; |
|
|||
1131 | }; |
|
|||
1132 | ajaxPOST(url, postData, success, failure); |
|
|||
1133 | } |
|
|||
1134 |
|
||||
1135 | var hideLicenseWarning = function () { |
|
|||
1136 | var fingerprint = templateContext.session_attrs.license_fingerprint; |
|
|||
1137 | storeUserSessionAttr('rc_user_session_attr.hide_license_warning', fingerprint); |
|
|||
1138 | $('#notifications').hide(); |
|
|||
1139 | } |
|
|||
1140 |
|
||||
1141 | var hideLicenseError = function () { |
|
|||
1142 | var fingerprint = templateContext.session_attrs.license_fingerprint; |
|
|||
1143 | storeUserSessionAttr('rc_user_session_attr.hide_license_error', fingerprint); |
|
|||
1144 | $('#notifications').hide(); |
|
|||
1145 | } |
|
|||
1146 |
|
||||
1147 | </script> |
|
1114 | </script> | |
1148 | <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script> |
|
1115 | <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script> | |
1149 | </%def> |
|
1116 | </%def> |
@@ -104,6 +104,38 c.template_context['attachment_store'] = { | |||||
104 | rhodecode_edition: '${c.rhodecode_edition}' |
|
104 | rhodecode_edition: '${c.rhodecode_edition}' | |
105 | } |
|
105 | } | |
106 | }; |
|
106 | }; | |
|
107 | var dismissNotice = function(noticeId) { | |||
|
108 | ||||
|
109 | var url = pyroutes.url('user_notice_dismiss', | |||
|
110 | {"user_id": templateContext.rhodecode_user.user_id}); | |||
|
111 | ||||
|
112 | var postData = { | |||
|
113 | 'csrf_token': CSRF_TOKEN, | |||
|
114 | 'notice_id': noticeId, | |||
|
115 | }; | |||
|
116 | ||||
|
117 | var success = function(response) { | |||
|
118 | $('#notice-message-' + noticeId).remove(); | |||
|
119 | return false; | |||
|
120 | }; | |||
|
121 | var failure = function(data, textStatus, xhr) { | |||
|
122 | alert("error processing request: " + textStatus); | |||
|
123 | return false; | |||
|
124 | }; | |||
|
125 | ajaxPOST(url, postData, success, failure); | |||
|
126 | } | |||
|
127 | ||||
|
128 | var hideLicenseWarning = function () { | |||
|
129 | var fingerprint = templateContext.session_attrs.license_fingerprint; | |||
|
130 | storeUserSessionAttr('rc_user_session_attr.hide_license_warning', fingerprint); | |||
|
131 | $('#notifications').hide(); | |||
|
132 | } | |||
|
133 | ||||
|
134 | var hideLicenseError = function () { | |||
|
135 | var fingerprint = templateContext.session_attrs.license_fingerprint; | |||
|
136 | storeUserSessionAttr('rc_user_session_attr.hide_license_error', fingerprint); | |||
|
137 | $('#notifications').hide(); | |||
|
138 | } | |||
107 |
|
139 | |||
108 | </script> |
|
140 | </script> | |
109 | <%include file="/base/plugins_base.mako"/> |
|
141 | <%include file="/base/plugins_base.mako"/> |
General Comments 0
You need to be logged in to leave comments.
Login now