Show More
The requested changes are too big and content was truncated. Show full diff
@@ -0,0 +1,60 b'' | |||
|
1 | |RCE| 4.18.1 |RNS| | |
|
2 | ------------------ | |
|
3 | ||
|
4 | Release Date | |
|
5 | ^^^^^^^^^^^^ | |
|
6 | ||
|
7 | - 2020-01-20 | |
|
8 | ||
|
9 | ||
|
10 | New Features | |
|
11 | ^^^^^^^^^^^^ | |
|
12 | ||
|
13 | ||
|
14 | ||
|
15 | General | |
|
16 | ^^^^^^^ | |
|
17 | ||
|
18 | - API: invalidate license cache on set_license_key call. | |
|
19 | - API: add send_email flag for comments api to allow commenting without email notification. | |
|
20 | - API: added pull requests versions into returned API data. | |
|
21 | - Dashboard: fixed jumping of text in grid loading by new loading indicator. | |
|
22 | - Installation: add few extra defaults that makes RhodeCode nicer out of the box. | |
|
23 | - Pull Requests: small code cleanup to define other type of merge username. | |
|
24 | RC_MERGE_USER_NAME_ATTR env variable defines what should be used from user as merge username. | |
|
25 | - Gists: cleanup UI and make the gist access id use monospace according to the new UI. | |
|
26 | ||
|
27 | ||
|
28 | Security | |
|
29 | ^^^^^^^^ | |
|
30 | ||
|
31 | - Repository permission: properly flush permission caches on set private mode of repository. | |
|
32 | Otherwise we get cached values still in place until it expires. | |
|
33 | - Repository permission: add set/un-set of private repository from permissions page. | |
|
34 | - Permissions: flush all user permissions in case of default user permission changes. | |
|
35 | ||
|
36 | ||
|
37 | Performance | |
|
38 | ^^^^^^^^^^^ | |
|
39 | ||
|
40 | - Caches: used more efficient way of fetching all users for permissions invalidation. | |
|
41 | - Issue trackers: optimized performance of fetching issue tracker patterns. | |
|
42 | ||
|
43 | ||
|
44 | Fixes | |
|
45 | ^^^^^ | |
|
46 | ||
|
47 | - SSH: fixed SSH problems with EE edition. | |
|
48 | - Branch permissions: remove emtpy tooltips on branch permission entries. | |
|
49 | - Core: fixed cython compat inspect that caused some API calls to not work correctly in EE release. | |
|
50 | - Audit logger: use copy of params we later modify to prevent from modification by the store | |
|
51 | function of parameters that we only use for reading. | |
|
52 | - Users: fixed wrong mention of readme in user description help block. | |
|
53 | - Issue trackers: fixed wrong examples in patterns. | |
|
54 | - Issue trackers: fixed missing option to get back to inherited settings. | |
|
55 | ||
|
56 | ||
|
57 | Upgrade notes | |
|
58 | ^^^^^^^^^^^^^ | |
|
59 | ||
|
60 | - Scheduled release addressing problems in 4.18.X releases. |
@@ -0,0 +1,49 b'' | |||
|
1 | |RCE| 4.18.2 |RNS| | |
|
2 | ------------------ | |
|
3 | ||
|
4 | Release Date | |
|
5 | ^^^^^^^^^^^^ | |
|
6 | ||
|
7 | - 2020-01-28 | |
|
8 | ||
|
9 | ||
|
10 | New Features | |
|
11 | ^^^^^^^^^^^^ | |
|
12 | ||
|
13 | ||
|
14 | ||
|
15 | General | |
|
16 | ^^^^^^^ | |
|
17 | ||
|
18 | - Permissions: add better help text about default permissions, and correlation with anonymous access enabled. | |
|
19 | - Mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user. | |
|
20 | - Documentation: added note about hard restart due to celery update. | |
|
21 | - Maintenance: run rebuildfncache for Mercurial in maintenance command. | |
|
22 | ||
|
23 | ||
|
24 | Security | |
|
25 | ^^^^^^^^ | |
|
26 | ||
|
27 | ||
|
28 | ||
|
29 | Performance | |
|
30 | ^^^^^^^^^^^ | |
|
31 | ||
|
32 | - Authentication: cache plugins for auth and their settings in the auth_registry for single request. | |
|
33 | This heavily influences SVN performance on multiple-file commits. | |
|
34 | ||
|
35 | ||
|
36 | Fixes | |
|
37 | ^^^^^ | |
|
38 | ||
|
39 | - Descriptions: fixed rendering problem with certain meta-tags in repo description. | |
|
40 | - Emails: fixed fonts rendering problems in Outlook. | |
|
41 | - Emails: fixed bug in test email sending. | |
|
42 | - Summary: fixed styling of readme indicator. | |
|
43 | - Flash: fixed display problem with flash messages on error pages. | |
|
44 | ||
|
45 | ||
|
46 | Upgrade notes | |
|
47 | ^^^^^^^^^^^^^ | |
|
48 | ||
|
49 | - Scheduled release addressing problems in 4.18.X releases. |
@@ -0,0 +1,64 b'' | |||
|
1 | |RCE| 4.18.3 |RNS| | |
|
2 | ------------------ | |
|
3 | ||
|
4 | Release Date | |
|
5 | ^^^^^^^^^^^^ | |
|
6 | ||
|
7 | - 2020-03-24 | |
|
8 | ||
|
9 | ||
|
10 | New Features | |
|
11 | ^^^^^^^^^^^^ | |
|
12 | ||
|
13 | - LDAP: added nested user groups sync which was planned in 4.18.X but didn't | |
|
14 | make it to the release. New option for sync is available in the LDAP configuration. | |
|
15 | ||
|
16 | ||
|
17 | General | |
|
18 | ^^^^^^^ | |
|
19 | ||
|
20 | - API: added branch permissions functions. | |
|
21 | - Pull requests: added creating indicator to let users know they should wait until PR is creating. | |
|
22 | - Pull requests: allow super-admins to force change state of locked PRs. | |
|
23 | - Users/User groups: in edit mode we now show the actual name of what we're editing. | |
|
24 | - SSH: allow generation of legacy SSH keys for older systems and Windows users. | |
|
25 | - File store: don't response with cookie data on file-store download response. | |
|
26 | - File store: use our own logic for setting content-type. This solves a problem | |
|
27 | when previously used resolver set different content-type+content-encoding which | |
|
28 | is an incorrect behaviour. | |
|
29 | - My Account: show info about password usage for external accounts e.g github/google etc | |
|
30 | We now recommend using auth-tokens instead of actual passwords. | |
|
31 | - Repositories: in description field we now show mention of metatags only if they | |
|
32 | are enabled. | |
|
33 | ||
|
34 | ||
|
35 | Security | |
|
36 | ^^^^^^^^ | |
|
37 | ||
|
38 | - Remote sync: don't expose credentials in displayed URLs. | |
|
39 | Remote links url had visible credentials displayed in the link. | |
|
40 | This was used for web-view and not needed anymore. | |
|
41 | ||
|
42 | ||
|
43 | Performance | |
|
44 | ^^^^^^^^^^^ | |
|
45 | ||
|
46 | - Full text search: significantly improved GIT commit indexing performance by reducing | |
|
47 | number of calls to the vcsserver. | |
|
48 | ||
|
49 | ||
|
50 | Fixes | |
|
51 | ^^^^^ | |
|
52 | ||
|
53 | - Mercurial: fixed cases of lookup of branches that are exactly 20 character long. | |
|
54 | - SVN: allow legacy (pre SVN 1.7) extraction of post commit data. | |
|
55 | - GIT: use non-unicode author extraction as it's returned as bytes from backend, and | |
|
56 | we can get an unicode errors while there's some non-ascii characters. | |
|
57 | - GIT: use safe configparser for git submodules to prevent from errors on submodules with % sign. | |
|
58 | - System info: fixed UI problem with new version update info screen. | |
|
59 | ||
|
60 | ||
|
61 | Upgrade notes | |
|
62 | ^^^^^^^^^^^^^ | |
|
63 | ||
|
64 | - Scheduled release addressing problems in 4.18.X releases. |
@@ -58,3 +58,7 b' ad5bd0c4bd322fdbd04bb825a3d027e08f7a3901' | |||
|
58 | 58 | 037f5794b55a6236d68f6485a485372dde6566e0 v4.17.3 |
|
59 | 59 | 83bc3100cfd6094c1d04f475ddb299b7dc3d0b33 v4.17.4 |
|
60 | 60 | e3de8c95baf8cc9109ca56aee8193a2cb6a54c8a v4.17.4 |
|
61 | f37a3126570477543507f0bc9d245ce75546181a v4.18.0 | |
|
62 | 71d8791463e87b64c1a18475de330ee600d37561 v4.18.1 | |
|
63 | 4bd6b75dac1d25c64885d4d49385e5533f21c525 v4.18.2 | |
|
64 | 12ed92fe57f2e9fc7b71dc0b65e26c2da5c7085f v4.18.3 |
@@ -57,5 +57,5 b' Each lines should represent a single nam' | |||
|
57 | 57 | Run this line from CLI to execute the code from the `repo_delete_task.py` file and |
|
58 | 58 | exit the ishell after the execution:: |
|
59 | 59 | |
|
60 |
echo "%run repo_delete_task.py" | rccontrol ishell |
|
|
60 | echo "%run repo_delete_task.py" | rccontrol ishell enterprise-1 | |
|
61 | 61 |
@@ -124,6 +124,7 b' 1. To configure Apache, create and edit ' | |||
|
124 | 124 | LogLevel info |
|
125 | 125 | # allows custom host names, prevents 400 errors on checkout |
|
126 | 126 | HttpProtocolOptions Unsafe |
|
127 | # Most likely this will be: /home/user/.rccontrol/enterprise-1/mod_dav_svn.conf | |
|
127 | 128 | Include /home/user/.rccontrol/enterprise-1/mod_dav_svn.conf |
|
128 | 129 | </VirtualHost> |
|
129 | 130 |
@@ -48,7 +48,7 b' uses, or if required it can be a differe' | |||
|
48 | 48 | |
|
49 | 49 | |
|
50 | 50 | |
|
51 | To switch to reds-based user sessions uncomment the following section in | |
|
51 | To switch to redis-based user sessions uncomment the following section in | |
|
52 | 52 | your :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. |
|
53 | 53 | |
|
54 | 54 | .. code-block:: ini |
@@ -33,6 +33,15 b' 2. Run the |RCC| installer and accept th' | |||
|
33 | 33 | Do you accept the RhodeCode Control license? |
|
34 | 34 | Press [Y] to accept license and [V] to view license text: y |
|
35 | 35 | |
|
36 | ||
|
37 | .. important:: | |
|
38 | ||
|
39 | We recommend running RhodeCode as a non-root user, such as `rhodecode`; | |
|
40 | this user must have a proper home directory. | |
|
41 | Either log in as that user to install the software, or do it as root | |
|
42 | with `sudo -i -u rhodecode ./RhodeCode-installer-linux-*` | |
|
43 | ||
|
44 | ||
|
36 | 45 | 3. Install a VCS Server, and configure it to start at boot. |
|
37 | 46 | |
|
38 | 47 | .. code-block:: bash |
@@ -193,6 +193,10 b' Fixes' | |||
|
193 | 193 | Upgrade notes |
|
194 | 194 | ^^^^^^^^^^^^^ |
|
195 | 195 | |
|
196 | - Major Celery Version upgrade. The 4.18.X release includes a major Celery version. | |
|
197 | It's recommended to run `rccontrol self-stop && rccontrol self-init` after the | |
|
198 | upgrade to ensure celery workers are restarted and updated. | |
|
199 | ||
|
196 | 200 | - New Automation task. We've changed the logic for updating latest change inside repository group. |
|
197 | 201 | New logic includes scanning for changes in all nested objects. Since this is a heavy task |
|
198 | 202 | a new dedicated scheduler task has been created to update it automatically on a scheduled base. |
@@ -218,6 +222,11 b' Upgrade notes' | |||
|
218 | 222 | Please review vcsserver.ini settings under: |
|
219 | 223 | `rc_cache.repo_object.backend = dogpile.cache.rc.redis_msgpack` |
|
220 | 224 | |
|
225 | - Gunicorn configuration now moved to .ini files. | |
|
226 | Upgrading to 4.18.X will overwrite the gunicorn_conf.py file. If there are any custom changes in that file | |
|
227 | they will be lost. Recommended way to configure gunicorn is now via the .ini files. Please check `rhodecode.template.ini` file | |
|
228 | for example gunicorn configuration. | |
|
229 | ||
|
221 | 230 | - New memory monitoring for Gunicorn workers. Starting from 4.18 release a option was added |
|
222 | 231 | to limit the maximum amount of memory used by a worker. |
|
223 | 232 | Please review new settings in `[server:main]` section for memory management in both |
@@ -9,6 +9,9 b' Release Notes' | |||
|
9 | 9 | .. toctree:: |
|
10 | 10 | :maxdepth: 1 |
|
11 | 11 | |
|
12 | release-notes-4.18.3.rst | |
|
13 | release-notes-4.18.2.rst | |
|
14 | release-notes-4.18.1.rst | |
|
12 | 15 | release-notes-4.18.0.rst |
|
13 | 16 | release-notes-4.17.4.rst |
|
14 | 17 | release-notes-4.17.3.rst |
@@ -18,7 +18,6 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | import inspect | |
|
22 | 21 | import itertools |
|
23 | 22 | import logging |
|
24 | 23 | import sys |
@@ -186,10 +185,12 b' def request_view(request):' | |||
|
186 | 185 | Main request handling method. It handles all logic to call a specific |
|
187 | 186 | exposed method |
|
188 | 187 | """ |
|
188 | # cython compatible inspect | |
|
189 | from rhodecode.config.patches import inspect_getargspec | |
|
190 | inspect = inspect_getargspec() | |
|
189 | 191 | |
|
190 | 192 | # check if we can find this session using api_key, get_by_auth_token |
|
191 | 193 | # search not expired tokens only |
|
192 | ||
|
193 | 194 | try: |
|
194 | 195 | api_user = User.get_by_auth_token(request.rpc_api_key) |
|
195 | 196 |
@@ -56,5 +56,6 b' class TestGetMethod(object):' | |||
|
56 | 56 | 'request': '<RequiredType>', |
|
57 | 57 | 'resolves_comment_id': '<Optional:None>', |
|
58 | 58 | 'status': '<Optional:None>', |
|
59 |
'userid': '<Optional:<OptionalAttr:apiuser>>' |
|
|
59 | 'userid': '<Optional:<OptionalAttr:apiuser>>', | |
|
60 | 'send_email': '<Optional:True>'}] | |
|
60 | 61 | assert_ok(id_, expected, given=response.body) |
@@ -66,7 +66,7 b' class TestGrantUserGroupPermission(objec' | |||
|
66 | 66 | perm=perm) |
|
67 | 67 | response = api_call(self.app, params) |
|
68 | 68 | |
|
69 | expected = 'permission `%s` does not exist' % (perm,) | |
|
69 | expected = 'permission `%s` does not exist.' % (perm,) | |
|
70 | 70 | assert_error(id_, expected, given=response.body) |
|
71 | 71 | |
|
72 | 72 | @mock.patch.object(RepoModel, 'grant_user_group_permission', crash) |
@@ -132,8 +132,7 b' class TestGrantUserGroupPermissionFromRe' | |||
|
132 | 132 | RepoGroupModel().revoke_user_group_permission( |
|
133 | 133 | repo_group.group_id, user_group.users_group_id) |
|
134 | 134 | else: |
|
135 | expected = 'repository group `%s` does not exist' % ( | |
|
136 | repo_group.name,) | |
|
135 | expected = 'repository group `%s` does not exist' % (repo_group.name,) | |
|
137 | 136 | assert_error(id_, expected, given=response.body) |
|
138 | 137 | |
|
139 | 138 | def test_api_grant_user_group_permission_to_repo_group_wrong_permission( |
@@ -149,7 +148,7 b' class TestGrantUserGroupPermissionFromRe' | |||
|
149 | 148 | perm=perm) |
|
150 | 149 | response = api_call(self.app, params) |
|
151 | 150 | |
|
152 | expected = 'permission `%s` does not exist' % (perm,) | |
|
151 | expected = 'permission `%s` does not exist. Permission should start with prefix: `group.`' % (perm,) | |
|
153 | 152 | assert_error(id_, expected, given=response.body) |
|
154 | 153 | |
|
155 | 154 | @mock.patch.object(RepoGroupModel, 'grant_user_group_permission', crash) |
@@ -65,7 +65,7 b' class TestGrantUserPermission(object):' | |||
|
65 | 65 | perm=perm) |
|
66 | 66 | response = api_call(self.app, params) |
|
67 | 67 | |
|
68 | expected = 'permission `%s` does not exist' % (perm,) | |
|
68 | expected = 'permission `%s` does not exist.' % (perm,) | |
|
69 | 69 | assert_error(id_, expected, given=response.body) |
|
70 | 70 | |
|
71 | 71 | @mock.patch.object(RepoModel, 'grant_user_permission', crash) |
@@ -132,7 +132,7 b' class TestGrantUserPermissionFromRepoGro' | |||
|
132 | 132 | perm=perm) |
|
133 | 133 | response = api_call(self.app, params) |
|
134 | 134 | |
|
135 | expected = 'permission `%s` does not exist' % (perm,) | |
|
135 | expected = 'permission `%s` does not exist. Permission should start with prefix: `group.`' % (perm,) | |
|
136 | 136 | assert_error(id_, expected, given=response.body) |
|
137 | 137 | |
|
138 | 138 | @mock.patch.object(RepoGroupModel, 'grant_user_permission', crash) |
@@ -130,7 +130,7 b' class TestGrantUserPermissionFromUserGro' | |||
|
130 | 130 | perm=perm) |
|
131 | 131 | response = api_call(self.app, params) |
|
132 | 132 | |
|
133 | expected = 'permission `%s` does not exist' % perm | |
|
133 | expected = 'permission `%s` does not exist. Permission should start with prefix: `usergroup.`' % perm | |
|
134 | 134 | assert_error(id_, expected, given=response.body) |
|
135 | 135 | |
|
136 | 136 | def test_api_grant_user_permission_to_user_group_exception_when_adding( |
@@ -308,7 +308,11 b' def get_perm_or_error(permid, prefix=Non' | |||
|
308 | 308 | |
|
309 | 309 | perm = PermissionModel.cls.get_by_key(permid) |
|
310 | 310 | if perm is None: |
|
311 |
|
|
|
311 | msg = 'permission `{}` does not exist.'.format(permid) | |
|
312 | if prefix: | |
|
313 | msg += ' Permission should start with prefix: `{}`'.format(prefix) | |
|
314 | raise JSONRPCError(msg) | |
|
315 | ||
|
312 | 316 | if prefix: |
|
313 | 317 | if not perm.permission_name.startswith(prefix): |
|
314 | 318 | raise JSONRPCError('permission `%s` is invalid, ' |
@@ -351,12 +355,12 b' def get_pull_request_or_error(pullreques' | |||
|
351 | 355 | def build_commit_data(commit, detail_level): |
|
352 | 356 | parsed_diff = [] |
|
353 | 357 | if detail_level == 'extended': |
|
354 | for f in commit.added: | |
|
355 |
parsed_diff.append(_get_commit_dict(filename=f |
|
|
356 | for f in commit.changed: | |
|
357 |
parsed_diff.append(_get_commit_dict(filename=f |
|
|
358 | for f in commit.removed: | |
|
359 |
parsed_diff.append(_get_commit_dict(filename=f |
|
|
358 | for f_path in commit.added_paths: | |
|
359 | parsed_diff.append(_get_commit_dict(filename=f_path, op='A')) | |
|
360 | for f_path in commit.changed_paths: | |
|
361 | parsed_diff.append(_get_commit_dict(filename=f_path, op='M')) | |
|
362 | for f_path in commit.removed_paths: | |
|
363 | parsed_diff.append(_get_commit_dict(filename=f_path, op='D')) | |
|
360 | 364 | |
|
361 | 365 | elif detail_level == 'full': |
|
362 | 366 | from rhodecode.lib.diffs import DiffProcessor |
@@ -73,6 +73,7 b' def get_pull_request(request, apiuser, p' | |||
|
73 | 73 | "status" : "<status>", |
|
74 | 74 | "created_on": "<date_time_created>", |
|
75 | 75 | "updated_on": "<date_time_updated>", |
|
76 | "versions": "<number_or_versions_of_pr>", | |
|
76 | 77 | "commit_ids": [ |
|
77 | 78 | ... |
|
78 | 79 | "<commit_id>", |
@@ -452,7 +453,7 b' def comment_pull_request(' | |||
|
452 | 453 | message=Optional(None), commit_id=Optional(None), status=Optional(None), |
|
453 | 454 | comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE), |
|
454 | 455 | resolves_comment_id=Optional(None), extra_recipients=Optional([]), |
|
455 | userid=Optional(OAttr('apiuser'))): | |
|
456 | userid=Optional(OAttr('apiuser')), send_email=Optional(True)): | |
|
456 | 457 | """ |
|
457 | 458 | Comment on the pull request specified with the `pullrequestid`, |
|
458 | 459 | in the |repo| specified by the `repoid`, and optionally change the |
@@ -483,6 +484,8 b' def comment_pull_request(' | |||
|
483 | 484 | :type extra_recipients: Optional(list) |
|
484 | 485 | :param userid: Comment on the pull request as this user |
|
485 | 486 | :type userid: Optional(str or int) |
|
487 | :param send_email: Define if this comment should also send email notification | |
|
488 | :type send_email: Optional(bool) | |
|
486 | 489 | |
|
487 | 490 | Example output: |
|
488 | 491 | |
@@ -527,6 +530,7 b' def comment_pull_request(' | |||
|
527 | 530 | comment_type = Optional.extract(comment_type) |
|
528 | 531 | resolves_comment_id = Optional.extract(resolves_comment_id) |
|
529 | 532 | extra_recipients = Optional.extract(extra_recipients) |
|
533 | send_email = Optional.extract(send_email, binary=True) | |
|
530 | 534 | |
|
531 | 535 | if not message and not status: |
|
532 | 536 | raise JSONRPCError( |
@@ -587,7 +591,8 b' def comment_pull_request(' | |||
|
587 | 591 | comment_type=comment_type, |
|
588 | 592 | resolves_comment_id=resolves_comment_id, |
|
589 | 593 | auth_user=auth_user, |
|
590 | extra_recipients=extra_recipients | |
|
594 | extra_recipients=extra_recipients, | |
|
595 | send_email=send_email | |
|
591 | 596 | ) |
|
592 | 597 | |
|
593 | 598 | if allowed_to_change_status and status: |
@@ -1551,7 +1551,7 b' def comment_commit(' | |||
|
1551 | 1551 | request, apiuser, repoid, commit_id, message, status=Optional(None), |
|
1552 | 1552 | comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE), |
|
1553 | 1553 | resolves_comment_id=Optional(None), extra_recipients=Optional([]), |
|
1554 | userid=Optional(OAttr('apiuser'))): | |
|
1554 | userid=Optional(OAttr('apiuser')), send_email=Optional(True)): | |
|
1555 | 1555 | """ |
|
1556 | 1556 | Set a commit comment, and optionally change the status of the commit. |
|
1557 | 1557 | |
@@ -1575,6 +1575,8 b' def comment_commit(' | |||
|
1575 | 1575 | :type extra_recipients: Optional(list) |
|
1576 | 1576 | :param userid: Set the user name of the comment creator. |
|
1577 | 1577 | :type userid: Optional(str or int) |
|
1578 | :param send_email: Define if this comment should also send email notification | |
|
1579 | :type send_email: Optional(bool) | |
|
1578 | 1580 | |
|
1579 | 1581 | Example error output: |
|
1580 | 1582 | |
@@ -1610,6 +1612,7 b' def comment_commit(' | |||
|
1610 | 1612 | comment_type = Optional.extract(comment_type) |
|
1611 | 1613 | resolves_comment_id = Optional.extract(resolves_comment_id) |
|
1612 | 1614 | extra_recipients = Optional.extract(extra_recipients) |
|
1615 | send_email = Optional.extract(send_email, binary=True) | |
|
1613 | 1616 | |
|
1614 | 1617 | allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES] |
|
1615 | 1618 | if status and status not in allowed_statuses: |
@@ -1639,7 +1642,8 b' def comment_commit(' | |||
|
1639 | 1642 | comment_type=comment_type, |
|
1640 | 1643 | resolves_comment_id=resolves_comment_id, |
|
1641 | 1644 | auth_user=apiuser, |
|
1642 | extra_recipients=extra_recipients | |
|
1645 | extra_recipients=extra_recipients, | |
|
1646 | send_email=send_email | |
|
1643 | 1647 | ) |
|
1644 | 1648 | if status: |
|
1645 | 1649 | # also do a status change |
@@ -18,7 +18,6 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | import inspect | |
|
22 | 21 | import logging |
|
23 | 22 | import itertools |
|
24 | 23 | import base64 |
@@ -334,6 +333,9 b' def get_method(request, apiuser, pattern' | |||
|
334 | 333 | ] |
|
335 | 334 | error : null |
|
336 | 335 | """ |
|
336 | from rhodecode.config.patches import inspect_getargspec | |
|
337 | inspect = inspect_getargspec() | |
|
338 | ||
|
337 | 339 | if not has_superadmin_permission(apiuser): |
|
338 | 340 | raise JSONRPCForbidden() |
|
339 | 341 |
@@ -37,7 +37,7 b' from rhodecode.model import user_group' | |||
|
37 | 37 | from rhodecode.model import user |
|
38 | 38 | from rhodecode.model.db import User |
|
39 | 39 | from rhodecode.model.scm import ScmModel |
|
40 | from rhodecode.model.settings import VcsSettingsModel | |
|
40 | from rhodecode.model.settings import VcsSettingsModel, IssueTrackerSettingsModel | |
|
41 | 41 | from rhodecode.model.repo import ReadmeFinder |
|
42 | 42 | |
|
43 | 43 | log = logging.getLogger(__name__) |
@@ -226,6 +226,7 b' class RepoAppView(BaseAppView):' | |||
|
226 | 226 | self.db_repo_name = self.db_repo.repo_name |
|
227 | 227 | self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo) |
|
228 | 228 | self.db_repo_artifacts = ScmModel().get_artifacts(self.db_repo) |
|
229 | self.db_repo_patterns = IssueTrackerSettingsModel(repo=self.db_repo) | |
|
229 | 230 | |
|
230 | 231 | def _handle_missing_requirements(self, error): |
|
231 | 232 | log.error( |
@@ -573,7 +573,7 b' class AdminSettingsView(BaseAppView):' | |||
|
573 | 573 | |
|
574 | 574 | email_kwargs = { |
|
575 | 575 | 'date': datetime.datetime.now(), |
|
576 |
'user': |
|
|
576 | 'user': self._rhodecode_db_user | |
|
577 | 577 | } |
|
578 | 578 | |
|
579 | 579 | (subject, headers, email_body, |
@@ -872,7 +872,10 b' class UsersView(UserAppView):' | |||
|
872 | 872 | |
|
873 | 873 | c.active = 'ssh_keys_generate' |
|
874 | 874 | comment = 'RhodeCode-SSH {}'.format(c.user.email or '') |
|
875 | c.private, c.public = SshKeyModel().generate_keypair(comment=comment) | |
|
875 | private_format = self.request.GET.get('private_format') \ | |
|
876 | or SshKeyModel.DEFAULT_PRIVATE_KEY_FORMAT | |
|
877 | c.private, c.public = SshKeyModel().generate_keypair( | |
|
878 | comment=comment, private_format=private_format) | |
|
876 | 879 | |
|
877 | 880 | return self._get_template_context(c) |
|
878 | 881 |
@@ -33,6 +33,7 b' from rhodecode.lib import audit_logger' | |||
|
33 | 33 | from rhodecode.lib.auth import ( |
|
34 | 34 | CSRFRequired, NotAnonymous, HasRepoPermissionAny, HasRepoGroupPermissionAny, |
|
35 | 35 | LoginRequired) |
|
36 | from rhodecode.lib.vcs.conf.mtypes import get_mimetypes_db | |
|
36 | 37 | from rhodecode.model.db import Session, FileStore, UserApiKeys |
|
37 | 38 | |
|
38 | 39 | log = logging.getLogger(__name__) |
@@ -46,6 +47,15 b' class FileStoreView(BaseAppView):' | |||
|
46 | 47 | self.storage = utils.get_file_storage(self.request.registry.settings) |
|
47 | 48 | return c |
|
48 | 49 | |
|
50 | def _guess_type(self, file_name): | |
|
51 | """ | |
|
52 | Our own type guesser for mimetypes using the rich DB | |
|
53 | """ | |
|
54 | if not hasattr(self, 'db'): | |
|
55 | self.db = get_mimetypes_db() | |
|
56 | _content_type, _encoding = self.db.guess_type(file_name, strict=False) | |
|
57 | return _content_type, _encoding | |
|
58 | ||
|
49 | 59 | def _serve_file(self, file_uid): |
|
50 | 60 | |
|
51 | 61 | if not self.storage.exists(file_uid): |
@@ -92,7 +102,18 b' class FileStoreView(BaseAppView):' | |||
|
92 | 102 | FileStore.bump_access_counter(file_uid) |
|
93 | 103 | |
|
94 | 104 | file_path = self.storage.store_path(file_uid) |
|
95 | return FileResponse(file_path) | |
|
105 | content_type = 'application/octet-stream' | |
|
106 | content_encoding = None | |
|
107 | ||
|
108 | _content_type, _encoding = self._guess_type(file_path) | |
|
109 | if _content_type: | |
|
110 | content_type = _content_type | |
|
111 | ||
|
112 | # For file store we don't submit any session data, this logic tells the | |
|
113 | # Session lib to skip it | |
|
114 | setattr(self.request, '_file_response', True) | |
|
115 | return FileResponse(file_path, request=self.request, | |
|
116 | content_type=content_type, content_encoding=content_encoding) | |
|
96 | 117 | |
|
97 | 118 | @LoginRequired() |
|
98 | 119 | @NotAnonymous() |
@@ -105,11 +105,11 b' class TestGistsController(TestController' | |||
|
105 | 105 | g4 = create_gist('gist4', gist_type='private').gist_access_id |
|
106 | 106 | response = self.app.get(route_path('gists_show')) |
|
107 | 107 | |
|
108 |
response.mustcontain( |
|
|
109 |
response.mustcontain( |
|
|
110 |
response.mustcontain( |
|
|
108 | response.mustcontain(g1.gist_access_id) | |
|
109 | response.mustcontain(g2.gist_access_id) | |
|
110 | response.mustcontain(g3.gist_access_id) | |
|
111 | 111 | response.mustcontain('gist3-desc') |
|
112 |
response.mustcontain(no=[ |
|
|
112 | response.mustcontain(no=[g4]) | |
|
113 | 113 | |
|
114 | 114 | # Expiration information should be visible |
|
115 | 115 | expires_tag = '%s' % h.age_component( |
@@ -122,7 +122,7 b' class TestGistsController(TestController' | |||
|
122 | 122 | response = self.app.get(route_path('gists_show', params=dict(private=1))) |
|
123 | 123 | |
|
124 | 124 | # and privates |
|
125 |
response.mustcontain( |
|
|
125 | response.mustcontain(gist.gist_access_id) | |
|
126 | 126 | |
|
127 | 127 | def test_index_show_all(self, create_gist): |
|
128 | 128 | self.log_user() |
@@ -136,7 +136,7 b' class TestGistsController(TestController' | |||
|
136 | 136 | assert len(GistModel.get_all()) == 4 |
|
137 | 137 | # and privates |
|
138 | 138 | for gist in GistModel.get_all(): |
|
139 |
response.mustcontain( |
|
|
139 | response.mustcontain(gist.gist_access_id) | |
|
140 | 140 | |
|
141 | 141 | def test_index_show_all_hidden_from_regular(self, create_gist): |
|
142 | 142 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
@@ -150,7 +150,7 b' class TestGistsController(TestController' | |||
|
150 | 150 | # since we don't have access to private in this view, we |
|
151 | 151 | # should see nothing |
|
152 | 152 | for gist in GistModel.get_all(): |
|
153 |
response.mustcontain(no=[ |
|
|
153 | response.mustcontain(no=[gist.gist_access_id]) | |
|
154 | 154 | |
|
155 | 155 | def test_create(self): |
|
156 | 156 | self.log_user() |
@@ -33,7 +33,7 b' def assert_and_get_main_filter_content(r' | |||
|
33 | 33 | if data_item['type'] == 'search': |
|
34 | 34 | display_val = data_item['value_display'] |
|
35 | 35 | if data_item['id'] == -1: |
|
36 | assert 'File search for:' in display_val, display_val | |
|
36 | assert 'File content search for:' in display_val, display_val | |
|
37 | 37 | elif data_item['id'] == -2: |
|
38 | 38 | assert 'Commit search for:' in display_val, display_val |
|
39 | 39 | else: |
@@ -453,7 +453,7 b' class HomeView(BaseAppView, DataGridAppV' | |||
|
453 | 453 | qry = query |
|
454 | 454 | return {'q': qry, 'type': 'content'} |
|
455 | 455 | |
|
456 | label = u'File search for `{}`'.format(h.escape(query)) | |
|
456 | label = u'File content search for `{}`'.format(h.escape(query)) | |
|
457 | 457 | file_qry = { |
|
458 | 458 | 'id': -10, |
|
459 | 459 | 'value': query, |
@@ -497,7 +497,7 b' class HomeView(BaseAppView, DataGridAppV' | |||
|
497 | 497 | qry = query |
|
498 | 498 | return {'q': qry, 'type': 'content'} |
|
499 | 499 | |
|
500 | label = u'File search for `{}`'.format(query) | |
|
500 | label = u'File content search for `{}`'.format(query) | |
|
501 | 501 | file_qry = { |
|
502 | 502 | 'id': -30, |
|
503 | 503 | 'value': query, |
@@ -541,7 +541,7 b' class HomeView(BaseAppView, DataGridAppV' | |||
|
541 | 541 | { |
|
542 | 542 | 'id': -1, |
|
543 | 543 | 'value': query, |
|
544 | 'value_display': u'File search for: `{}`'.format(query), | |
|
544 | 'value_display': u'File content search for: `{}`'.format(query), | |
|
545 | 545 | 'value_icon': '<i class="icon-code"></i>', |
|
546 | 546 | 'type': 'search', |
|
547 | 547 | 'subtype': 'global', |
@@ -26,6 +26,10 b' def includeme(config):' | |||
|
26 | 26 | pattern='/_hovercard/user/{user_id}') |
|
27 | 27 | |
|
28 | 28 | config.add_route( |
|
29 | name='hovercard_username', | |
|
30 | pattern='/_hovercard/username/{username}') | |
|
31 | ||
|
32 | config.add_route( | |
|
29 | 33 | name='hovercard_user_group', |
|
30 | 34 | pattern='/_hovercard/user_group/{user_group_id}') |
|
31 | 35 |
@@ -65,6 +65,19 b' class HoverCardsView(BaseAppView):' | |||
|
65 | 65 | |
|
66 | 66 | @LoginRequired() |
|
67 | 67 | @view_config( |
|
68 | route_name='hovercard_username', request_method='GET', xhr=True, | |
|
69 | renderer='rhodecode:templates/hovercards/hovercard_user.mako') | |
|
70 | def hovercard_username(self): | |
|
71 | c = self.load_default_context() | |
|
72 | username = self.request.matchdict['username'] | |
|
73 | c.user = User.get_by_username(username) | |
|
74 | if not c.user: | |
|
75 | raise HTTPNotFound() | |
|
76 | ||
|
77 | return self._get_template_context(c) | |
|
78 | ||
|
79 | @LoginRequired() | |
|
80 | @view_config( | |
|
68 | 81 | route_name='hovercard_user_group', request_method='GET', xhr=True, |
|
69 | 82 | renderer='rhodecode:templates/hovercards/hovercard_user_group.mako') |
|
70 | 83 | def hovercard_user_group(self): |
@@ -108,7 +108,8 b' class TestLoginController(object):' | |||
|
108 | 108 | |
|
109 | 109 | def test_login_regular_forbidden_when_super_admin_restriction(self): |
|
110 | 110 | from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin |
|
111 | with fixture.auth_restriction(RhodeCodeAuthPlugin.AUTH_RESTRICTION_SUPER_ADMIN): | |
|
111 | with fixture.auth_restriction(self.app._pyramid_registry, | |
|
112 | RhodeCodeAuthPlugin.AUTH_RESTRICTION_SUPER_ADMIN): | |
|
112 | 113 | response = self.app.post(route_path('login'), |
|
113 | 114 | {'username': 'test_regular', |
|
114 | 115 | 'password': 'test12'}) |
@@ -118,7 +119,8 b' class TestLoginController(object):' | |||
|
118 | 119 | |
|
119 | 120 | def test_login_regular_forbidden_when_scope_restriction(self): |
|
120 | 121 | from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin |
|
121 | with fixture.scope_restriction(RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_VCS): | |
|
122 | with fixture.scope_restriction(self.app._pyramid_registry, | |
|
123 | RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_VCS): | |
|
122 | 124 | response = self.app.post(route_path('login'), |
|
123 | 125 | {'username': 'test_regular', |
|
124 | 126 | 'password': 'test12'}) |
@@ -76,6 +76,7 b' class MyAccountView(BaseAppView, DataGri' | |||
|
76 | 76 | def my_account_profile(self): |
|
77 | 77 | c = self.load_default_context() |
|
78 | 78 | c.active = 'profile' |
|
79 | c.extern_type = c.user.extern_type | |
|
79 | 80 | return self._get_template_context(c) |
|
80 | 81 | |
|
81 | 82 | @LoginRequired() |
@@ -72,8 +72,11 b' class MyAccountSshKeysView(BaseAppView, ' | |||
|
72 | 72 | |
|
73 | 73 | c.active = 'ssh_keys_generate' |
|
74 | 74 | if c.ssh_key_generator_enabled: |
|
75 | private_format = self.request.GET.get('private_format') \ | |
|
76 | or SshKeyModel.DEFAULT_PRIVATE_KEY_FORMAT | |
|
75 | 77 | comment = 'RhodeCode-SSH {}'.format(c.user.email or '') |
|
76 |
c.private, c.public = SshKeyModel().generate_keypair( |
|
|
78 | c.private, c.public = SshKeyModel().generate_keypair( | |
|
79 | comment=comment, private_format=private_format) | |
|
77 | 80 | c.target_form_url = h.route_path( |
|
78 | 81 | 'my_account_ssh_keys', _query=dict(default_key=c.public)) |
|
79 | 82 | return self._get_template_context(c) |
@@ -28,6 +28,7 b' from rhodecode.lib import helpers as h' | |||
|
28 | 28 | from rhodecode.lib import audit_logger |
|
29 | 29 | from rhodecode.lib.auth import ( |
|
30 | 30 | LoginRequired, HasRepoGroupPermissionAnyDecorator, CSRFRequired) |
|
31 | from rhodecode.model.db import User | |
|
31 | 32 | from rhodecode.model.permission import PermissionModel |
|
32 | 33 | from rhodecode.model.repo_group import RepoGroupModel |
|
33 | 34 | from rhodecode.model.forms import RepoGroupPermsForm |
@@ -96,7 +97,13 b' class RepoGroupPermissionsView(RepoGroup' | |||
|
96 | 97 | |
|
97 | 98 | Session().commit() |
|
98 | 99 | h.flash(_('Repository Group permissions updated'), category='success') |
|
99 | PermissionModel().flush_user_permission_caches(changes) | |
|
100 | ||
|
101 | affected_user_ids = None | |
|
102 | if changes.get('default_user_changed', False): | |
|
103 | # if we change the default user, we need to flush everyone permissions | |
|
104 | affected_user_ids = User.get_all_user_ids() | |
|
105 | PermissionModel().flush_user_permission_caches( | |
|
106 | changes, affected_user_ids=affected_user_ids) | |
|
100 | 107 | |
|
101 | 108 | raise HTTPFound( |
|
102 | 109 | h.route_path('edit_repo_group_perms', |
@@ -28,6 +28,8 b' from rhodecode.lib import helpers as h' | |||
|
28 | 28 | from rhodecode.lib import audit_logger |
|
29 | 29 | from rhodecode.lib.auth import ( |
|
30 | 30 | LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) |
|
31 | from rhodecode.lib.utils2 import str2bool | |
|
32 | from rhodecode.model.db import User | |
|
31 | 33 | from rhodecode.model.forms import RepoPermsForm |
|
32 | 34 | from rhodecode.model.meta import Session |
|
33 | 35 | from rhodecode.model.permission import PermissionModel |
@@ -89,7 +91,12 b' class RepoSettingsPermissionsView(RepoAp' | |||
|
89 | 91 | Session().commit() |
|
90 | 92 | h.flash(_('Repository access permissions updated'), category='success') |
|
91 | 93 | |
|
92 | PermissionModel().flush_user_permission_caches(changes) | |
|
94 | affected_user_ids = None | |
|
95 | if changes.get('default_user_changed', False): | |
|
96 | # if we change the default user, we need to flush everyone permissions | |
|
97 | affected_user_ids = User.get_all_user_ids() | |
|
98 | PermissionModel().flush_user_permission_caches( | |
|
99 | changes, affected_user_ids=affected_user_ids) | |
|
93 | 100 | |
|
94 | 101 | raise HTTPFound( |
|
95 | 102 | h.route_path('edit_repo_perms', repo_name=self.db_repo_name)) |
@@ -104,9 +111,11 b' class RepoSettingsPermissionsView(RepoAp' | |||
|
104 | 111 | _ = self.request.translate |
|
105 | 112 | self.load_default_context() |
|
106 | 113 | |
|
114 | private_flag = str2bool(self.request.POST.get('private')) | |
|
115 | ||
|
107 | 116 | try: |
|
108 | 117 | RepoModel().update( |
|
109 |
self.db_repo, **{'repo_private': |
|
|
118 | self.db_repo, **{'repo_private': private_flag, 'repo_name': self.db_repo_name}) | |
|
110 | 119 | Session().commit() |
|
111 | 120 | |
|
112 | 121 | h.flash(_('Repository `{}` private mode set successfully').format(self.db_repo_name), |
@@ -116,7 +125,11 b' class RepoSettingsPermissionsView(RepoAp' | |||
|
116 | 125 | h.flash(_('Error occurred during update of repository {}').format( |
|
117 | 126 | self.db_repo_name), category='error') |
|
118 | 127 | |
|
128 | # NOTE(dan): we change repo private mode we need to notify all USERS | |
|
129 | affected_user_ids = User.get_all_user_ids() | |
|
130 | PermissionModel().trigger_permission_flush(affected_user_ids) | |
|
131 | ||
|
119 | 132 | return { |
|
120 | 133 | 'redirect_url': h.route_path('edit_repo_perms', repo_name=self.db_repo_name), |
|
121 |
'private': |
|
|
134 | 'private': private_flag | |
|
122 | 135 | } |
@@ -275,6 +275,20 b' class RepoPullRequestsView(RepoAppView, ' | |||
|
275 | 275 | |
|
276 | 276 | c.state_progressing = pull_request.is_state_changing() |
|
277 | 277 | |
|
278 | _new_state = { | |
|
279 | 'created': PullRequest.STATE_CREATED, | |
|
280 | }.get(self.request.GET.get('force_state')) | |
|
281 | if c.is_super_admin and _new_state: | |
|
282 | with pull_request.set_state(PullRequest.STATE_UPDATING, final_state=_new_state): | |
|
283 | h.flash( | |
|
284 | _('Pull Request state was force changed to `{}`').format(_new_state), | |
|
285 | category='success') | |
|
286 | Session().commit() | |
|
287 | ||
|
288 | raise HTTPFound(h.route_path( | |
|
289 | 'pullrequest_show', repo_name=self.db_repo_name, | |
|
290 | pull_request_id=pull_request_id)) | |
|
291 | ||
|
278 | 292 | version = self.request.GET.get('version') |
|
279 | 293 | from_version = self.request.GET.get('from_version') or version |
|
280 | 294 | merge_checks = self.request.GET.get('merge_checks') |
@@ -31,7 +31,7 b' from rhodecode.lib.auth import (' | |||
|
31 | 31 | LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired) |
|
32 | 32 | from rhodecode.model.forms import IssueTrackerPatternsForm |
|
33 | 33 | from rhodecode.model.meta import Session |
|
34 |
from rhodecode.model.settings import |
|
|
34 | from rhodecode.model.settings import SettingsModel | |
|
35 | 35 | |
|
36 | 36 | log = logging.getLogger(__name__) |
|
37 | 37 | |
@@ -53,7 +53,7 b' class RepoSettingsIssueTrackersView(Repo' | |||
|
53 | 53 | c.active = 'issuetracker' |
|
54 | 54 | c.data = 'data' |
|
55 | 55 | |
|
56 |
c.settings_model = |
|
|
56 | c.settings_model = self.db_repo_patterns | |
|
57 | 57 | c.global_patterns = c.settings_model.get_global_settings() |
|
58 | 58 | c.repo_patterns = c.settings_model.get_repo_settings() |
|
59 | 59 | |
@@ -79,7 +79,7 b' class RepoSettingsIssueTrackersView(Repo' | |||
|
79 | 79 | def repo_issuetracker_delete(self): |
|
80 | 80 | _ = self.request.translate |
|
81 | 81 | uid = self.request.POST.get('uid') |
|
82 |
repo_settings = |
|
|
82 | repo_settings = self.db_repo_patterns | |
|
83 | 83 | try: |
|
84 | 84 | repo_settings.delete_entries(uid) |
|
85 | 85 | except Exception: |
@@ -113,7 +113,7 b' class RepoSettingsIssueTrackersView(Repo' | |||
|
113 | 113 | def repo_issuetracker_update(self): |
|
114 | 114 | _ = self.request.translate |
|
115 | 115 | # Save inheritance |
|
116 |
repo_settings = |
|
|
116 | repo_settings = self.db_repo_patterns | |
|
117 | 117 | inherited = ( |
|
118 | 118 | self.request.POST.get('inherit_global_issuetracker') == "inherited") |
|
119 | 119 | repo_settings.inherit_global_settings = inherited |
@@ -24,6 +24,7 b'' | |||
|
24 | 24 | # LogLevel info |
|
25 | 25 | # # allows custom host names, prevents 400 errors on checkout |
|
26 | 26 | # HttpProtocolOptions Unsafe |
|
27 | # # Most likely this will be: /home/user/.rccontrol/enterprise-1/mod_dav_svn.conf | |
|
27 | 28 | # Include /path/to/generated/mod_dav_svn.conf |
|
28 | 29 | # </VirtualHost> |
|
29 | 30 | # |
@@ -150,6 +150,7 b' class RhodeCodeAuthPluginBase(object):' | |||
|
150 | 150 | |
|
151 | 151 | def __init__(self, plugin_id): |
|
152 | 152 | self._plugin_id = plugin_id |
|
153 | self._settings = {} | |
|
153 | 154 | |
|
154 | 155 | def __str__(self): |
|
155 | 156 | return self.get_id() |
@@ -226,17 +227,26 b' class RhodeCodeAuthPluginBase(object):' | |||
|
226 | 227 | """ |
|
227 | 228 | return AuthnPluginSettingsSchemaBase() |
|
228 | 229 | |
|
229 |
def |
|
|
230 | """ | |
|
231 | Returns the plugin settings as dictionary. | |
|
232 | """ | |
|
230 | def _propagate_settings(self, raw_settings): | |
|
233 | 231 | settings = {} |
|
234 | raw_settings = SettingsModel().get_all_settings() | |
|
235 | 232 | for node in self.get_settings_schema(): |
|
236 | 233 | settings[node.name] = self.get_setting_by_name( |
|
237 | 234 | node.name, plugin_cached_settings=raw_settings) |
|
238 | 235 | return settings |
|
239 | 236 | |
|
237 | def get_settings(self, use_cache=True): | |
|
238 | """ | |
|
239 | Returns the plugin settings as dictionary. | |
|
240 | """ | |
|
241 | if self._settings != {} and use_cache: | |
|
242 | return self._settings | |
|
243 | ||
|
244 | raw_settings = SettingsModel().get_all_settings() | |
|
245 | settings = self._propagate_settings(raw_settings) | |
|
246 | ||
|
247 | self._settings = settings | |
|
248 | return self._settings | |
|
249 | ||
|
240 | 250 | def get_setting_by_name(self, name, default=None, plugin_cached_settings=None): |
|
241 | 251 | """ |
|
242 | 252 | Returns a plugin setting by name. |
@@ -594,19 +604,19 b' class AuthLdapBase(object):' | |||
|
594 | 604 | if not full_resolve: |
|
595 | 605 | return '{}:{}'.format(host, port) |
|
596 | 606 | |
|
597 | log.debug('LDAP: Resolving IP for LDAP host %s', host) | |
|
607 | log.debug('LDAP: Resolving IP for LDAP host `%s`', host) | |
|
598 | 608 | try: |
|
599 | 609 | ip = socket.gethostbyname(host) |
|
600 |
log.debug('Got LDAP |
|
|
610 | log.debug('LDAP: Got LDAP host `%s` ip %s', host, ip) | |
|
601 | 611 | except Exception: |
|
602 | raise LdapConnectionError( | |
|
603 | 'Failed to resolve host: `{}`'.format(host)) | |
|
612 | raise LdapConnectionError('Failed to resolve host: `{}`'.format(host)) | |
|
604 | 613 | |
|
605 | 614 | log.debug('LDAP: Checking if IP %s is accessible', ip) |
|
606 | 615 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
607 | 616 | try: |
|
608 | 617 | s.connect((ip, int(port))) |
|
609 | 618 | s.shutdown(socket.SHUT_RD) |
|
619 | log.debug('LDAP: connection to %s successful', ip) | |
|
610 | 620 | except Exception: |
|
611 | 621 | raise LdapConnectionError( |
|
612 | 622 | 'Failed to connect to host: `{}:{}`'.format(host, port)) |
@@ -667,7 +677,7 b' def loadplugin(plugin_id):' | |||
|
667 | 677 | |
|
668 | 678 | def get_authn_registry(registry=None): |
|
669 | 679 | registry = registry or get_current_registry() |
|
670 |
authn_registry = registry. |
|
|
680 | authn_registry = registry.queryUtility(IAuthnPluginRegistry) | |
|
671 | 681 | return authn_registry |
|
672 | 682 | |
|
673 | 683 | |
@@ -690,6 +700,7 b' def authenticate(username, password, env' | |||
|
690 | 700 | headers_only = environ and not (username and password) |
|
691 | 701 | |
|
692 | 702 | authn_registry = get_authn_registry(registry) |
|
703 | ||
|
693 | 704 | plugins_to_check = authn_registry.get_plugins_for_authentication() |
|
694 | 705 | log.debug('Starting ordered authentication chain using %s plugins', |
|
695 | 706 | [x.name for x in plugins_to_check]) |
@@ -145,16 +145,16 b' class AuthLdap(AuthLdapBase):' | |||
|
145 | 145 | log.debug('Trying simple_bind with password and given login DN: %r', |
|
146 | 146 | self.LDAP_BIND_DN) |
|
147 | 147 | ldap_conn.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS) |
|
148 | ||
|
148 | log.debug('simple_bind successful') | |
|
149 | 149 | return ldap_conn |
|
150 | 150 | |
|
151 | 151 | def fetch_attrs_from_simple_bind(self, server, dn, username, password): |
|
152 | 152 | try: |
|
153 | 153 | log.debug('Trying simple bind with %r', dn) |
|
154 | 154 | server.simple_bind_s(dn, safe_str(password)) |
|
155 |
|
|
|
155 | _dn, attrs = server.search_ext_s( | |
|
156 | 156 | dn, ldap.SCOPE_BASE, '(objectClass=*)', )[0] |
|
157 | _, attrs = user | |
|
157 | ||
|
158 | 158 | return attrs |
|
159 | 159 | |
|
160 | 160 | except ldap.INVALID_CREDENTIALS: |
@@ -206,7 +206,7 b' class AuthLdap(AuthLdapBase):' | |||
|
206 | 206 | break |
|
207 | 207 | else: |
|
208 | 208 | raise LdapPasswordError( |
|
209 | 'Failed to authenticate user `{}`' | |
|
209 | 'Failed to authenticate user `{}` ' | |
|
210 | 210 | 'with given password'.format(username)) |
|
211 | 211 | |
|
212 | 212 | except ldap.NO_SUCH_OBJECT: |
@@ -249,7 +249,7 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
249 | 249 | colander.Int(), |
|
250 | 250 | default=389, |
|
251 | 251 | description=_('Custom port that the LDAP server is listening on. ' |
|
252 | 'Default value is: 389, use 689 for LDAPS(SSL)'), | |
|
252 | 'Default value is: 389, use 689 for LDAPS (SSL)'), | |
|
253 | 253 | preparer=strip_whitespace, |
|
254 | 254 | title=_('Port'), |
|
255 | 255 | validator=colander.Range(min=0, max=65536), |
@@ -272,7 +272,7 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
272 | 272 | 'uid=root,cn=users,dc=mydomain,dc=com, or admin@mydomain.com'), |
|
273 | 273 | missing='', |
|
274 | 274 | preparer=strip_whitespace, |
|
275 |
title=_(' |
|
|
275 | title=_('Bind account'), | |
|
276 | 276 | widget='string') |
|
277 | 277 | dn_pass = colander.SchemaNode( |
|
278 | 278 | colander.String(), |
@@ -280,7 +280,7 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
280 | 280 | description=_('Password to authenticate for given user DN.'), |
|
281 | 281 | missing='', |
|
282 | 282 | preparer=strip_whitespace, |
|
283 |
title=_(' |
|
|
283 | title=_('Bind account password'), | |
|
284 | 284 | widget='password') |
|
285 | 285 | tls_kind = colander.SchemaNode( |
|
286 | 286 | colander.String(), |
@@ -318,7 +318,7 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
318 | 318 | colander.String(), |
|
319 | 319 | default='', |
|
320 | 320 | description=_('Base DN to search. Dynamic bind is supported. Add `$login` marker ' |
|
321 |
'in it to be replaced with current user |
|
|
321 | 'in it to be replaced with current user username \n' | |
|
322 | 322 | '(e.g., dc=mydomain,dc=com, or ou=Users,dc=mydomain,dc=com)'), |
|
323 | 323 | missing='', |
|
324 | 324 | preparer=strip_whitespace, |
@@ -38,6 +38,7 b' class AuthenticationPluginRegistry(objec' | |||
|
38 | 38 | |
|
39 | 39 | def __init__(self, settings): |
|
40 | 40 | self._plugins = {} |
|
41 | self._plugins_for_auth = None | |
|
41 | 42 | self._fallback_plugin = settings.get(self.fallback_plugin_key, None) |
|
42 | 43 | |
|
43 | 44 | def add_authn_plugin(self, config, plugin): |
@@ -63,6 +64,10 b' class AuthenticationPluginRegistry(objec' | |||
|
63 | 64 | if plugin.uid == plugin_uid: |
|
64 | 65 | return plugin |
|
65 | 66 | |
|
67 | def invalidate_plugins_for_auth(self): | |
|
68 | log.debug('Invalidating cached plugins for authentication') | |
|
69 | self._plugins_for_auth = None | |
|
70 | ||
|
66 | 71 | def get_plugins_for_authentication(self): |
|
67 | 72 | """ |
|
68 | 73 | Returns a list of plugins which should be consulted when authenticating |
@@ -70,6 +75,9 b' class AuthenticationPluginRegistry(objec' | |||
|
70 | 75 | Additionally it includes the fallback plugin from the INI file, if |
|
71 | 76 | `rhodecode.auth_plugin_fallback` is set to a plugin ID. |
|
72 | 77 | """ |
|
78 | if self._plugins_for_auth is not None: | |
|
79 | return self._plugins_for_auth | |
|
80 | ||
|
73 | 81 | plugins = [] |
|
74 | 82 | |
|
75 | 83 | # Add all enabled and active plugins to the list. We iterate over the |
@@ -80,6 +88,9 b' class AuthenticationPluginRegistry(objec' | |||
|
80 | 88 | plugin = self.get_plugin(plugin_id) |
|
81 | 89 | if plugin is not None and plugin.is_active( |
|
82 | 90 | plugin_cached_settings=raw_settings): |
|
91 | ||
|
92 | # inject settings into plugin, we can re-use the DB fetched settings here | |
|
93 | plugin._settings = plugin._propagate_settings(raw_settings) | |
|
83 | 94 | plugins.append(plugin) |
|
84 | 95 | |
|
85 | 96 | # Add the fallback plugin from ini file. |
@@ -89,6 +100,8 b' class AuthenticationPluginRegistry(objec' | |||
|
89 | 100 | self._fallback_plugin) |
|
90 | 101 | plugin = self.get_plugin(self._fallback_plugin) |
|
91 | 102 | if plugin is not None and plugin not in plugins: |
|
103 | plugin._settings = plugin._propagate_settings(raw_settings) | |
|
92 | 104 | plugins.append(plugin) |
|
93 | 105 | |
|
94 | return plugins | |
|
106 | self._plugins_for_auth = plugins | |
|
107 | return self._plugins_for_auth |
@@ -99,11 +99,12 b' class AuthnPluginViewBase(BaseAppView):' | |||
|
99 | 99 | for name, value in valid_data.items(): |
|
100 | 100 | self.plugin.create_or_update_setting(name, value) |
|
101 | 101 | Session().commit() |
|
102 | SettingsModel().invalidate_settings_cache() | |
|
102 | 103 | |
|
103 | 104 | # Display success message and redirect. |
|
104 | 105 | h.flash(_('Auth settings updated successfully.'), category='success') |
|
105 | redirect_to = self.request.resource_path( | |
|
106 | self.context, route_name='auth_home') | |
|
106 | redirect_to = self.request.resource_path(self.context, route_name='auth_home') | |
|
107 | ||
|
107 | 108 | return HTTPFound(redirect_to) |
|
108 | 109 | |
|
109 | 110 | |
@@ -159,7 +160,7 b' class AuthSettingsView(BaseAppView):' | |||
|
159 | 160 | 'auth_plugins', plugins) |
|
160 | 161 | Session().add(setting) |
|
161 | 162 | Session().commit() |
|
162 | ||
|
163 | SettingsModel().invalidate_settings_cache() | |
|
163 | 164 | h.flash(_('Auth settings updated successfully.'), category='success') |
|
164 | 165 | except formencode.Invalid as errors: |
|
165 | 166 | e = errors.error_dict or {} |
@@ -174,6 +175,6 b' class AuthSettingsView(BaseAppView):' | |||
|
174 | 175 | h.flash(_('Error occurred during update of auth settings.'), |
|
175 | 176 | category='error') |
|
176 | 177 | |
|
177 | redirect_to = self.request.resource_path( | |
|
178 | self.context, route_name='auth_home') | |
|
178 | redirect_to = self.request.resource_path(self.context, route_name='auth_home') | |
|
179 | ||
|
179 | 180 | return HTTPFound(redirect_to) |
@@ -95,3 +95,5 b' def inspect_getargspec():' | |||
|
95 | 95 | return inspect.ArgSpec(args, varargs, varkw, func.func_defaults) |
|
96 | 96 | |
|
97 | 97 | inspect.getargspec = custom_getargspec |
|
98 | ||
|
99 | return inspect |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
@@ -151,20 +151,22 b' def _store_log(action_name, action_data,' | |||
|
151 | 151 | |
|
152 | 152 | |
|
153 | 153 | def store_web(*args, **kwargs): |
|
154 |
|
|
|
155 |
|
|
|
156 |
|
|
|
157 |
|
|
|
158 | }) | |
|
154 | action_data = {} | |
|
155 | org_action_data = kwargs.pop('action_data', {}) | |
|
156 | action_data.update(org_action_data) | |
|
157 | action_data['source'] = SOURCE_WEB | |
|
158 | kwargs['action_data'] = action_data | |
|
159 | ||
|
159 | 160 | return store(*args, **kwargs) |
|
160 | 161 | |
|
161 | 162 | |
|
162 | 163 | def store_api(*args, **kwargs): |
|
163 |
|
|
|
164 |
|
|
|
165 |
|
|
|
166 |
|
|
|
167 | }) | |
|
164 | action_data = {} | |
|
165 | org_action_data = kwargs.pop('action_data', {}) | |
|
166 | action_data.update(org_action_data) | |
|
167 | action_data['source'] = SOURCE_API | |
|
168 | kwargs['action_data'] = action_data | |
|
169 | ||
|
168 | 170 | return store(*args, **kwargs) |
|
169 | 171 | |
|
170 | 172 |
@@ -24,7 +24,6 b' authentication and permission libraries' | |||
|
24 | 24 | |
|
25 | 25 | import os |
|
26 | 26 | import time |
|
27 | import inspect | |
|
28 | 27 | import collections |
|
29 | 28 | import fnmatch |
|
30 | 29 | import hashlib |
@@ -2013,6 +2012,7 b' class PermsFunction(object):' | |||
|
2013 | 2012 | self.user_group_name = None |
|
2014 | 2013 | |
|
2015 | 2014 | def __bool__(self): |
|
2015 | import inspect | |
|
2016 | 2016 | frame = inspect.currentframe() |
|
2017 | 2017 | stack_trace = traceback.format_stack(frame) |
|
2018 | 2018 | log.error('Checking bool value on a class instance of perm ' |
@@ -211,8 +211,9 b' def vcs_operation_context(' | |||
|
211 | 211 | class BasicAuth(AuthBasicAuthenticator): |
|
212 | 212 | |
|
213 | 213 | def __init__(self, realm, authfunc, registry, auth_http_code=None, |
|
214 | initial_call_detection=False, acl_repo_name=None): | |
|
214 | initial_call_detection=False, acl_repo_name=None, rc_realm=''): | |
|
215 | 215 | self.realm = realm |
|
216 | self.rc_realm = rc_realm | |
|
216 | 217 | self.initial_call = initial_call_detection |
|
217 | 218 | self.authfunc = authfunc |
|
218 | 219 | self.registry = registry |
@@ -227,7 +228,7 b' class BasicAuth(AuthBasicAuthenticator):' | |||
|
227 | 228 | return HTTPForbidden |
|
228 | 229 | |
|
229 | 230 | def get_rc_realm(self): |
|
230 |
return safe_str(self.r |
|
|
231 | return safe_str(self.rc_realm) | |
|
231 | 232 | |
|
232 | 233 | def build_authentication(self): |
|
233 | 234 | head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm) |
@@ -288,7 +289,7 b' def attach_context_attributes(context, r' | |||
|
288 | 289 | """ |
|
289 | 290 | config = request.registry.settings |
|
290 | 291 | |
|
291 | rc_config = SettingsModel().get_all_settings(cache=True) | |
|
292 | rc_config = SettingsModel().get_all_settings(cache=True, from_request=False) | |
|
292 | 293 | context.rc_config = rc_config |
|
293 | 294 | context.rhodecode_version = rhodecode.__version__ |
|
294 | 295 | context.rhodecode_edition = config.get('rhodecode.edition') |
@@ -66,11 +66,12 b' markdown_tags = [' | |||
|
66 | 66 | markdown_attrs = { |
|
67 | 67 | "*": ["class", "style", "align"], |
|
68 | 68 | "img": ["src", "alt", "title"], |
|
69 | "a": ["href", "alt", "title", "name"], | |
|
69 | "a": ["href", "alt", "title", "name", "data-hovercard-alt", "data-hovercard-url"], | |
|
70 | 70 | "abbr": ["title"], |
|
71 | 71 | "acronym": ["title"], |
|
72 | 72 | "pre": ["lang"], |
|
73 | "input": ["type", "disabled", "checked"] | |
|
73 | "input": ["type", "disabled", "checked"], | |
|
74 | "strong": ["title", "data-hovercard-alt", "data-hovercard-url"], | |
|
74 | 75 | } |
|
75 | 76 | |
|
76 | 77 | standard_styles = [ |
@@ -421,9 +421,20 b' class DbManage(object):' | |||
|
421 | 421 | |
|
422 | 422 | :param skip_existing: |
|
423 | 423 | """ |
|
424 | defaults = [ | |
|
425 | ('auth_plugins', | |
|
426 | 'egg:rhodecode-enterprise-ce#token,egg:rhodecode-enterprise-ce#rhodecode', | |
|
427 | 'list'), | |
|
424 | 428 | |
|
425 | for k, v, t in [('auth_plugins', 'egg:rhodecode-enterprise-ce#rhodecode', 'list'), | |
|
426 | ('auth_rhodecode_enabled', 'True', 'bool')]: | |
|
429 | ('auth_authtoken_enabled', | |
|
430 | 'True', | |
|
431 | 'bool'), | |
|
432 | ||
|
433 | ('auth_rhodecode_enabled', | |
|
434 | 'True', | |
|
435 | 'bool'), | |
|
436 | ] | |
|
437 | for k, v, t in defaults: | |
|
427 | 438 | if (skip_existing and |
|
428 | 439 | SettingsModel().get_setting_by_name(k) is not None): |
|
429 | 440 | log.debug('Skipping option %s', k) |
@@ -568,19 +579,32 b' class DbManage(object):' | |||
|
568 | 579 | ('title', '', 'unicode'), |
|
569 | 580 | ('pre_code', '', 'unicode'), |
|
570 | 581 | ('post_code', '', 'unicode'), |
|
582 | ||
|
583 | # Visual | |
|
571 | 584 | ('show_public_icon', True, 'bool'), |
|
572 | 585 | ('show_private_icon', True, 'bool'), |
|
573 | 586 | ('stylify_metatags', False, 'bool'), |
|
574 | 587 | ('dashboard_items', 100, 'int'), |
|
575 | 588 | ('admin_grid_items', 25, 'int'), |
|
589 | ||
|
590 | ('markup_renderer', 'markdown', 'unicode'), | |
|
591 | ||
|
576 | 592 | ('show_version', True, 'bool'), |
|
593 | ('show_revision_number', True, 'bool'), | |
|
594 | ('show_sha_length', 12, 'int'), | |
|
595 | ||
|
577 | 596 | ('use_gravatar', False, 'bool'), |
|
578 | 597 | ('gravatar_url', User.DEFAULT_GRAVATAR_URL, 'unicode'), |
|
598 | ||
|
579 | 599 | ('clone_uri_tmpl', Repository.DEFAULT_CLONE_URI, 'unicode'), |
|
600 | ('clone_uri_ssh_tmpl', Repository.DEFAULT_CLONE_URI_SSH, 'unicode'), | |
|
580 | 601 | ('support_url', '', 'unicode'), |
|
581 | 602 | ('update_url', RhodeCodeSetting.DEFAULT_UPDATE_URL, 'unicode'), |
|
582 | ('show_revision_number', True, 'bool'), | |
|
583 | ('show_sha_length', 12, 'int'), | |
|
603 | ||
|
604 | # VCS Settings | |
|
605 | ('pr_merge_enabled', True, 'bool'), | |
|
606 | ('use_outdated_comments', True, 'bool'), | |
|
607 | ('diff_cache', True, 'bool'), | |
|
584 | 608 | ] |
|
585 | 609 | |
|
586 | 610 | for key, val, type_ in settings: |
@@ -598,9 +598,10 b' class _Message(object):' | |||
|
598 | 598 | * ``category``: the category specified when the message was created. |
|
599 | 599 | """ |
|
600 | 600 | |
|
601 | def __init__(self, category, message): | |
|
601 | def __init__(self, category, message, sub_data=None): | |
|
602 | 602 | self.category = category |
|
603 | 603 | self.message = message |
|
604 | self.sub_data = sub_data or {} | |
|
604 | 605 | |
|
605 | 606 | def __str__(self): |
|
606 | 607 | return self.message |
@@ -663,7 +664,17 b' class Flash(object):' | |||
|
663 | 664 | # of strings. |
|
664 | 665 | for cat in self.categories: |
|
665 | 666 | for msg in session.pop_flash(queue=cat): |
|
666 | messages.append(_Message(cat, msg)) | |
|
667 | sub_data = {} | |
|
668 | if hasattr(msg, 'rsplit'): | |
|
669 | flash_data = msg.rsplit('|DELIM|', 1) | |
|
670 | org_message = flash_data[0] | |
|
671 | if len(flash_data) > 1: | |
|
672 | sub_data = json.loads(flash_data[1]) | |
|
673 | else: | |
|
674 | org_message = msg | |
|
675 | ||
|
676 | messages.append(_Message(cat, org_message, sub_data=sub_data)) | |
|
677 | ||
|
667 | 678 | # Map messages from the default queue to the 'notice' category. |
|
668 | 679 | for msg in session.pop_flash(): |
|
669 | 680 | messages.append(_Message('notice', msg)) |
@@ -673,25 +684,16 b' class Flash(object):' | |||
|
673 | 684 | |
|
674 | 685 | def json_alerts(self, session=None, request=None): |
|
675 | 686 | payloads = [] |
|
676 | messages = flash.pop_messages(session=session, request=request) | |
|
677 |
|
|
|
678 | for message in messages: | |
|
679 |
|
|
|
680 |
|
|
|
681 | flash_data = message.message.rsplit('|DELIM|', 1) | |
|
682 | org_message = flash_data[0] | |
|
683 |
|
|
|
684 | subdata = json.loads(flash_data[1]) | |
|
685 |
|
|
|
686 | org_message = message.message | |
|
687 | payloads.append({ | |
|
688 | 'message': { | |
|
689 | 'message': u'{}'.format(org_message), | |
|
690 | 'level': message.category, | |
|
691 | 'force': True, | |
|
692 | 'subdata': subdata | |
|
693 | } | |
|
694 | }) | |
|
687 | messages = flash.pop_messages(session=session, request=request) or [] | |
|
688 | for message in messages: | |
|
689 | payloads.append({ | |
|
690 | 'message': { | |
|
691 | 'message': u'{}'.format(message.message), | |
|
692 | 'level': message.category, | |
|
693 | 'force': True, | |
|
694 | 'subdata': message.sub_data | |
|
695 | } | |
|
696 | }) | |
|
695 | 697 | return json.dumps(payloads) |
|
696 | 698 | |
|
697 | 699 | def __call__(self, message, category=None, ignore_duplicate=True, |
@@ -1514,6 +1516,9 b' def get_active_pattern_entries(repo_name' | |||
|
1514 | 1516 | return active_entries |
|
1515 | 1517 | |
|
1516 | 1518 | |
|
1519 | pr_pattern_re = re.compile(r'(?:(?:^!)|(?: !))(\d+)') | |
|
1520 | ||
|
1521 | ||
|
1517 | 1522 | def process_patterns(text_string, repo_name, link_format='html', active_entries=None): |
|
1518 | 1523 | |
|
1519 | 1524 | allowed_formats = ['html', 'rst', 'markdown', |
@@ -1522,7 +1527,10 b' def process_patterns(text_string, repo_n' | |||
|
1522 | 1527 | raise ValueError('Link format can be only one of:{} got {}'.format( |
|
1523 | 1528 | allowed_formats, link_format)) |
|
1524 | 1529 | |
|
1525 | active_entries = active_entries or get_active_pattern_entries(repo_name) | |
|
1530 | if active_entries is None: | |
|
1531 | log.debug('Fetch active patterns for repo: %s', repo_name) | |
|
1532 | active_entries = get_active_pattern_entries(repo_name) | |
|
1533 | ||
|
1526 | 1534 | issues_data = [] |
|
1527 | 1535 | new_text = text_string |
|
1528 | 1536 | |
@@ -1537,11 +1545,14 b' def process_patterns(text_string, repo_n' | |||
|
1537 | 1545 | log.debug('issue tracker entry: uid: `%s` PAT:%s URL:%s PREFIX:%s', |
|
1538 | 1546 | uid, entry['pat'], entry['url'], entry['pref']) |
|
1539 | 1547 | |
|
1540 | try: | |
|
1541 |
pattern = |
|
|
1542 | except re.error: | |
|
1543 | log.exception('issue tracker pattern: `%s` failed to compile', entry['pat']) | |
|
1544 | continue | |
|
1548 | if entry.get('pat_compiled'): | |
|
1549 | pattern = entry['pat_compiled'] | |
|
1550 | else: | |
|
1551 | try: | |
|
1552 | pattern = re.compile(r'%s' % entry['pat']) | |
|
1553 | except re.error: | |
|
1554 | log.exception('issue tracker pattern: `%s` failed to compile', entry['pat']) | |
|
1555 | continue | |
|
1545 | 1556 | |
|
1546 | 1557 | data_func = partial( |
|
1547 | 1558 | _process_url_func, repo_name=repo_name, entry=entry, uid=uid, |
@@ -1569,7 +1580,7 b' def process_patterns(text_string, repo_n' | |||
|
1569 | 1580 | pr_url_func = partial( |
|
1570 | 1581 | _process_url_func, repo_name=repo_name, entry=pr_entry, uid=None, |
|
1571 | 1582 | link_format=link_format+'+hovercard') |
|
1572 |
new_text = |
|
|
1583 | new_text = pr_pattern_re.sub(pr_url_func, new_text) | |
|
1573 | 1584 | log.debug('processed !pr pattern') |
|
1574 | 1585 | |
|
1575 | 1586 | return new_text, issues_data |
@@ -1580,6 +1591,7 b' def urlify_commit_message(commit_text, r' | |||
|
1580 | 1591 | Parses given text message and makes proper links. |
|
1581 | 1592 | issues are linked to given issue-server, and rest is a commit link |
|
1582 | 1593 | """ |
|
1594 | ||
|
1583 | 1595 | def escaper(_text): |
|
1584 | 1596 | return _text.replace('<', '<').replace('>', '>') |
|
1585 | 1597 | |
@@ -1636,7 +1648,7 b' def renderer_from_filename(filename, exc' | |||
|
1636 | 1648 | |
|
1637 | 1649 | |
|
1638 | 1650 | def render(source, renderer='rst', mentions=False, relative_urls=None, |
|
1639 | repo_name=None): | |
|
1651 | repo_name=None, active_pattern_entries=None): | |
|
1640 | 1652 | |
|
1641 | 1653 | def maybe_convert_relative_links(html_source): |
|
1642 | 1654 | if relative_urls: |
@@ -1651,7 +1663,8 b" def render(source, renderer='rst', menti" | |||
|
1651 | 1663 | if repo_name: |
|
1652 | 1664 | # process patterns on comments if we pass in repo name |
|
1653 | 1665 | source, issues = process_patterns( |
|
1654 |
source, repo_name, link_format='rst' |
|
|
1666 | source, repo_name, link_format='rst', | |
|
1667 | active_entries=active_pattern_entries) | |
|
1655 | 1668 | |
|
1656 | 1669 | return literal( |
|
1657 | 1670 | '<div class="rst-block">%s</div>' % |
@@ -1662,7 +1675,8 b" def render(source, renderer='rst', menti" | |||
|
1662 | 1675 | if repo_name: |
|
1663 | 1676 | # process patterns on comments if we pass in repo name |
|
1664 | 1677 | source, issues = process_patterns( |
|
1665 |
source, repo_name, link_format='markdown' |
|
|
1678 | source, repo_name, link_format='markdown', | |
|
1679 | active_entries=active_pattern_entries) | |
|
1666 | 1680 | |
|
1667 | 1681 | return literal( |
|
1668 | 1682 | '<div class="markdown-block">%s</div>' % |
@@ -47,6 +47,14 b' log = logging.getLogger(__name__)' | |||
|
47 | 47 | # default renderer used to generate automated comments |
|
48 | 48 | DEFAULT_COMMENTS_RENDERER = 'rst' |
|
49 | 49 | |
|
50 | try: | |
|
51 | from lxml.html import fromstring | |
|
52 | from lxml.html import tostring | |
|
53 | except ImportError: | |
|
54 | log.exception('Failed to import lxml') | |
|
55 | fromstring = None | |
|
56 | tostring = None | |
|
57 | ||
|
50 | 58 | |
|
51 | 59 | class CustomHTMLTranslator(writers.html4css1.HTMLTranslator): |
|
52 | 60 | """ |
@@ -81,11 +89,7 b' def relative_links(html_source, server_p' | |||
|
81 | 89 | if not html_source: |
|
82 | 90 | return html_source |
|
83 | 91 | |
|
84 | try: | |
|
85 | from lxml.html import fromstring | |
|
86 | from lxml.html import tostring | |
|
87 | except ImportError: | |
|
88 | log.exception('Failed to import lxml') | |
|
92 | if not fromstring and tostring: | |
|
89 | 93 | return html_source |
|
90 | 94 | |
|
91 | 95 | try: |
@@ -210,6 +214,8 b' class MarkupRenderer(object):' | |||
|
210 | 214 | URL_PAT = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]' |
|
211 | 215 | r'|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)') |
|
212 | 216 | |
|
217 | MENTION_PAT = re.compile(MENTIONS_REGEX) | |
|
218 | ||
|
213 | 219 | extensions = ['markdown.extensions.codehilite', 'markdown.extensions.extra', |
|
214 | 220 | 'markdown.extensions.def_list', 'markdown.extensions.sane_lists'] |
|
215 | 221 | |
@@ -348,6 +354,26 b' class MarkupRenderer(object):' | |||
|
348 | 354 | return cls.URL_PAT.sub(url_func, text) |
|
349 | 355 | |
|
350 | 356 | @classmethod |
|
357 | def convert_mentions(cls, text, mode): | |
|
358 | mention_pat = cls.MENTION_PAT | |
|
359 | ||
|
360 | def wrapp(match_obj): | |
|
361 | uname = match_obj.groups()[0] | |
|
362 | hovercard_url = "pyroutes.url('hovercard_username', {'username': '%s'});" % uname | |
|
363 | ||
|
364 | if mode == 'markdown': | |
|
365 | tmpl = '<strong class="tooltip-hovercard" data-hovercard-alt="{uname}" data-hovercard-url="{hovercard_url}">@{uname}</strong>' | |
|
366 | elif mode == 'rst': | |
|
367 | tmpl = ' **@{uname}** ' | |
|
368 | else: | |
|
369 | raise ValueError('mode must be rst or markdown') | |
|
370 | ||
|
371 | return tmpl.format(**{'uname': uname, | |
|
372 | 'hovercard_url': hovercard_url}) | |
|
373 | ||
|
374 | return mention_pat.sub(wrapp, text).strip() | |
|
375 | ||
|
376 | @classmethod | |
|
351 | 377 | def plain(cls, source, universal_newline=True, leading_newline=True): |
|
352 | 378 | source = safe_unicode(source) |
|
353 | 379 | if universal_newline: |
@@ -378,12 +404,7 b' class MarkupRenderer(object):' | |||
|
378 | 404 | cls.extensions, cls.output_format) |
|
379 | 405 | |
|
380 | 406 | if mentions: |
|
381 | mention_pat = re.compile(MENTIONS_REGEX) | |
|
382 | ||
|
383 | def wrapp(match_obj): | |
|
384 | uname = match_obj.groups()[0] | |
|
385 | return ' **@%(uname)s** ' % {'uname': uname} | |
|
386 | mention_hl = mention_pat.sub(wrapp, source).strip() | |
|
407 | mention_hl = cls.convert_mentions(source, mode='markdown') | |
|
387 | 408 | # we extracted mentions render with this using Mentions false |
|
388 | 409 | return cls.markdown(mention_hl, safe=safe, flavored=flavored, |
|
389 | 410 | mentions=False) |
@@ -409,12 +430,7 b' class MarkupRenderer(object):' | |||
|
409 | 430 | @classmethod |
|
410 | 431 | def rst(cls, source, safe=True, mentions=False, clean_html=False): |
|
411 | 432 | if mentions: |
|
412 | mention_pat = re.compile(MENTIONS_REGEX) | |
|
413 | ||
|
414 | def wrapp(match_obj): | |
|
415 | uname = match_obj.groups()[0] | |
|
416 | return ' **@%(uname)s** ' % {'uname': uname} | |
|
417 | mention_hl = mention_pat.sub(wrapp, source).strip() | |
|
433 | mention_hl = cls.convert_mentions(source, mode='rst') | |
|
418 | 434 | # we extracted mentions render with this using Mentions false |
|
419 | 435 | return cls.rst(mention_hl, safe=safe, mentions=False) |
|
420 | 436 | |
@@ -443,7 +459,7 b' class MarkupRenderer(object):' | |||
|
443 | 459 | except Exception: |
|
444 | 460 | log.exception('Error when rendering RST') |
|
445 | 461 | if safe: |
|
446 |
log.debug('Fallback |
|
|
462 | log.debug('Fallback to render in plain mode') | |
|
447 | 463 | return cls.plain(source) |
|
448 | 464 | else: |
|
449 | 465 | raise |
@@ -133,15 +133,16 b' class SimpleVCS(object):' | |||
|
133 | 133 | self.config = config |
|
134 | 134 | # re-populated by specialized middleware |
|
135 | 135 | self.repo_vcs_config = base.Config() |
|
136 | self.rhodecode_settings = SettingsModel().get_all_settings(cache=True) | |
|
137 | 136 | |
|
138 | registry.rhodecode_settings = self.rhodecode_settings | |
|
137 | rc_settings = SettingsModel().get_all_settings(cache=True, from_request=False) | |
|
138 | realm = rc_settings.get('rhodecode_realm') or 'RhodeCode AUTH' | |
|
139 | ||
|
139 | 140 | # authenticate this VCS request using authfunc |
|
140 | 141 | auth_ret_code_detection = \ |
|
141 | 142 | str2bool(self.config.get('auth_ret_code_detection', False)) |
|
142 | 143 | self.authenticate = BasicAuth( |
|
143 | 144 | '', authenticate, registry, config.get('auth_ret_code'), |
|
144 | auth_ret_code_detection) | |
|
145 | auth_ret_code_detection, rc_realm=realm) | |
|
145 | 146 | self.ip_addr = '0.0.0.0' |
|
146 | 147 | |
|
147 | 148 | @LazyProperty |
@@ -32,10 +32,14 b' def BeakerSessionFactoryConfig(**options' | |||
|
32 | 32 | |
|
33 | 33 | def session_callback(request, response): |
|
34 | 34 | exception = getattr(request, 'exception', None) |
|
35 | if (exception is None or self._cookie_on_exception) and self.accessed(): | |
|
35 | file_response = getattr(request, '_file_response', None) | |
|
36 | ||
|
37 | if file_response is None \ | |
|
38 | and (exception is None or self._cookie_on_exception) \ | |
|
39 | and self.accessed(): | |
|
36 | 40 | self.persist() |
|
37 | 41 | headers = self.__dict__['_headers'] |
|
38 |
if headers |
|
|
42 | if headers.get('set_cookie') and headers.get('cookie_out'): | |
|
39 | 43 | response.headerlist.append(('Set-Cookie', headers['cookie_out'])) |
|
40 | 44 | request.add_response_callback(session_callback) |
|
41 | 45 |
@@ -148,6 +148,15 b' class HGUpdateCaches(MaintenanceTask):' | |||
|
148 | 148 | return res |
|
149 | 149 | |
|
150 | 150 | |
|
151 | class HGRebuildFnCaches(MaintenanceTask): | |
|
152 | human_name = 'HG rebuild fn caches' | |
|
153 | ||
|
154 | def run(self): | |
|
155 | instance = self.db_repo.scm_instance() | |
|
156 | res = instance.hg_rebuild_fn_cache() | |
|
157 | return res | |
|
158 | ||
|
159 | ||
|
151 | 160 | class SVNVerify(MaintenanceTask): |
|
152 | 161 | human_name = 'SVN Verify repo' |
|
153 | 162 | |
@@ -162,7 +171,7 b' class RepoMaintenance(object):' | |||
|
162 | 171 | Performs maintenance of repository based on it's type |
|
163 | 172 | """ |
|
164 | 173 | tasks = { |
|
165 | 'hg': [HGVerify, HGUpdateCaches], | |
|
174 | 'hg': [HGVerify, HGUpdateCaches, HGRebuildFnCaches], | |
|
166 | 175 | 'git': [GitFSCK, GitGC, GitRepack], |
|
167 | 176 | 'svn': [SVNVerify], |
|
168 | 177 | } |
@@ -432,8 +432,11 b' class GitCommit(base.BaseCommit):' | |||
|
432 | 432 | """ |
|
433 | 433 | if not self.parents: |
|
434 | 434 | return list(self._get_file_nodes()) |
|
435 | return AddedFileNodesGenerator( | |
|
436 | [n for n in self._get_paths_for_status('added')], self) | |
|
435 | return AddedFileNodesGenerator(self.added_paths, self) | |
|
436 | ||
|
437 | @LazyProperty | |
|
438 | def added_paths(self): | |
|
439 | return [n for n in self._get_paths_for_status('added')] | |
|
437 | 440 | |
|
438 | 441 | @LazyProperty |
|
439 | 442 | def changed(self): |
@@ -442,8 +445,11 b' class GitCommit(base.BaseCommit):' | |||
|
442 | 445 | """ |
|
443 | 446 | if not self.parents: |
|
444 | 447 | return [] |
|
445 | return ChangedFileNodesGenerator( | |
|
446 | [n for n in self._get_paths_for_status('modified')], self) | |
|
448 | return ChangedFileNodesGenerator(self.changed_paths, self) | |
|
449 | ||
|
450 | @LazyProperty | |
|
451 | def changed_paths(self): | |
|
452 | return [n for n in self._get_paths_for_status('modified')] | |
|
447 | 453 | |
|
448 | 454 | @LazyProperty |
|
449 | 455 | def removed(self): |
@@ -452,8 +458,11 b' class GitCommit(base.BaseCommit):' | |||
|
452 | 458 | """ |
|
453 | 459 | if not self.parents: |
|
454 | 460 | return [] |
|
455 | return RemovedFileNodesGenerator( | |
|
456 | [n for n in self._get_paths_for_status('deleted')], self) | |
|
461 | return RemovedFileNodesGenerator(self.removed_paths, self) | |
|
462 | ||
|
463 | @LazyProperty | |
|
464 | def removed_paths(self): | |
|
465 | return [n for n in self._get_paths_for_status('deleted')] | |
|
457 | 466 | |
|
458 | 467 | def _get_submodule_url(self, submodule_path): |
|
459 | 468 | git_modules_path = '.gitmodules' |
@@ -472,7 +481,7 b' class GitCommit(base.BaseCommit):' | |||
|
472 | 481 | for line in _content.splitlines(): |
|
473 | 482 | yield line |
|
474 | 483 | |
|
475 | parser = configparser.ConfigParser() | |
|
484 | parser = configparser.RawConfigParser() | |
|
476 | 485 | parser.read_file(iter_content(submodules_node.content)) |
|
477 | 486 | |
|
478 | 487 | for section in parser.sections(): |
@@ -372,18 +372,30 b' class MercurialCommit(base.BaseCommit):' | |||
|
372 | 372 | """ |
|
373 | 373 | Returns list of added ``FileNode`` objects. |
|
374 | 374 | """ |
|
375 |
return AddedFileNodesGenerator( |
|
|
375 | return AddedFileNodesGenerator(self.added_paths, self) | |
|
376 | ||
|
377 | @LazyProperty | |
|
378 | def added_paths(self): | |
|
379 | return [n for n in self.status[1]] | |
|
376 | 380 | |
|
377 | 381 | @property |
|
378 | 382 | def changed(self): |
|
379 | 383 | """ |
|
380 | 384 | Returns list of modified ``FileNode`` objects. |
|
381 | 385 | """ |
|
382 |
return ChangedFileNodesGenerator( |
|
|
386 | return ChangedFileNodesGenerator(self.changed_paths, self) | |
|
387 | ||
|
388 | @LazyProperty | |
|
389 | def changed_paths(self): | |
|
390 | return [n for n in self.status[0]] | |
|
383 | 391 | |
|
384 | 392 | @property |
|
385 | 393 | def removed(self): |
|
386 | 394 | """ |
|
387 | 395 | Returns list of removed ``FileNode`` objects. |
|
388 | 396 | """ |
|
389 |
return RemovedFileNodesGenerator( |
|
|
397 | return RemovedFileNodesGenerator(self.removed_paths, self) | |
|
398 | ||
|
399 | @LazyProperty | |
|
400 | def removed_paths(self): | |
|
401 | return [n for n in self.status[2]] |
@@ -290,6 +290,12 b' class MercurialRepository(BaseRepository' | |||
|
290 | 290 | self._remote.invalidate_vcs_cache() |
|
291 | 291 | return update_cache |
|
292 | 292 | |
|
293 | def hg_rebuild_fn_cache(self): | |
|
294 | update_cache = self._remote.hg_rebuild_fn_cache() | |
|
295 | ||
|
296 | self._remote.invalidate_vcs_cache() | |
|
297 | return update_cache | |
|
298 | ||
|
293 | 299 | def get_common_ancestor(self, commit_id1, commit_id2, repo2): |
|
294 | 300 | if commit_id1 == commit_id2: |
|
295 | 301 | return commit_id1 |
@@ -218,18 +218,27 b' class SubversionCommit(base.BaseCommit):' | |||
|
218 | 218 | |
|
219 | 219 | @property |
|
220 | 220 | def added(self): |
|
221 | return nodes.AddedFileNodesGenerator( | |
|
222 | self._changes_cache['added'], self) | |
|
221 | return nodes.AddedFileNodesGenerator(self.added_paths, self) | |
|
222 | ||
|
223 | @LazyProperty | |
|
224 | def added_paths(self): | |
|
225 | return [n for n in self._changes_cache['added']] | |
|
223 | 226 | |
|
224 | 227 | @property |
|
225 | 228 | def changed(self): |
|
226 | return nodes.ChangedFileNodesGenerator( | |
|
227 | self._changes_cache['changed'], self) | |
|
229 | return nodes.ChangedFileNodesGenerator(self.changed_paths, self) | |
|
230 | ||
|
231 | @LazyProperty | |
|
232 | def changed_paths(self): | |
|
233 | return [n for n in self._changes_cache['changed']] | |
|
228 | 234 | |
|
229 | 235 | @property |
|
230 | 236 | def removed(self): |
|
231 | return nodes.RemovedFileNodesGenerator( | |
|
232 | self._changes_cache['removed'], self) | |
|
237 | return nodes.RemovedFileNodesGenerator(self.removed_paths, self) | |
|
238 | ||
|
239 | @LazyProperty | |
|
240 | def removed_paths(self): | |
|
241 | return [n for n in self._changes_cache['removed']] | |
|
233 | 242 | |
|
234 | 243 | |
|
235 | 244 | def _date_from_svn_properties(properties): |
@@ -18,6 +18,19 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | DEFAULTS = { | |
|
22 | 'encodings_map': {'.gz': 'gzip', | |
|
23 | '.Z': 'compress', | |
|
24 | '.bz2': 'bzip2', | |
|
25 | '.xz': 'xz'}, | |
|
26 | 'suffix_map': {'.svgz': '.svg.gz', | |
|
27 | '.tgz': '.tar.gz', | |
|
28 | '.taz': '.tar.gz', | |
|
29 | '.tz': '.tar.gz', | |
|
30 | '.tbz2': '.tar.bz2', | |
|
31 | '.txz': '.tar.xz'}, | |
|
32 | } | |
|
33 | ||
|
21 | 34 | TYPES_MAP = [ |
|
22 | 35 | {'.jpg': 'image/jpg', |
|
23 | 36 | '.mid': 'audio/midi', |
@@ -1203,4 +1216,6 b' def get_mimetypes_db(extra_types=None):' | |||
|
1203 | 1216 | types_map[1].update(extra_types) |
|
1204 | 1217 | db = mimetypes.MimeTypes() |
|
1205 | 1218 | db.types_map = types_map |
|
1219 | db.encodings_map.update(DEFAULTS['encodings_map']) | |
|
1220 | db.suffix_map.update(DEFAULTS['suffix_map']) | |
|
1206 | 1221 | return db |
@@ -1025,6 +1025,17 b' class User(Base, BaseModel):' | |||
|
1025 | 1025 | return qry.all() |
|
1026 | 1026 | |
|
1027 | 1027 | @classmethod |
|
1028 | def get_all_user_ids(cls, only_active=True): | |
|
1029 | """ | |
|
1030 | Returns all users IDs | |
|
1031 | """ | |
|
1032 | qry = Session().query(User.user_id) | |
|
1033 | ||
|
1034 | if only_active: | |
|
1035 | qry = qry.filter(User.active == true()) | |
|
1036 | return [x.user_id for x in qry] | |
|
1037 | ||
|
1038 | @classmethod | |
|
1028 | 1039 | def get_default_user(cls, cache=False, refresh=False): |
|
1029 | 1040 | user = User.get_by_username(User.DEFAULT_USER, cache=cache) |
|
1030 | 1041 | if user is None: |
@@ -3890,8 +3901,8 b' class _SetState(object):' | |||
|
3890 | 3901 | self._current_state = None |
|
3891 | 3902 | |
|
3892 | 3903 | def __enter__(self): |
|
3893 | log.debug('StateLock: entering set state context, setting state to: `%s`', | |
|
3894 | self._pr_state) | |
|
3904 | log.debug('StateLock: entering set state context of pr %s, setting state to: `%s`', | |
|
3905 | self._pr, self._pr_state) | |
|
3895 | 3906 | self.set_pr_state(self._pr_state) |
|
3896 | 3907 | return self |
|
3897 | 3908 | |
@@ -3901,8 +3912,9 b' class _SetState(object):' | |||
|
3901 | 3912 | return None |
|
3902 | 3913 | |
|
3903 | 3914 | self.set_pr_state(self._org_state) |
|
3904 | log.debug('StateLock: exiting set state context, setting state to: `%s`', | |
|
3905 | self._org_state) | |
|
3915 | log.debug('StateLock: exiting set state context of pr %s, setting state to: `%s`', | |
|
3916 | self._pr, self._org_state) | |
|
3917 | ||
|
3906 | 3918 | @property |
|
3907 | 3919 | def state(self): |
|
3908 | 3920 | return self._current_state |
@@ -4285,6 +4297,7 b' class PullRequest(Base, _PullRequestBase' | |||
|
4285 | 4297 | def __json__(self): |
|
4286 | 4298 | return { |
|
4287 | 4299 | 'revisions': self.revisions, |
|
4300 | 'versions': self.versions_count | |
|
4288 | 4301 | } |
|
4289 | 4302 | |
|
4290 | 4303 | def calculated_review_status(self): |
@@ -4307,6 +4320,14 b' class PullRequest(Base, _PullRequestBase' | |||
|
4307 | 4320 | vcs_obj = self.target_repo.scm_instance() |
|
4308 | 4321 | return vcs_obj.get_shadow_instance(shadow_repository_path) |
|
4309 | 4322 | |
|
4323 | @property | |
|
4324 | def versions_count(self): | |
|
4325 | """ | |
|
4326 | return number of versions this PR have, e.g a PR that once been | |
|
4327 | updated will have 2 versions | |
|
4328 | """ | |
|
4329 | return self.versions.count() + 1 | |
|
4330 | ||
|
4310 | 4331 | |
|
4311 | 4332 | class PullRequestVersion(Base, _PullRequestBase): |
|
4312 | 4333 | __tablename__ = 'pull_request_versions' |
@@ -21,8 +21,7 b'' | |||
|
21 | 21 | """ |
|
22 | 22 | permissions model for RhodeCode |
|
23 | 23 | """ |
|
24 | ||
|
25 | ||
|
24 | import collections | |
|
26 | 25 | import logging |
|
27 | 26 | import traceback |
|
28 | 27 | |
@@ -557,6 +556,27 b' class PermissionModel(BaseModel):' | |||
|
557 | 556 | self.sa.rollback() |
|
558 | 557 | raise |
|
559 | 558 | |
|
559 | def get_users_with_repo_write(self, db_repo): | |
|
560 | write_plus = ['repository.write', 'repository.admin'] | |
|
561 | default_user_id = User.get_default_user().user_id | |
|
562 | user_write_permissions = collections.OrderedDict() | |
|
563 | ||
|
564 | # write+ and DEFAULT user for inheritance | |
|
565 | for perm in db_repo.permissions(): | |
|
566 | if perm.permission in write_plus or perm.user_id == default_user_id: | |
|
567 | user_write_permissions[perm.user_id] = perm | |
|
568 | return user_write_permissions | |
|
569 | ||
|
570 | def get_user_groups_with_repo_write(self, db_repo): | |
|
571 | write_plus = ['repository.write', 'repository.admin'] | |
|
572 | user_group_write_permissions = collections.OrderedDict() | |
|
573 | ||
|
574 | # write+ and DEFAULT user for inheritance | |
|
575 | for p in db_repo.permission_user_groups(): | |
|
576 | if p.permission in write_plus: | |
|
577 | user_group_write_permissions[p.users_group_id] = p | |
|
578 | return user_group_write_permissions | |
|
579 | ||
|
560 | 580 | def trigger_permission_flush(self, affected_user_ids): |
|
561 | 581 | events.trigger(events.UserPermissionsChange(affected_user_ids)) |
|
562 | 582 |
@@ -26,6 +26,8 b' pull request model for RhodeCode' | |||
|
26 | 26 | |
|
27 | 27 | import json |
|
28 | 28 | import logging |
|
29 | import os | |
|
30 | ||
|
29 | 31 | import datetime |
|
30 | 32 | import urllib |
|
31 | 33 | import collections |
@@ -632,6 +634,7 b' class PullRequestModel(BaseModel):' | |||
|
632 | 634 | repo_id = pull_request.target_repo.repo_id |
|
633 | 635 | use_rebase = self._use_rebase_for_merging(pull_request) |
|
634 | 636 | close_branch = self._close_branch_before_merging(pull_request) |
|
637 | user_name = self._user_name_for_merging(pull_request, user) | |
|
635 | 638 | |
|
636 | 639 | target_ref = self._refresh_reference( |
|
637 | 640 | pull_request.target_ref_parts, target_vcs) |
@@ -647,7 +650,6 b' class PullRequestModel(BaseModel):' | |||
|
647 | 650 | target_vcs.config.set( |
|
648 | 651 | 'rhodecode', 'RC_SCM_DATA', json.dumps(extras)) |
|
649 | 652 | |
|
650 | user_name = user.short_contact | |
|
651 | 653 | merge_state = target_vcs.merge( |
|
652 | 654 | repo_id, workspace_id, target_ref, source_vcs, |
|
653 | 655 | pull_request.source_ref_parts, |
@@ -1664,6 +1666,16 b' class PullRequestModel(BaseModel):' | |||
|
1664 | 1666 | |
|
1665 | 1667 | return False |
|
1666 | 1668 | |
|
1669 | def _user_name_for_merging(self, pull_request, user): | |
|
1670 | env_user_name_attr = os.environ.get('RC_MERGE_USER_NAME_ATTR', '') | |
|
1671 | if env_user_name_attr and hasattr(user, env_user_name_attr): | |
|
1672 | user_name_attr = env_user_name_attr | |
|
1673 | else: | |
|
1674 | user_name_attr = 'short_contact' | |
|
1675 | ||
|
1676 | user_name = getattr(user, user_name_attr) | |
|
1677 | return user_name | |
|
1678 | ||
|
1667 | 1679 | def _close_branch_before_merging(self, pull_request): |
|
1668 | 1680 | repo_type = pull_request.target_repo.repo_type |
|
1669 | 1681 | if repo_type == 'hg': |
@@ -38,8 +38,7 b' from rhodecode.lib.user_log_filter impor' | |||
|
38 | 38 | from rhodecode.lib.utils import make_db_config |
|
39 | 39 | from rhodecode.lib.utils2 import ( |
|
40 | 40 | safe_str, safe_unicode, remove_prefix, obfuscate_url_pw, |
|
41 |
get_current_rhodecode_user, safe_int, |
|
|
42 | action_logger_generic) | |
|
41 | get_current_rhodecode_user, safe_int, action_logger_generic) | |
|
43 | 42 | from rhodecode.lib.vcs.backends import get_backend |
|
44 | 43 | from rhodecode.model import BaseModel |
|
45 | 44 | from rhodecode.model.db import ( |
@@ -199,9 +198,11 b' class RepoModel(BaseModel):' | |||
|
199 | 198 | |
|
200 | 199 | def get_repos_as_dict(self, repo_list=None, admin=False, |
|
201 | 200 | super_user_actions=False, short_name=None): |
|
201 | ||
|
202 | 202 | _render = get_current_request().get_partial_renderer( |
|
203 | 203 | 'rhodecode:templates/data_table/_dt_elements.mako') |
|
204 | 204 | c = _render.get_call_context() |
|
205 | h = _render.get_helpers() | |
|
205 | 206 | |
|
206 | 207 | def quick_menu(repo_name): |
|
207 | 208 | return _render('quick_menu', repo_name) |
@@ -258,7 +259,7 b' class RepoModel(BaseModel):' | |||
|
258 | 259 | "name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state, |
|
259 | 260 | repo.private, repo.archived, repo.fork), |
|
260 | 261 | |
|
261 | "desc": desc(repo.description), | |
|
262 | "desc": desc(h.escape(repo.description)), | |
|
262 | 263 | |
|
263 | 264 | "last_change": last_change(repo.updated_on), |
|
264 | 265 | |
@@ -619,13 +620,26 b' class RepoModel(BaseModel):' | |||
|
619 | 620 | changes = { |
|
620 | 621 | 'added': [], |
|
621 | 622 | 'updated': [], |
|
622 | 'deleted': [] | |
|
623 | 'deleted': [], | |
|
624 | 'default_user_changed': None | |
|
623 | 625 | } |
|
626 | ||
|
627 | repo = self._get_repo(repo) | |
|
628 | ||
|
624 | 629 | # update permissions |
|
625 | 630 | for member_id, perm, member_type in perm_updates: |
|
626 | 631 | member_id = int(member_id) |
|
627 | 632 | if member_type == 'user': |
|
628 | 633 | member_name = User.get(member_id).username |
|
634 | if member_name == User.DEFAULT_USER: | |
|
635 | # NOTE(dan): detect if we changed permissions for default user | |
|
636 | perm_obj = self.sa.query(UserRepoToPerm) \ | |
|
637 | .filter(UserRepoToPerm.user_id == member_id) \ | |
|
638 | .filter(UserRepoToPerm.repository == repo) \ | |
|
639 | .scalar() | |
|
640 | if perm_obj and perm_obj.permission.permission_name != perm: | |
|
641 | changes['default_user_changed'] = True | |
|
642 | ||
|
629 | 643 | # this updates also current one if found |
|
630 | 644 | self.grant_user_permission( |
|
631 | 645 | repo=repo, user=member_id, perm=perm) |
@@ -41,7 +41,7 b' from rhodecode.model.db import (_hash_ke' | |||
|
41 | 41 | UserGroup, Repository) |
|
42 | 42 | from rhodecode.model.settings import VcsSettingsModel, SettingsModel |
|
43 | 43 | from rhodecode.lib.caching_query import FromCache |
|
44 |
from rhodecode.lib.utils2 import action_logger_generic |
|
|
44 | from rhodecode.lib.utils2 import action_logger_generic | |
|
45 | 45 | |
|
46 | 46 | log = logging.getLogger(__name__) |
|
47 | 47 | |
@@ -353,7 +353,8 b' class RepoGroupModel(BaseModel):' | |||
|
353 | 353 | changes = { |
|
354 | 354 | 'added': [], |
|
355 | 355 | 'updated': [], |
|
356 | 'deleted': [] | |
|
356 | 'deleted': [], | |
|
357 | 'default_user_changed': None | |
|
357 | 358 | } |
|
358 | 359 | |
|
359 | 360 | def _set_perm_user(obj, user, perm): |
@@ -430,6 +431,15 b' class RepoGroupModel(BaseModel):' | |||
|
430 | 431 | member_id = int(member_id) |
|
431 | 432 | if member_type == 'user': |
|
432 | 433 | member_name = User.get(member_id).username |
|
434 | if isinstance(obj, RepoGroup) and obj == repo_group and member_name == User.DEFAULT_USER: | |
|
435 | # NOTE(dan): detect if we changed permissions for default user | |
|
436 | perm_obj = self.sa.query(UserRepoGroupToPerm) \ | |
|
437 | .filter(UserRepoGroupToPerm.user_id == member_id) \ | |
|
438 | .filter(UserRepoGroupToPerm.group == repo_group) \ | |
|
439 | .scalar() | |
|
440 | if perm_obj and perm_obj.permission.permission_name != perm: | |
|
441 | changes['default_user_changed'] = True | |
|
442 | ||
|
433 | 443 | # this updates also current one if found |
|
434 | 444 | _set_perm_user(obj, user=member_id, perm=perm) |
|
435 | 445 | elif member_type == 'user_group': |
@@ -698,8 +708,6 b' class RepoGroupModel(BaseModel):' | |||
|
698 | 708 | for repo_group in repo_groups: |
|
699 | 709 | repo_group.update_commit_cache() |
|
700 | 710 | |
|
701 | ||
|
702 | ||
|
703 | 711 | def get_repo_groups_as_dict(self, repo_group_list=None, admin=False, |
|
704 | 712 | super_user_actions=False): |
|
705 | 713 | |
@@ -753,7 +761,7 b' class RepoGroupModel(BaseModel):' | |||
|
753 | 761 | "last_changeset": "", |
|
754 | 762 | "last_changeset_raw": "", |
|
755 | 763 | |
|
756 | "desc": desc(group.group_description, group.personal), | |
|
764 | "desc": desc(h.escape(group.group_description), group.personal), | |
|
757 | 765 | "top_level_repos": 0, |
|
758 | 766 | "owner": user_profile(group.User.username) |
|
759 | 767 | } |
@@ -21,9 +21,11 b'' | |||
|
21 | 21 | import os |
|
22 | 22 | import hashlib |
|
23 | 23 | import logging |
|
24 | import re | |
|
24 | 25 | from collections import namedtuple |
|
25 | 26 | from functools import wraps |
|
26 | 27 | import bleach |
|
28 | from pyramid.threadlocal import get_current_request, get_current_registry | |
|
27 | 29 | |
|
28 | 30 | from rhodecode.lib import rc_cache |
|
29 | 31 | from rhodecode.lib.utils2 import ( |
@@ -210,7 +212,23 b' class SettingsModel(BaseModel):' | |||
|
210 | 212 | invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE |
|
211 | 213 | CacheKey.set_invalidate(invalidation_namespace) |
|
212 | 214 | |
|
213 | def get_all_settings(self, cache=False): | |
|
215 | def get_all_settings(self, cache=False, from_request=True): | |
|
216 | from rhodecode.authentication.base import get_authn_registry | |
|
217 | ||
|
218 | # defines if we use GLOBAL, or PER_REPO | |
|
219 | repo = self._get_repo(self.repo) if self.repo else None | |
|
220 | key = "settings_repo.{}".format(repo.repo_id) if repo else "settings_app" | |
|
221 | ||
|
222 | # initially try the requests context, this is the fastest | |
|
223 | # we only fetch global config | |
|
224 | if from_request: | |
|
225 | request = get_current_request() | |
|
226 | ||
|
227 | if request and not repo and hasattr(request, 'call_context') and hasattr(request.call_context, 'rc_config'): | |
|
228 | rc_config = request.call_context.rc_config | |
|
229 | if rc_config: | |
|
230 | return rc_config | |
|
231 | ||
|
214 | 232 | region = rc_cache.get_or_create_region('sql_cache_short') |
|
215 | 233 | invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE |
|
216 | 234 | |
@@ -226,9 +244,6 b' class SettingsModel(BaseModel):' | |||
|
226 | 244 | } |
|
227 | 245 | return settings |
|
228 | 246 | |
|
229 | repo = self._get_repo(self.repo) if self.repo else None | |
|
230 | key = "settings_repo.{}".format(repo.repo_id) if repo else "settings_app" | |
|
231 | ||
|
232 | 247 | inv_context_manager = rc_cache.InvalidationContext( |
|
233 | 248 | uid='cache_settings', invalidation_namespace=invalidation_namespace) |
|
234 | 249 | with inv_context_manager as invalidation_context: |
@@ -240,6 +255,11 b' class SettingsModel(BaseModel):' | |||
|
240 | 255 | # are anyway very short lived and it's a safest way. |
|
241 | 256 | region = rc_cache.get_or_create_region('sql_cache_short') |
|
242 | 257 | region.invalidate() |
|
258 | registry = get_current_registry() | |
|
259 | if registry: | |
|
260 | authn_registry = get_authn_registry(registry) | |
|
261 | if authn_registry: | |
|
262 | authn_registry.invalidate_plugins_for_auth() | |
|
243 | 263 | |
|
244 | 264 | result = _get_all_settings('rhodecode_settings', key) |
|
245 | 265 | log.debug('Fetching app settings for key: %s took: %.4fs', key, |
@@ -360,9 +380,15 b' class IssueTrackerSettingsModel(object):' | |||
|
360 | 380 | for uid in issuetracker_entries: |
|
361 | 381 | url_data = qs.get(self._get_keyname('url', uid, 'rhodecode_')) |
|
362 | 382 | |
|
383 | pat = qs.get(self._get_keyname('pat', uid, 'rhodecode_')) | |
|
384 | try: | |
|
385 | pat_compiled = re.compile(r'%s' % pat) | |
|
386 | except re.error: | |
|
387 | pat_compiled = None | |
|
388 | ||
|
363 | 389 | issuetracker_entries[uid] = AttributeDict({ |
|
364 |
'pat': |
|
|
365 | self._get_keyname('pat', uid, 'rhodecode_')), | |
|
390 | 'pat': pat, | |
|
391 | 'pat_compiled': pat_compiled, | |
|
366 | 392 | 'url': url_cleaner( |
|
367 | 393 | qs.get(self._get_keyname('url', uid, 'rhodecode_')) or ''), |
|
368 | 394 | 'pref': bleach.clean( |
@@ -38,6 +38,7 b' log = logging.getLogger(__name__)' | |||
|
38 | 38 | |
|
39 | 39 | class SshKeyModel(BaseModel): |
|
40 | 40 | cls = UserSshKeys |
|
41 | DEFAULT_PRIVATE_KEY_FORMAT = 'pkcs8' | |
|
41 | 42 | |
|
42 | 43 | def parse_key(self, key_data): |
|
43 | 44 | """ |
@@ -66,16 +67,23 b' class SshKeyModel(BaseModel):' | |||
|
66 | 67 | log.error("Key Parse error: %s", err) |
|
67 | 68 | raise |
|
68 | 69 | |
|
69 | def generate_keypair(self, comment=None): | |
|
70 | def generate_keypair(self, comment=None, private_format=DEFAULT_PRIVATE_KEY_FORMAT): | |
|
70 | 71 | |
|
71 | 72 | key = rsa.generate_private_key( |
|
72 | 73 | backend=crypto_default_backend(), |
|
73 | 74 | public_exponent=65537, |
|
74 | 75 | key_size=2048 |
|
75 | 76 | ) |
|
77 | if private_format == self.DEFAULT_PRIVATE_KEY_FORMAT: | |
|
78 | private_format = crypto_serialization.PrivateFormat.PKCS8 | |
|
79 | else: | |
|
80 | # legacy format that can be used by older systems, use if pkcs8 have | |
|
81 | # problems | |
|
82 | private_format = crypto_serialization.PrivateFormat.TraditionalOpenSSL | |
|
83 | ||
|
76 | 84 | private_key = key.private_bytes( |
|
77 | 85 | crypto_serialization.Encoding.PEM, |
|
78 |
|
|
|
86 | private_format, | |
|
79 | 87 | crypto_serialization.NoEncryption()) |
|
80 | 88 | public_key = key.public_key().public_bytes( |
|
81 | 89 | crypto_serialization.Encoding.OpenSSH, |
@@ -134,14 +134,11 b' div.markdown-block h2 {' | |||
|
134 | 134 | div.markdown-block h1 { |
|
135 | 135 | font-size: 32px; |
|
136 | 136 | margin: 15px 0 15px 0 !important; |
|
137 | padding-bottom: 5px !important; | |
|
138 | 137 | } |
|
139 | 138 | |
|
140 | 139 | div.markdown-block h2 { |
|
141 | 140 | font-size: 24px !important; |
|
142 | 141 | margin: 34px 0 10px 0 !important; |
|
143 | padding-top: 15px !important; | |
|
144 | padding-bottom: 8px !important; | |
|
145 | 142 | } |
|
146 | 143 | |
|
147 | 144 | div.markdown-block h3 { |
@@ -174,6 +171,21 b' div.markdown-block hr {' | |||
|
174 | 171 | margin-bottom: 13px; |
|
175 | 172 | } |
|
176 | 173 | |
|
174 | div.markdown-block blockquote { | |
|
175 | color: #424242 !important; | |
|
176 | padding: 8px 21px; | |
|
177 | margin: 12px 0; | |
|
178 | border-left: 4px solid @grey6; | |
|
179 | } | |
|
180 | ||
|
181 | div.markdown-block blockquote p { | |
|
182 | color: #424242 !important; | |
|
183 | padding: 0 !important; | |
|
184 | margin: 0 !important; | |
|
185 | line-height: 1.5; | |
|
186 | } | |
|
187 | ||
|
188 | ||
|
177 | 189 | div.markdown-block ol, |
|
178 | 190 | div.markdown-block ul, |
|
179 | 191 | div.markdown-block p, |
@@ -181,13 +193,11 b' div.markdown-block blockquote,' | |||
|
181 | 193 | div.markdown-block dl, |
|
182 | 194 | div.markdown-block li, |
|
183 | 195 | div.markdown-block table { |
|
184 | margin: 3px 0px 13px 0px !important; | |
|
185 | 196 | color: #424242 !important; |
|
186 | 197 | font-size: 13px !important; |
|
187 | 198 | font-family: @text-regular; |
|
188 | 199 | font-weight: normal !important; |
|
189 | 200 | overflow: visible !important; |
|
190 | line-height: 140% !important; | |
|
191 | 201 | } |
|
192 | 202 | |
|
193 | 203 | div.markdown-block pre { |
@@ -245,14 +255,6 b' div.markdown-block ol li {' | |||
|
245 | 255 | list-style: decimal !important; |
|
246 | 256 | } |
|
247 | 257 | |
|
248 | /* | |
|
249 | div.markdown-block a, | |
|
250 | div.markdown-block a:visited { | |
|
251 | color: #4183C4 !important; | |
|
252 | background-color: inherit; | |
|
253 | text-decoration: none; | |
|
254 | } | |
|
255 | */ | |
|
256 | 258 | |
|
257 | 259 | div.markdown-block #message { |
|
258 | 260 | .border-radius(@border-radius); |
@@ -87,6 +87,10 b' body {' | |||
|
87 | 87 | border-left: @border-thickness solid @border-default-color; |
|
88 | 88 | } |
|
89 | 89 | |
|
90 | .cursor-pointer { | |
|
91 | cursor: pointer; | |
|
92 | } | |
|
93 | ||
|
90 | 94 | input + .action-link, .action-link.first{ |
|
91 | 95 | border-left: none; |
|
92 | 96 | } |
@@ -3,9 +3,13 b'' | |||
|
3 | 3 | .readme-title { |
|
4 | 4 | border: 1px solid @grey6; |
|
5 | 5 | padding: 10px 5px; |
|
6 | font-weight: 600; | |
|
7 | 6 | margin-top: 30px; |
|
8 | 7 | margin-bottom: -1px; |
|
8 | ||
|
9 | a { | |
|
10 | font-weight: 600; | |
|
11 | font-size: 13px | |
|
12 | } | |
|
9 | 13 | } |
|
10 | 14 | |
|
11 | 15 | div.readme_box { |
@@ -34,14 +38,11 b' div.readme_box h2 {' | |||
|
34 | 38 | div.readme_box h1 { |
|
35 | 39 | font-size: 32px; |
|
36 | 40 | margin: 15px 0 15px 0 !important; |
|
37 | padding-bottom: 5px !important; | |
|
38 | 41 | } |
|
39 | 42 | |
|
40 | 43 | div.readme_box h2 { |
|
41 | 44 | font-size: 24px !important; |
|
42 | 45 | margin: 34px 0 10px 0 !important; |
|
43 | padding-top: 15px !important; | |
|
44 | padding-bottom: 8px !important; | |
|
45 | 46 | } |
|
46 | 47 | |
|
47 | 48 | div.readme_box h3 { |
@@ -74,6 +75,20 b' div.readme_box hr {' | |||
|
74 | 75 | margin-bottom: 13px; |
|
75 | 76 | } |
|
76 | 77 | |
|
78 | div.readme_box blockquote { | |
|
79 | color: #424242 !important; | |
|
80 | padding: 8px 21px; | |
|
81 | margin: 12px 0; | |
|
82 | border-left: 4px solid @grey6; | |
|
83 | } | |
|
84 | ||
|
85 | div.readme_box blockquote p { | |
|
86 | color: #424242 !important; | |
|
87 | padding: 0 !important; | |
|
88 | margin: 0 !important; | |
|
89 | line-height: 1.5; | |
|
90 | } | |
|
91 | ||
|
77 | 92 | div.readme_box ol, |
|
78 | 93 | div.readme_box ul, |
|
79 | 94 | div.readme_box p, |
@@ -81,13 +96,11 b' div.readme_box blockquote,' | |||
|
81 | 96 | div.readme_box dl, |
|
82 | 97 | div.readme_box li, |
|
83 | 98 | div.readme_box table { |
|
84 | margin: 3px 0px 13px 0px !important; | |
|
85 | 99 | color: #424242 !important; |
|
86 | 100 | font-size: 13px !important; |
|
87 | 101 | font-family: @text-regular; |
|
88 | 102 | font-weight: normal !important; |
|
89 | 103 | overflow: visible !important; |
|
90 | line-height: 140% !important; | |
|
91 | 104 | } |
|
92 | 105 | |
|
93 | 106 | div.readme_box pre { |
@@ -373,6 +373,17 b' table#repo_list_table {' | |||
|
373 | 373 | min-width: 600px; |
|
374 | 374 | } |
|
375 | 375 | |
|
376 | #no_grid_data { | |
|
377 | text-align: center; | |
|
378 | } | |
|
379 | ||
|
380 | #grid_data_loading { | |
|
381 | text-align: center; | |
|
382 | font-weight: 600; | |
|
383 | font-size: 16px; | |
|
384 | padding: 80px 20px; | |
|
385 | } | |
|
386 | ||
|
376 | 387 | // Keyboard mappings |
|
377 | 388 | table.keyboard-mappings { |
|
378 | 389 | th { |
@@ -538,5 +549,12 b' table.compare_view_commits {' | |||
|
538 | 549 | img{ |
|
539 | 550 | vertical-align: middle; |
|
540 | 551 | } |
|
552 | ||
|
553 | &.td-expire { | |
|
554 | width: 200px; | |
|
555 | } | |
|
556 | &.td-gist-type { | |
|
557 | width: 100px; | |
|
558 | } | |
|
541 | 559 | } |
|
542 | 560 | } |
@@ -593,7 +593,7 b' address {' | |||
|
593 | 593 | } |
|
594 | 594 | |
|
595 | 595 | .help-block-inline { |
|
596 | margin: 0; | |
|
596 | margin: 0 !important; | |
|
597 | 597 | } |
|
598 | 598 | |
|
599 | 599 | // help block text |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Follow', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': 'Lifetime', |
|
33 | 42 | 'Loading ...': 'Loading ...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'No matching files', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'No results', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Follow', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': 'Lebensdauer', |
|
33 | 42 | 'Loading ...': 'Loading ...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'No matching files', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'No results', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Follow', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': 'Lifetime', |
|
33 | 42 | 'Loading ...': 'Loading ...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'No matching files', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'No results', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Follow', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': 'De por vida', |
|
33 | 42 | 'Loading ...': 'Loading ...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'No matching files', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'No results', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Follow', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': 'Durée de vie', |
|
33 | 42 | 'Loading ...': 'Loading ...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'No matching files', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'No results', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} mois', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Segui', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': 'a vita', |
|
33 | 42 | 'Loading ...': 'Caricamento ...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'Nessuna corrispondenza tra i file', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'Nessun risultato', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': '選択したステータス ({0}) を元にコメントが自動的に設定されます...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'フォロー', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': '有効期間', |
|
33 | 42 | 'Loading ...': '読み込み中...', |
|
34 | 43 | 'Loading failed': '読み込み失敗', |
|
35 | 44 | 'Loading more results...': '結果を読み込み中...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'まだブックマークがありません。', |
|
37 | 47 | 'No branches available yet.': 'まだブランチがありません。', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'マッチするファイルはありません', |
|
42 | 52 | 'No pull requests available yet.': 'まだプルリクエストがありません。', |
|
43 | 53 | 'No repositories available yet.': 'まだリポジトリがありません。', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'まだリポジトリグループがありません。', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': '結果がありません', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'まだタグがありません。', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} 分', |
|
126 | 138 | '{0} month': '{0} ヶ月', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} 件の結果があります。矢印キーの上下で選択できます。', |
|
133 | 147 | '{0} sec': '{0} 秒', |
@@ -5,28 +5,38 b'' | |||
|
5 | 5 | _gettext('All Authors'); |
|
6 | 6 | _gettext('All individual reviewers must vote.'); |
|
7 | 7 | _gettext('All reviewers must vote.'); |
|
8 | _gettext('Are you sure to close this pull request without merging?'); | |
|
8 | 9 | _gettext('At least {0} reviewer must vote.'); |
|
9 | 10 | _gettext('At least {0} reviewers must vote.'); |
|
10 | 11 | _gettext('Author is not allowed to be a reviewer.'); |
|
11 | 12 | _gettext('Changed files'); |
|
12 | 13 | _gettext('Close'); |
|
14 | _gettext('Collapse all files'); | |
|
15 | _gettext('Collapse {0} commit'); | |
|
16 | _gettext('Collapse {0} commits'); | |
|
13 | 17 | _gettext('Comment text will be set automatically based on currently selected status ({0}) ...'); |
|
14 | 18 | _gettext('Commit Authors are not allowed to be a reviewer.'); |
|
15 | 19 | _gettext('Context file: '); |
|
16 | 20 | _gettext('Delete this comment?'); |
|
17 | 21 | _gettext('Diff to Commit '); |
|
22 | _gettext('Expand all files'); | |
|
23 | _gettext('Expand {0} commit'); | |
|
24 | _gettext('Expand {0} commits'); | |
|
18 | 25 | _gettext('Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.'); |
|
19 | 26 | _gettext('Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.'); |
|
20 | 27 | _gettext('Follow'); |
|
28 | _gettext('Force updating...'); | |
|
21 | 29 | _gettext('Hide full context diff'); |
|
22 | 30 | _gettext('Hide whitespace changes'); |
|
23 | 31 | _gettext('Invite reviewers to this discussion'); |
|
24 | 32 | _gettext('Leave a comment on line {0}.'); |
|
25 | 33 | _gettext('Leave a comment, or click resolve button to resolve TODO comment #{0}'); |
|
34 | _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}'); | |
|
26 | 35 | _gettext('Lifetime'); |
|
27 | 36 | _gettext('Loading ...'); |
|
28 | 37 | _gettext('Loading failed'); |
|
29 | 38 | _gettext('Loading more results...'); |
|
39 | _gettext('Loading...'); | |
|
30 | 40 | _gettext('No bookmarks available yet.'); |
|
31 | 41 | _gettext('No branches available yet.'); |
|
32 | 42 | _gettext('No forks available yet.'); |
@@ -35,7 +45,9 b'' | |||
|
35 | 45 | _gettext('No matching files'); |
|
36 | 46 | _gettext('No pull requests available yet.'); |
|
37 | 47 | _gettext('No repositories available yet.'); |
|
48 | _gettext('No repositories present.'); | |
|
38 | 49 | _gettext('No repository groups available yet.'); |
|
50 | _gettext('No repository groups present.'); | |
|
39 | 51 | _gettext('No results'); |
|
40 | 52 | _gettext('No ssh keys available yet.'); |
|
41 | 53 | _gettext('No tags available yet.'); |
@@ -119,9 +131,11 b'' | |||
|
119 | 131 | _gettext('{0} min'); |
|
120 | 132 | _gettext('{0} month'); |
|
121 | 133 | _gettext('{0} months'); |
|
134 | _gettext('{0} of {1} repositories'); | |
|
122 | 135 | _gettext('{0} of {1} repository groups'); |
|
123 | 136 | _gettext('{0} out of {1} ssh keys'); |
|
124 | 137 | _gettext('{0} out of {1} users'); |
|
138 | _gettext('{0} repositories'); | |
|
125 | 139 | _gettext('{0} repository groups'); |
|
126 | 140 | _gettext('{0} results are available, use up and down arrow keys to navigate.'); |
|
127 | 141 | _gettext('{0} sec'); |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Zamknij', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Obserwuj', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': 'Czas życia', |
|
33 | 42 | 'Loading ...': 'Ładuję...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'Nie ma plików pasujących', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'No results', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Seguir', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': 'Tempo de Vida', |
|
33 | 42 | 'Loading ...': 'Carregando...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'Nenhum arquivo encontrado', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'No results', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Наблюдать', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': 'Срок', |
|
33 | 42 | 'Loading ...': 'Загрузка...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'Нет совпадений', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'No results', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -11,28 +11,38 b' var _TM = {' | |||
|
11 | 11 | 'All Authors': 'All Authors', |
|
12 | 12 | 'All individual reviewers must vote.': 'All individual reviewers must vote.', |
|
13 | 13 | 'All reviewers must vote.': 'All reviewers must vote.', |
|
14 | 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?', | |
|
14 | 15 | 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.', |
|
15 | 16 | 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.', |
|
16 | 17 | 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.', |
|
17 | 18 | 'Changed files': 'Changed files', |
|
18 | 19 | 'Close': 'Close', |
|
20 | 'Collapse all files': 'Collapse all files', | |
|
21 | 'Collapse {0} commit': 'Collapse {0} commit', | |
|
22 | 'Collapse {0} commits': 'Collapse {0} commits', | |
|
19 | 23 | 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...', |
|
20 | 24 | 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.', |
|
21 | 25 | 'Context file: ': 'Context file: ', |
|
22 | 26 | 'Delete this comment?': 'Delete this comment?', |
|
23 | 27 | 'Diff to Commit ': 'Diff to Commit ', |
|
28 | 'Expand all files': 'Expand all files', | |
|
29 | 'Expand {0} commit': 'Expand {0} commit', | |
|
30 | 'Expand {0} commits': 'Expand {0} commits', | |
|
24 | 31 | 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.': 'Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.', |
|
25 | 32 | 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.', |
|
26 | 33 | 'Follow': 'Follow', |
|
34 | 'Force updating...': 'Force updating...', | |
|
27 | 35 | 'Hide full context diff': 'Hide full context diff', |
|
28 | 36 | 'Hide whitespace changes': 'Hide whitespace changes', |
|
29 | 37 | 'Invite reviewers to this discussion': 'Invite reviewers to this discussion', |
|
30 | 38 | 'Leave a comment on line {0}.': 'Leave a comment on line {0}.', |
|
31 | 39 | 'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}', |
|
40 | 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}': 'Leave a resolution comment, or click resolve button to resolve TODO comment #{0}', | |
|
32 | 41 | 'Lifetime': '终身', |
|
33 | 42 | 'Loading ...': 'Loading ...', |
|
34 | 43 | 'Loading failed': 'Loading failed', |
|
35 | 44 | 'Loading more results...': 'Loading more results...', |
|
45 | 'Loading...': 'Loading...', | |
|
36 | 46 | 'No bookmarks available yet.': 'No bookmarks available yet.', |
|
37 | 47 | 'No branches available yet.': 'No branches available yet.', |
|
38 | 48 | 'No forks available yet.': 'No forks available yet.', |
@@ -41,7 +51,9 b' var _TM = {' | |||
|
41 | 51 | 'No matching files': 'No matching files', |
|
42 | 52 | 'No pull requests available yet.': 'No pull requests available yet.', |
|
43 | 53 | 'No repositories available yet.': 'No repositories available yet.', |
|
54 | 'No repositories present.': 'No repositories present.', | |
|
44 | 55 | 'No repository groups available yet.': 'No repository groups available yet.', |
|
56 | 'No repository groups present.': 'No repository groups present.', | |
|
45 | 57 | 'No results': 'No results', |
|
46 | 58 | 'No ssh keys available yet.': 'No ssh keys available yet.', |
|
47 | 59 | 'No tags available yet.': 'No tags available yet.', |
@@ -125,9 +137,11 b' var _TM = {' | |||
|
125 | 137 | '{0} min': '{0} min', |
|
126 | 138 | '{0} month': '{0} month', |
|
127 | 139 | '{0} months': '{0} months', |
|
140 | '{0} of {1} repositories': '{0} of {1} repositories', | |
|
128 | 141 | '{0} of {1} repository groups': '{0} of {1} repository groups', |
|
129 | 142 | '{0} out of {1} ssh keys': '{0} out of {1} ssh keys', |
|
130 | 143 | '{0} out of {1} users': '{0} out of {1} users', |
|
144 | '{0} repositories': '{0} repositories', | |
|
131 | 145 | '{0} repository groups': '{0} repository groups', |
|
132 | 146 | '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.', |
|
133 | 147 | '{0} sec': '{0} sec', |
@@ -31,6 +31,7 b' function registerRCRoutes() {' | |||
|
31 | 31 | pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']); |
|
32 | 32 | pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']); |
|
33 | 33 | pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']); |
|
34 | pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']); | |
|
34 | 35 | pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']); |
|
35 | 36 | pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']); |
|
36 | 37 | pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']); |
@@ -299,6 +299,10 b' var tooltipActivate = function () {' | |||
|
299 | 299 | var altHovercard =$origin.data('hovercardAlt'); |
|
300 | 300 | |
|
301 | 301 | if (hovercardUrl !== undefined && hovercardUrl !== "") { |
|
302 | if (hovercardUrl.substr(0,12) === 'pyroutes.url'){ | |
|
303 | hovercardUrl = eval(hovercardUrl) | |
|
304 | } | |
|
305 | ||
|
302 | 306 | var loaded = loadHoverCard(hovercardUrl, altHovercard, function (data) { |
|
303 | 307 | instance.content(data); |
|
304 | 308 | }) |
@@ -102,7 +102,7 b'' | |||
|
102 | 102 | { data: {"_": "author", |
|
103 | 103 | "sort": "author_raw"}, title: "${_("Author")}", width: "250px", className: "td-user" }, |
|
104 | 104 | { data: {"_": "type", |
|
105 |
"sort": "type"}, title: "${_("Type")}", width: " |
|
|
105 | "sort": "type"}, title: "${_("Type")}", width: "100px", className: "td-gist-type" }, | |
|
106 | 106 | { data: {"_": "access_id", |
|
107 | 107 | "sort": "access_id"}, title: "${_("Name")}", width:"150px", className: "td-componentname" }, |
|
108 | 108 | { data: {"_": "description", |
@@ -110,7 +110,7 b'' | |||
|
110 | 110 | { data: {"_": "created_on", |
|
111 | 111 | "sort": "created_on_raw"}, title: "${_("Created on")}", className: "td-time" }, |
|
112 | 112 | { data: {"_": "expires", |
|
113 | "sort": "expires"}, title: "${_("Expires")}", className: "td-exp" } | |
|
113 | "sort": "expires"}, title: "${_("Expires")}", width: "200px", className: "td-expire" } | |
|
114 | 114 | ], |
|
115 | 115 | language: { |
|
116 | 116 | paginate: DEFAULT_GRID_PAGINATION, |
@@ -71,7 +71,7 b'' | |||
|
71 | 71 | <div class="input"> |
|
72 | 72 | ${h.text('description', class_='medium', placeholder=_('Description'))} |
|
73 | 73 | ${h.hidden('lifetime')} |
|
74 | ${h.select('role', '', c.role_options)} | |
|
74 | ${h.select('role', request.GET.get('token_role', ''), c.role_options)} | |
|
75 | 75 | |
|
76 | 76 | % if c.allow_scoped_tokens: |
|
77 | 77 | ${h.hidden('scope_repo_id')} |
@@ -4,7 +4,9 b'' | |||
|
4 | 4 | |
|
5 | 5 | % if c.extern_type != 'rhodecode': |
|
6 | 6 | <p>${_('Your user account details are managed by an external source. Details cannot be managed here.')} |
|
7 | <br/>${_('Source type')}: <strong>${c.extern_type}</strong> | |
|
7 | <br/>${_('For VCS access please generate')} | |
|
8 | <a href="${h.route_path('my_account_auth_tokens', _query={'token_role':'token_role_vcs'})}">Authentication Token</a> or <a href="${h.route_path('my_account_ssh_keys_generate')}">SSH Key</a>. | |
|
9 | <br/>${_('Source type')}: <strong>${c.extern_type}</strong> | |
|
8 | 10 | </p> |
|
9 | 11 | % else: |
|
10 | 12 | ${c.form.render() | n} |
@@ -8,6 +8,17 b'' | |||
|
8 | 8 | </div> |
|
9 | 9 | |
|
10 | 10 | <div class="panel-body fields"> |
|
11 | %if c.extern_type != 'rhodecode': | |
|
12 | <% readonly = "readonly" %> | |
|
13 | <% disabled = " disabled" %> | |
|
14 | <div class="alert-warning" style="margin:0px 0px 20px 0px; padding: 10px"> | |
|
15 | <strong>${_('This user was created from external source (%s). Editing some of the settings is limited.' % c.extern_type)}</strong> | |
|
16 | </div> | |
|
17 | <div style="margin:-10px 0px 20px 0px;"> | |
|
18 | ${_('For VCS access please generate')} | |
|
19 | <a href="${h.route_path('my_account_auth_tokens', _query={'token_role':'token_role_vcs'})}">Authentication Token</a> or <a href="${h.route_path('my_account_ssh_keys_generate')}">SSH Key</a>. | |
|
20 | </div> | |
|
21 | %endif | |
|
11 | 22 | <div class="field"> |
|
12 | 23 | <div class="label"> |
|
13 | 24 | ${_('Photo')}: |
@@ -11,13 +11,19 b'' | |||
|
11 | 11 | |
|
12 | 12 | %if c.extern_type != 'rhodecode': |
|
13 | 13 | <% readonly = "readonly" %> |
|
14 | <% disabled = "disabled" %> | |
|
14 | <% disabled = " disabled" %> | |
|
15 | <div class="alert-warning" style="margin:0px 0px 20px 0px; padding: 10px"> | |
|
16 | <strong>${_('This user was created from external source (%s). Editing some of the settings is limited.' % c.extern_type)}</strong> | |
|
17 | </div> | |
|
18 | <div style="margin:-10px 0px 20px 0px;"> | |
|
19 | ${_('For VCS access please generate')} | |
|
20 | <a href="${h.route_path('my_account_auth_tokens', _query={'token_role':'token_role_vcs'})}">Authentication Token</a> or <a href="${h.route_path('my_account_ssh_keys_generate')}">SSH Key</a>. | |
|
21 | </div> | |
|
22 | %endif | |
|
23 | ||
|
24 | %if c.extern_type != 'rhodecode': | |
|
15 | 25 | <div class="infoform"> |
|
16 | 26 | <div class="fields"> |
|
17 | <p>${_('Your user account details are managed by an external source. Details cannot be managed here.')} | |
|
18 | <br/>${_('Source type')}: <strong>${c.extern_type}</strong> | |
|
19 | </p> | |
|
20 | ||
|
21 | 27 | <div class="field"> |
|
22 | 28 | <div class="label"> |
|
23 | 29 | <label for="username">${_('Username')}:</label> |
@@ -55,7 +55,13 b'' | |||
|
55 | 55 | <div class="textarea editor"> |
|
56 | 56 | ${h.textarea('group_description',cols=23,rows=5,class_="medium")} |
|
57 | 57 | <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %> |
|
58 | <span class="help-block">${_('Plain text format with support of {metatags}').format(metatags=metatags_url)|n}</span> | |
|
58 | <span class="help-block"> | |
|
59 | % if c.visual.stylify_metatags: | |
|
60 | ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n} | |
|
61 | % else: | |
|
62 | ${_('Plain text format.')} | |
|
63 | % endif | |
|
64 | </span> | |
|
59 | 65 | <span id="meta-tags-desc" style="display: none"> |
|
60 | 66 | <%namespace name="dt" file="/data_table/_dt_elements.mako"/> |
|
61 | 67 | ${dt.metatags_help()} |
@@ -28,7 +28,7 b'' | |||
|
28 | 28 | <div class="sidebar"> |
|
29 | 29 | <ul class="nav nav-pills nav-stacked"> |
|
30 | 30 | <li class="${h.is_active('settings', c.active)}"><a href="${h.route_path('edit_repo_group', repo_group_name=c.repo_group.group_name)}">${_('Settings')}</a></li> |
|
31 | <li class="${h.is_active('permissions', c.active)}"><a href="${h.route_path('edit_repo_group_perms', repo_group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li> | |
|
31 | <li class="${h.is_active('permissions', c.active)}"><a href="${h.route_path('edit_repo_group_perms', repo_group_name=c.repo_group.group_name)}">${_('Access Permissions')}</a></li> | |
|
32 | 32 | <li class="${h.is_active('advanced', c.active)}"><a href="${h.route_path('edit_repo_group_advanced', repo_group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li> |
|
33 | 33 | <li class="${h.is_active('integrations', c.active)}"><a href="${h.route_path('repo_group_integrations_home', repo_group_name=c.repo_group.group_name)}">${_('Integrations')}</a></li> |
|
34 | 34 | </ul> |
@@ -61,7 +61,12 b'' | |||
|
61 | 61 | ${base.gravatar(_user.email, 16, user=_user, tooltip=True)} |
|
62 | 62 | <span class="user"> |
|
63 | 63 | % if _user.username == h.DEFAULT_USER: |
|
64 | ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> | |
|
64 | ${h.DEFAULT_USER} | |
|
65 | % if _user.active: | |
|
66 | <span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span> | |
|
67 | % else: | |
|
68 | <span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span> | |
|
69 | % endif | |
|
65 | 70 | % else: |
|
66 | 71 | ${h.link_to_user(_user.username)} |
|
67 | 72 | %if getattr(_user, 'duplicate_perm', None): |
@@ -104,7 +109,12 b'' | |||
|
104 | 109 | ${base.gravatar(_user.email, 16, user=_user, tooltip=True)} |
|
105 | 110 | <span class="user"> |
|
106 | 111 | % if _user.username == h.DEFAULT_USER: |
|
107 | ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> | |
|
112 | ${h.DEFAULT_USER} | |
|
113 | % if _user.active: | |
|
114 | <span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span> | |
|
115 | % else: | |
|
116 | <span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span> | |
|
117 | % endif | |
|
108 | 118 | % else: |
|
109 | 119 | ${h.link_to_user(_user.username)} |
|
110 | 120 | %if getattr(_user, 'duplicate_perm', None): |
@@ -59,7 +59,13 b'' | |||
|
59 | 59 | ${c.form.render_error(request, c.form['repo_group_description'])|n} |
|
60 | 60 | |
|
61 | 61 | <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %> |
|
62 | <span class="help-block">${_('Plain text format with support of {metatags}').format(metatags=metatags_url)|n}</span> | |
|
62 | <span class="help-block"> | |
|
63 | % if c.visual.stylify_metatags: | |
|
64 | ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n} | |
|
65 | % else: | |
|
66 | ${_('Plain text format.')} | |
|
67 | % endif | |
|
68 | </span> | |
|
63 | 69 | <span id="meta-tags-desc" style="display: none"> |
|
64 | 70 | <%namespace name="dt" file="/data_table/_dt_elements.mako"/> |
|
65 | 71 | ${dt.metatags_help()} |
@@ -68,7 +68,14 b'' | |||
|
68 | 68 | <div class="textarea editor"> |
|
69 | 69 | ${h.textarea('repo_description',cols=23,rows=5,class_="medium")} |
|
70 | 70 | <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %> |
|
71 | <span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span> | |
|
71 | <span class="help-block"> | |
|
72 | % if c.visual.stylify_metatags: | |
|
73 | ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n} | |
|
74 | % else: | |
|
75 | ${_('Plain text format.')} | |
|
76 | % endif | |
|
77 | ${_('Add a README file for longer descriptions')} | |
|
78 | </span> | |
|
72 | 79 | <span id="meta-tags-desc" style="display: none"> |
|
73 | 80 | <%namespace name="dt" file="/data_table/_dt_elements.mako"/> |
|
74 | 81 | ${dt.metatags_help()} |
@@ -23,43 +23,48 b'' | |||
|
23 | 23 | <div class="panel-heading"> |
|
24 | 24 | <h3 class="panel-title">${_('Inherited Issue Tracker Patterns')}</h3> |
|
25 | 25 | </div> |
|
26 | ||
|
26 | 27 | <div class="panel-body"> |
|
27 |
|
|
|
28 | <tr> | |
|
29 | <th>${_('Description')}</th> | |
|
30 | <th>${_('Pattern')}</th> | |
|
31 | <th>${_('Url')}</th> | |
|
32 | <th>${_('Prefix')}</th> | |
|
33 |
<th |
|
|
34 | </tr> | |
|
35 | %for uid, entry in c.global_patterns.items(): | |
|
36 | <tr id="${uid}"> | |
|
37 | <td class="td-description issuetracker_desc"> | |
|
38 | <span class="entry"> | |
|
39 | ${entry.desc} | |
|
40 | </span> | |
|
41 | </td> | |
|
42 | <td class="td-regex issuetracker_pat"> | |
|
43 | <span class="entry"> | |
|
44 | ${entry.pat} | |
|
45 | </span> | |
|
46 | </td> | |
|
47 | <td class="td-url issuetracker_url"> | |
|
48 | <span class="entry"> | |
|
49 | ${entry.url} | |
|
50 | </span> | |
|
51 | </td> | |
|
52 | <td class="td-prefix issuetracker_pref"> | |
|
53 | <span class="entry"> | |
|
54 | ${entry.pref} | |
|
55 | </span> | |
|
56 | </td> | |
|
57 | <td class="td-action"> | |
|
58 | </td> | |
|
59 | </tr> | |
|
60 | %endfor | |
|
28 | <table class="rctable issuetracker readonly"> | |
|
29 | <tr> | |
|
30 | <th>${_('Description')}</th> | |
|
31 | <th>${_('Pattern')}</th> | |
|
32 | <th>${_('Url')}</th> | |
|
33 | <th>${_('Prefix')}</th> | |
|
34 | <th></th> | |
|
35 | </tr> | |
|
61 | 36 | |
|
62 | </table> | |
|
37 | % for uid, entry in c.global_patterns.items(): | |
|
38 | <tr id="${uid}"> | |
|
39 | <td class="td-description issuetracker_desc"> | |
|
40 | <span class="entry"> | |
|
41 | ${entry.desc} | |
|
42 | </span> | |
|
43 | </td> | |
|
44 | <td class="td-regex issuetracker_pat"> | |
|
45 | <span class="entry"> | |
|
46 | ${entry.pat} | |
|
47 | </span> | |
|
48 | </td> | |
|
49 | <td class="td-url issuetracker_url"> | |
|
50 | <span class="entry"> | |
|
51 | ${entry.url} | |
|
52 | </span> | |
|
53 | </td> | |
|
54 | <td class="td-prefix issuetracker_pref"> | |
|
55 | <span class="entry"> | |
|
56 | ${entry.pref} | |
|
57 | </span> | |
|
58 | </td> | |
|
59 | <td class="td-action"> | |
|
60 | </td> | |
|
61 | </tr> | |
|
62 | % endfor | |
|
63 | ||
|
64 | </table> | |
|
65 | <div class="buttons"> | |
|
66 | <button type="submit" class="btn btn-primary save-inheritance" id="save">${_('Save')}</button> | |
|
67 | </div> | |
|
63 | 68 | </div> |
|
64 | 69 | </div> |
|
65 | 70 | </div> |
@@ -77,7 +82,6 b'' | |||
|
77 | 82 | )} |
|
78 | 83 | <div class="buttons"> |
|
79 | 84 | <button type="submit" class="btn btn-primary save-inheritance" id="save">${_('Save')}</button> |
|
80 | <button type="reset" class="btn reset-inheritance">${_('Reset')}</button> | |
|
81 | 85 | </div> |
|
82 | 86 | </div> |
|
83 | 87 | </div> |
@@ -58,7 +58,11 b'' | |||
|
58 | 58 | <td class="private_repo_msg"> |
|
59 | 59 | ${base.gravatar(h.DEFAULT_USER_EMAIL, 16)} |
|
60 | 60 | ${h.DEFAULT_USER} - ${_('only users/user groups explicitly added here will have access')}</td> |
|
61 |
<td |
|
|
61 | <td class="td-action"> | |
|
62 | <span class="tooltip btn btn-link btn-default" onclick="setPrivateRepo(false); return false" title="${_('Private repositories are only visible to people explicitly added as collaborators. Default permissions wont apply')}"> | |
|
63 | ${_('un-set private mode')} | |
|
64 | </span> | |
|
65 | </td> | |
|
62 | 66 | <td class="quick_repo_menu"> |
|
63 | 67 | % if c.rhodecode_user.is_admin: |
|
64 | 68 | <i class="icon-more"></i> |
@@ -83,7 +87,12 b'' | |||
|
83 | 87 | ${base.gravatar(_user.email, 16, user=_user, tooltip=True)} |
|
84 | 88 | <span class="user"> |
|
85 | 89 | % if _user.username == h.DEFAULT_USER: |
|
86 | ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> | |
|
90 | ${h.DEFAULT_USER} | |
|
91 | % if _user.active: | |
|
92 | <span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span> | |
|
93 | % else: | |
|
94 | <span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span> | |
|
95 | % endif | |
|
87 | 96 | % else: |
|
88 | 97 | ${h.link_to_user(_user.username)} |
|
89 | 98 | %if getattr(_user, 'duplicate_perm', None): |
@@ -106,7 +115,7 b'' | |||
|
106 | 115 | ${_('Remove')} |
|
107 | 116 | </span> |
|
108 | 117 | %elif _user.username == h.DEFAULT_USER: |
|
109 |
<span class="tooltip btn btn-link btn-default" onclick=" |
|
|
118 | <span class="tooltip btn btn-link btn-default" onclick="setPrivateRepo(true); return false" title="${_('Private repositories are only visible to people explicitly added as collaborators. Default permissions wont apply')}"> | |
|
110 | 119 | ${_('set private mode')} |
|
111 | 120 | </span> |
|
112 | 121 | %endif |
@@ -204,9 +213,10 b'' | |||
|
204 | 213 | }); |
|
205 | 214 | quick_repo_menu(); |
|
206 | 215 | |
|
207 |
var |
|
|
216 | var setPrivateRepo = function (private) { | |
|
208 | 217 | var postData = { |
|
209 | 'csrf_token': CSRF_TOKEN | |
|
218 | 'csrf_token': CSRF_TOKEN, | |
|
219 | 'private': private | |
|
210 | 220 | }; |
|
211 | 221 | |
|
212 | 222 | var success = function(o) { |
@@ -174,7 +174,14 b'' | |||
|
174 | 174 | ${c.form.render_error(request, c.form['repo_description'])|n} |
|
175 | 175 | |
|
176 | 176 | <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %> |
|
177 | <span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span> | |
|
177 | <span class="help-block"> | |
|
178 | % if c.visual.stylify_metatags: | |
|
179 | ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n} | |
|
180 | % else: | |
|
181 | ${_('Plain text format.')} | |
|
182 | % endif | |
|
183 | ${_('Add a README file for longer descriptions')} | |
|
184 | </span> | |
|
178 | 185 | <span id="meta-tags-desc" style="display: none"> |
|
179 | 186 | <%namespace name="dt" file="/data_table/_dt_elements.mako"/> |
|
180 | 187 | ${dt.metatags_help()} |
@@ -1,5 +1,5 b'' | |||
|
1 | 1 | |
|
2 |
<div id="update_notice" style="display: none; margin: |
|
|
2 | <div id="update_notice" style="display: none; margin: 0px 0px 30px 0px"> | |
|
3 | 3 | <div>${_('Checking for updates...')}</div> |
|
4 | 4 | </div> |
|
5 | 5 |
@@ -18,7 +18,11 b'' | |||
|
18 | 18 | |
|
19 | 19 | <div class="panel panel-default"> |
|
20 | 20 | <div class="panel-heading"> |
|
21 | <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3> | |
|
21 | <h3 class="panel-title"> | |
|
22 | <i class="icon-user-group" title="${_('User group')}"></i> | |
|
23 | ${h.link_to_group(c.user_group.users_group_name)} | |
|
24 | - ${_('Advanced')} | |
|
25 | </h3> | |
|
22 | 26 | </div> |
|
23 | 27 | <div class="panel-body"> |
|
24 | 28 | ${base.dt_info_panel(elems)} |
@@ -2,7 +2,11 b'' | |||
|
2 | 2 | |
|
3 | 3 | <div class="panel panel-default"> |
|
4 | 4 | <div class="panel-heading"> |
|
5 |
<h3 class="panel-title"> |
|
|
5 | <h3 class="panel-title"> | |
|
6 | <i class="icon-user-group" title="${_('User group')}"></i> | |
|
7 | ${h.link_to_group(c.user_group.users_group_name)} | |
|
8 | - ${_('Access Permissions')} | |
|
9 | </h3> | |
|
6 | 10 | </div> |
|
7 | 11 | <div class="panel-body"> |
|
8 | 12 | ${h.secure_form(h.route_path('edit_user_group_perms_update', user_group_id=c.user_group.users_group_id), request=request)} |
@@ -63,7 +67,12 b'' | |||
|
63 | 67 | ${base.gravatar(_user.email, 16, user=_user, tooltip=True)} |
|
64 | 68 | <span class="user"> |
|
65 | 69 | % if _user.username == h.DEFAULT_USER: |
|
66 | ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> | |
|
70 | ${h.DEFAULT_USER} | |
|
71 | % if _user.active: | |
|
72 | <span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span> | |
|
73 | % else: | |
|
74 | <span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span> | |
|
75 | % endif | |
|
67 | 76 | % else: |
|
68 | 77 | ${h.link_to_user(_user.username)} |
|
69 | 78 | %if getattr(_user, 'duplicate_perm', None): |
@@ -106,7 +115,12 b'' | |||
|
106 | 115 | ${base.gravatar(_user.email, 16, user=_user, tooltip=True)} |
|
107 | 116 | <span class="user"> |
|
108 | 117 | % if _user.username == h.DEFAULT_USER: |
|
109 | ${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span> | |
|
118 | ${h.DEFAULT_USER} | |
|
119 | % if _user.active: | |
|
120 | <span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span> | |
|
121 | % else: | |
|
122 | <span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span> | |
|
123 | % endif | |
|
110 | 124 | % else: |
|
111 | 125 | ${h.link_to_user(_user.username)} |
|
112 | 126 | %if getattr(_user, 'duplicate_perm', None): |
@@ -3,7 +3,11 b'' | |||
|
3 | 3 | |
|
4 | 4 | <div class="panel panel-default"> |
|
5 | 5 | <div class="panel-heading"> |
|
6 | <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3> | |
|
6 | <h3 class="panel-title"> | |
|
7 | <i class="icon-user-group" title="${_('User group')}"></i> | |
|
8 | ${h.link_to_group(c.user_group.users_group_name)} | |
|
9 | - ${_('Settings')} | |
|
10 | </h3> | |
|
7 | 11 | </div> |
|
8 | 12 | <div class="panel-body"> |
|
9 | 13 | ${h.secure_form(h.route_path('user_groups_update', user_group_id=c.user_group.users_group_id), id='edit_user_group', request=request)} |
@@ -25,7 +25,10 b'' | |||
|
25 | 25 | |
|
26 | 26 | <div class="panel panel-default"> |
|
27 | 27 | <div class="panel-heading"> |
|
28 | <h3 class="panel-title">${_('User: {}').format(c.user.username)}</h3> | |
|
28 | <h3 class="panel-title"> | |
|
29 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
30 | - ${_('Access Permissions')} | |
|
31 | </h3> | |
|
29 | 32 | </div> |
|
30 | 33 | <div class="panel-body"> |
|
31 | 34 | <table class="rctable"> |
@@ -4,8 +4,10 b'' | |||
|
4 | 4 | |
|
5 | 5 | <div class="panel panel-default"> |
|
6 | 6 | <div class="panel-heading"> |
|
7 |
<h3 class="panel-title"> |
|
|
8 | ${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)} | |
|
7 | <h3 class="panel-title"> | |
|
8 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
9 | - ${_('Audit Logs')} | |
|
10 | (${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)}) | |
|
9 | 11 | </h3> |
|
10 | 12 | <a href="${h.route_path('edit_user_audit_logs_download', user_id=c.user.user_id)}" class="panel-edit">${_('Download as JSON')}</a> |
|
11 | 13 | </div> |
@@ -1,6 +1,11 b'' | |||
|
1 | <%namespace name="base" file="/base/base.mako"/> | |
|
2 | ||
|
1 | 3 | <div class="panel panel-default"> |
|
2 | 4 | <div class="panel-heading"> |
|
3 |
<h3 class="panel-title"> |
|
|
5 | <h3 class="panel-title"> | |
|
6 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
7 | - ${_('Authentication Tokens')} | |
|
8 | </h3> | |
|
4 | 9 | </div> |
|
5 | 10 | <div class="panel-body"> |
|
6 | 11 | <div class="apikeys_wrap"> |
@@ -2,7 +2,10 b'' | |||
|
2 | 2 | |
|
3 | 3 | <div class="panel panel-default"> |
|
4 | 4 | <div class="panel-heading"> |
|
5 |
<h3 class="panel-title"> |
|
|
5 | <h3 class="panel-title"> | |
|
6 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
7 | - ${_('Caches')} | |
|
8 | </h3> | |
|
6 | 9 | </div> |
|
7 | 10 | <div class="panel-body"> |
|
8 | 11 | <p> |
@@ -2,7 +2,10 b'' | |||
|
2 | 2 | |
|
3 | 3 | <div class="panel panel-default"> |
|
4 | 4 | <div class="panel-heading"> |
|
5 |
<h3 class="panel-title"> |
|
|
5 | <h3 class="panel-title"> | |
|
6 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
7 | - ${_('Additional Email Addresses')} | |
|
8 | </h3> | |
|
6 | 9 | </div> |
|
7 | 10 | <div class="panel-body"> |
|
8 | 11 | <div class="emails_wrap"> |
@@ -1,9 +1,12 b'' | |||
|
1 | 1 | ## -*- coding: utf-8 -*- |
|
2 | ||
|
2 | <%namespace name="base" file="/base/base.mako"/> | |
|
3 | 3 | |
|
4 | 4 | <div class="panel panel-default"> |
|
5 | 5 | <div class="panel-heading"> |
|
6 |
<h3 class="panel-title"> |
|
|
6 | <h3 class="panel-title"> | |
|
7 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
8 | - ${_('User groups administration')} | |
|
9 | </h3> | |
|
7 | 10 | </div> |
|
8 | 11 | <div class="panel-body"> |
|
9 | 12 | <div class="fields"> |
@@ -1,6 +1,11 b'' | |||
|
1 | <%namespace name="base" file="/base/base.mako"/> | |
|
2 | ||
|
1 | 3 | <div class="panel panel-default"> |
|
2 | 4 | <div class="panel-heading"> |
|
3 |
<h3 class="panel-title"> |
|
|
5 | <h3 class="panel-title"> | |
|
6 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
7 | - ${_('Custom IP Whitelist')} | |
|
8 | </h3> | |
|
4 | 9 | </div> |
|
5 | 10 | <div class="panel-body"> |
|
6 | 11 | <div class="ips_wrap"> |
@@ -2,7 +2,10 b'' | |||
|
2 | 2 | |
|
3 | 3 | <div class="panel panel-default user-profile"> |
|
4 | 4 | <div class="panel-heading"> |
|
5 |
<h3 class="panel-title"> |
|
|
5 | <h3 class="panel-title"> | |
|
6 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
7 | - ${_('User Profile')} | |
|
8 | </h3> | |
|
6 | 9 | </div> |
|
7 | 10 | <div class="panel-body"> |
|
8 | 11 | <div class="user-profile-content"> |
@@ -73,7 +76,13 b'' | |||
|
73 | 76 | <div class="input textarea editor"> |
|
74 | 77 | ${h.textarea('description', rows=10, class_="medium")} |
|
75 | 78 | <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %> |
|
76 | <span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span> | |
|
79 | <span class="help-block"> | |
|
80 | % if c.visual.stylify_metatags: | |
|
81 | ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n} | |
|
82 | % else: | |
|
83 | ${_('Plain text format.')} | |
|
84 | % endif | |
|
85 | </span> | |
|
77 | 86 | <span id="meta-tags-desc" style="display: none"> |
|
78 | 87 | <%namespace name="dt" file="/data_table/_dt_elements.mako"/> |
|
79 | 88 | ${dt.metatags_help()} |
@@ -1,6 +1,11 b'' | |||
|
1 | <%namespace name="base" file="/base/base.mako"/> | |
|
2 | ||
|
1 | 3 | <div class="panel panel-default"> |
|
2 | 4 | <div class="panel-heading"> |
|
3 |
<h3 class="panel-title"> |
|
|
5 | <h3 class="panel-title"> | |
|
6 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
7 | - ${_('SSH Keys')} | |
|
8 | </h3> | |
|
4 | 9 | </div> |
|
5 | 10 | <div class="panel-body"> |
|
6 | 11 | <div class="sshkeys_wrap"> |
@@ -1,11 +1,16 b'' | |||
|
1 | <%namespace name="base" file="/base/base.mako"/> | |
|
2 | ||
|
1 | 3 | <div class="panel panel-default"> |
|
2 | 4 | <div class="panel-heading"> |
|
3 |
<h3 class="panel-title"> |
|
|
5 | <h3 class="panel-title"> | |
|
6 | ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')} | |
|
7 | - ${_('New SSH Key generation')} | |
|
8 | </h3> | |
|
4 | 9 | </div> |
|
5 | 10 | <div class="panel-body"> |
|
6 | 11 | %if c.ssh_enabled and c.ssh_key_generator_enabled: |
|
7 | 12 | <p> |
|
8 | ${_('Below is a 2048 bit generated SSH RSA key.')}<br/> | |
|
13 | ${_('Below is a 2048 bit generated SSH RSA key.')}<br/>${_('If you use older systems please try to generate a')} <a href="${h.current_route_path(request, private_format='legacy')}">${_('legacy format')}</a> ssh key.<br/> | |
|
9 | 14 | ${_('If You wish to use it to access RhodeCode via the SSH please save the private key and click `Use this generated key` at the bottom.')} |
|
10 | 15 | </p> |
|
11 | 16 | <h4>${_('Private key')}</h4> |
@@ -230,13 +230,13 b'' | |||
|
230 | 230 | </%def> |
|
231 | 231 | |
|
232 | 232 | |
|
233 | <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False)"> | |
|
233 | <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False, _class='rc-user')"> | |
|
234 | 234 | <% |
|
235 | 235 | email = h.email_or_none(contact) |
|
236 | 236 | rc_user = h.discover_user(contact) |
|
237 | 237 | %> |
|
238 | 238 | |
|
239 |
<div class=" |
|
|
239 | <div class="${_class}"> | |
|
240 | 240 | ${self.gravatar(email, size, tooltip=tooltip, tooltip_alt=contact, user=rc_user)} |
|
241 | 241 | <span class="${('user user-disabled' if show_disabled else 'user')}"> ${h.link_to_user(rc_user or contact)}</span> |
|
242 | 242 | </div> |
@@ -405,10 +405,6 b'' | |||
|
405 | 405 | %endif |
|
406 | 406 | %endif |
|
407 | 407 | </ul> |
|
408 | % else: | |
|
409 | <a class="menulink disabled"> | |
|
410 | <div class="menulabel">${_('Options')}<div class="show_more"></div></div> | |
|
411 | </a> | |
|
412 | 408 | % endif |
|
413 | 409 | </li> |
|
414 | 410 |
@@ -59,14 +59,14 b' examples = [' | |||
|
59 | 59 | |
|
60 | 60 | ( |
|
61 | 61 | 'Pivotal Tracker', |
|
62 | '(?:pivot-)(?<project_id>\d+)-(?<story>\d+)', | |
|
62 | '(?:pivot-)(?P<project_id>\d+)-(?P<story>\d+)', | |
|
63 | 63 | 'https://www.pivotaltracker.com/s/projects/${project_id}/stories/${story}', |
|
64 | 64 | 'PIV-', |
|
65 | 65 | ), |
|
66 | 66 | |
|
67 | 67 | ( |
|
68 | 68 | 'Trello', |
|
69 | '(?:trello-)(?<card_id>[a-zA-Z0-9]+)', | |
|
69 | '(?:trello-)(?P<card_id>[a-zA-Z0-9]+)', | |
|
70 | 70 | 'https://trello.com/example.com/${card_id}', |
|
71 | 71 | 'TRELLO-', |
|
72 | 72 | ), |
@@ -5,7 +5,7 b'' | |||
|
5 | 5 | ## |
|
6 | 6 | <%namespace name="base" file="/base/base.mako"/> |
|
7 | 7 | |
|
8 | <%def name="comment_block(comment, inline=False)"> | |
|
8 | <%def name="comment_block(comment, inline=False, active_pattern_entries=None)"> | |
|
9 | 9 | <% pr_index_ver = comment.get_index_version(getattr(c, 'versions', [])) %> |
|
10 | 10 | <% latest_ver = len(getattr(c, 'versions', [])) %> |
|
11 | 11 | % if inline: |
@@ -156,7 +156,7 b'' | |||
|
156 | 156 | </div> |
|
157 | 157 | </div> |
|
158 | 158 | <div class="text"> |
|
159 | ${h.render(comment.text, renderer=comment.renderer, mentions=True, repo_name=getattr(c, 'repo_name', None))} | |
|
159 | ${h.render(comment.text, renderer=comment.renderer, mentions=True, repo_name=getattr(c, 'repo_name', None), active_pattern_entries=active_pattern_entries)} | |
|
160 | 160 | </div> |
|
161 | 161 | |
|
162 | 162 | </div> |
@@ -164,13 +164,17 b'' | |||
|
164 | 164 | |
|
165 | 165 | ## generate main comments |
|
166 | 166 | <%def name="generate_comments(comments, include_pull_request=False, is_pull_request=False)"> |
|
167 | <% | |
|
168 | active_pattern_entries = h.get_active_pattern_entries(getattr(c, 'repo_name', None)) | |
|
169 | %> | |
|
170 | ||
|
167 | 171 | <div class="general-comments" id="comments"> |
|
168 | 172 | %for comment in comments: |
|
169 | 173 | <div id="comment-tr-${comment.comment_id}"> |
|
170 | 174 | ## only render comments that are not from pull request, or from |
|
171 | 175 | ## pull request and a status change |
|
172 | 176 | %if not comment.pull_request or (comment.pull_request and comment.status_change) or include_pull_request: |
|
173 | ${comment_block(comment)} | |
|
177 | ${comment_block(comment, active_pattern_entries=active_pattern_entries)} | |
|
174 | 178 | %endif |
|
175 | 179 | </div> |
|
176 | 180 | %endfor |
@@ -60,12 +60,16 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
60 | 60 | <% |
|
61 | 61 | diffset_container_id = h.md5(diffset.target_ref) |
|
62 | 62 | collapse_all = len(diffset.files) > collapse_when_files_over |
|
63 | active_pattern_entries = h.get_active_pattern_entries(getattr(c, 'repo_name', None)) | |
|
63 | 64 | %> |
|
64 | 65 | |
|
65 | 66 | %if use_comments: |
|
67 | ||
|
68 | ## Template for injecting comments | |
|
66 | 69 | <div id="cb-comments-inline-container-template" class="js-template"> |
|
67 |
${inline_comments_container([] |
|
|
70 | ${inline_comments_container([])} | |
|
68 | 71 | </div> |
|
72 | ||
|
69 | 73 | <div class="js-template" id="cb-comment-inline-form-template"> |
|
70 | 74 | <div class="comment-inline-form ac"> |
|
71 | 75 | |
@@ -259,7 +263,7 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
259 | 263 | ## new/deleted/empty content case |
|
260 | 264 | % if not filediff.hunks: |
|
261 | 265 | ## Comment container, on "fakes" hunk that contains all data to render comments |
|
262 | ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], filediff.hunk_ops, use_comments=use_comments, inline_comments=inline_comments)} | |
|
266 | ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], filediff.hunk_ops, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)} | |
|
263 | 267 | % endif |
|
264 | 268 | |
|
265 | 269 | %if filediff.limited_diff: |
@@ -299,7 +303,7 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
299 | 303 | ${hunk.section_header} |
|
300 | 304 | </td> |
|
301 | 305 | </tr> |
|
302 | ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], hunk, use_comments=use_comments, inline_comments=inline_comments)} | |
|
306 | ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)} | |
|
303 | 307 | % endfor |
|
304 | 308 | |
|
305 | 309 | <% unmatched_comments = (inline_comments or {}).get(filediff.patch['filename'], {}) %> |
@@ -323,7 +327,7 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
323 | 327 | <td class="cb-lineno cb-context"></td> |
|
324 | 328 | <td class="cb-lineno cb-context"></td> |
|
325 | 329 | <td class="cb-content cb-context"> |
|
326 |
${inline_comments_container(comments, |
|
|
330 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)} | |
|
327 | 331 | </td> |
|
328 | 332 | </tr> |
|
329 | 333 | %elif c.user_session_attrs["diffmode"] == 'sideside': |
@@ -348,7 +352,7 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
348 | 352 | <td class="cb-lineno cb-context"></td> |
|
349 | 353 | <td class="cb-content cb-context"> |
|
350 | 354 | % if lineno.startswith('o'): |
|
351 |
${inline_comments_container(comments, |
|
|
355 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)} | |
|
352 | 356 | % endif |
|
353 | 357 | </td> |
|
354 | 358 | |
@@ -356,7 +360,7 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
356 | 360 | <td class="cb-lineno cb-context"></td> |
|
357 | 361 | <td class="cb-content cb-context"> |
|
358 | 362 | % if lineno.startswith('n'): |
|
359 |
${inline_comments_container(comments, |
|
|
363 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)} | |
|
360 | 364 | % endif |
|
361 | 365 | </td> |
|
362 | 366 | </tr> |
@@ -415,7 +419,7 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
415 | 419 | <td class="cb-lineno cb-context"></td> |
|
416 | 420 | <td class="cb-lineno cb-context"></td> |
|
417 | 421 | <td class="cb-content cb-context"> |
|
418 |
${inline_comments_container(comments_dict['comments'], |
|
|
422 | ${inline_comments_container(comments_dict['comments'], active_pattern_entries=active_pattern_entries)} | |
|
419 | 423 | </td> |
|
420 | 424 | </tr> |
|
421 | 425 | %elif c.user_session_attrs["diffmode"] == 'sideside': |
@@ -427,7 +431,7 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
427 | 431 | <td class="cb-data cb-context"></td> |
|
428 | 432 | <td class="cb-lineno cb-context"></td> |
|
429 | 433 | <td class="cb-content cb-context"> |
|
430 |
${inline_comments_container(comments_dict['comments'], |
|
|
434 | ${inline_comments_container(comments_dict['comments'], active_pattern_entries=active_pattern_entries)} | |
|
431 | 435 | </td> |
|
432 | 436 | </tr> |
|
433 | 437 | %endif |
@@ -584,10 +588,11 b' from rhodecode.lib.diffs import NEW_FILE' | |||
|
584 | 588 | </%def> |
|
585 | 589 | |
|
586 | 590 | |
|
587 |
<%def name="inline_comments_container(comments, |
|
|
591 | <%def name="inline_comments_container(comments, active_pattern_entries=None)"> | |
|
592 | ||
|
588 | 593 | <div class="inline-comments"> |
|
589 | 594 | %for comment in comments: |
|
590 | ${commentblock.comment_block(comment, inline=True)} | |
|
595 | ${commentblock.comment_block(comment, inline=True, active_pattern_entries=active_pattern_entries)} | |
|
591 | 596 | %endfor |
|
592 | 597 | % if comments and comments[-1].outdated: |
|
593 | 598 | <span class="btn btn-secondary cb-comment-add-button comment-outdated}" style="display: none;}"> |
@@ -619,7 +624,7 b' def get_comments_for(diff_type, comments' | |||
|
619 | 624 | return data |
|
620 | 625 | %> |
|
621 | 626 | |
|
622 | <%def name="render_hunk_lines_sideside(filediff, hunk, use_comments=False, inline_comments=None)"> | |
|
627 | <%def name="render_hunk_lines_sideside(filediff, hunk, use_comments=False, inline_comments=None, active_pattern_entries=None)"> | |
|
623 | 628 | %for i, line in enumerate(hunk.sideside): |
|
624 | 629 | <% |
|
625 | 630 | old_line_anchor, new_line_anchor = None, None |
@@ -669,7 +674,7 b' def get_comments_for(diff_type, comments' | |||
|
669 | 674 | <span class="cb-code"><span class="cb-action ${action_class(line.original.action)}"></span>${line.original.content or '' | n}</span> |
|
670 | 675 | |
|
671 | 676 | %if use_comments and line.original.lineno and line_old_comments: |
|
672 |
${inline_comments_container(line_old_comments, |
|
|
677 | ${inline_comments_container(line_old_comments, active_pattern_entries=active_pattern_entries)} | |
|
673 | 678 | %endif |
|
674 | 679 | |
|
675 | 680 | </td> |
@@ -711,7 +716,7 b' def get_comments_for(diff_type, comments' | |||
|
711 | 716 | %endif |
|
712 | 717 | <span class="cb-code"><span class="cb-action ${action_class(line.modified.action)}"></span>${line.modified.content or '' | n}</span> |
|
713 | 718 | %if use_comments and line.modified.lineno and line_new_comments: |
|
714 |
${inline_comments_container(line_new_comments, |
|
|
719 | ${inline_comments_container(line_new_comments, active_pattern_entries=active_pattern_entries)} | |
|
715 | 720 | %endif |
|
716 | 721 | </td> |
|
717 | 722 | </tr> |
@@ -719,7 +724,7 b' def get_comments_for(diff_type, comments' | |||
|
719 | 724 | </%def> |
|
720 | 725 | |
|
721 | 726 | |
|
722 | <%def name="render_hunk_lines_unified(filediff, hunk, use_comments=False, inline_comments=None)"> | |
|
727 | <%def name="render_hunk_lines_unified(filediff, hunk, use_comments=False, inline_comments=None, active_pattern_entries=None)"> | |
|
723 | 728 | %for old_line_no, new_line_no, action, content, comments_args in hunk.unified: |
|
724 | 729 | |
|
725 | 730 | <% |
@@ -777,7 +782,7 b' def get_comments_for(diff_type, comments' | |||
|
777 | 782 | %endif |
|
778 | 783 | <span class="cb-code"><span class="cb-action ${action_class(action)}"></span> ${content or '' | n}</span> |
|
779 | 784 | %if use_comments and comments: |
|
780 |
${inline_comments_container(comments, |
|
|
785 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)} | |
|
781 | 786 | %endif |
|
782 | 787 | </td> |
|
783 | 788 | </tr> |
@@ -785,11 +790,11 b' def get_comments_for(diff_type, comments' | |||
|
785 | 790 | </%def> |
|
786 | 791 | |
|
787 | 792 | |
|
788 | <%def name="render_hunk_lines(filediff, diff_mode, hunk, use_comments, inline_comments)"> | |
|
793 | <%def name="render_hunk_lines(filediff, diff_mode, hunk, use_comments, inline_comments, active_pattern_entries)"> | |
|
789 | 794 | % if diff_mode == 'unified': |
|
790 | ${render_hunk_lines_unified(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments)} | |
|
795 | ${render_hunk_lines_unified(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)} | |
|
791 | 796 | % elif diff_mode == 'sideside': |
|
792 | ${render_hunk_lines_sideside(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments)} | |
|
797 | ${render_hunk_lines_sideside(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)} | |
|
793 | 798 | % else: |
|
794 | 799 | <tr class="cb-line"> |
|
795 | 800 | <td>unknown diff mode</td> |
@@ -310,9 +310,9 b'' | |||
|
310 | 310 | |
|
311 | 311 | <%def name="gist_access_id(gist_access_id, full_contact)"> |
|
312 | 312 | <div> |
|
313 |
< |
|
|
314 |
<a href="${h.route_path('gist_show', gist_id=gist_access_id)}"> |
|
|
315 |
</ |
|
|
313 | <code> | |
|
314 | <a href="${h.route_path('gist_show', gist_id=gist_access_id)}">${gist_access_id}</a> | |
|
315 | </code> | |
|
316 | 316 | </div> |
|
317 | 317 | </%def> |
|
318 | 318 |
@@ -21,7 +21,7 b'' | |||
|
21 | 21 | <ul> |
|
22 | 22 | % for elem in sorted(c.email_types.keys()): |
|
23 | 23 | <li> |
|
24 | <a href="${request.route_path('debug_style_email', email_id=elem, _query={'user':c.rhodecode_user.username})}">${elem}</a> | |
|
24 | <a href="${request.route_path('debug_style_email', email_id=elem, _query={'user':c.rhodecode_user.username, 'email': ''})}">${elem}</a> | |
|
25 | 25 | | |
|
26 | 26 | <a href="${request.route_path('debug_style_email_plain_rendered', email_id=elem, _query={'user':c.rhodecode_user.username})}">plain rendered</a> |
|
27 | 27 | </li> |
@@ -63,8 +63,8 b" css_style = ';'.join([" | |||
|
63 | 63 | |
|
64 | 64 | ## Constants |
|
65 | 65 | <% |
|
66 |
text_regular = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif |
|
|
67 |
text_monospace = "'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace |
|
|
66 | text_regular = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', Helvetica, sans-serif" | |
|
67 | text_monospace = "'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace" | |
|
68 | 68 | |
|
69 | 69 | %> |
|
70 | 70 | |
@@ -100,7 +100,7 b' text_monospace = "\'Menlo\', \'Liberation M' | |||
|
100 | 100 | -ms-text-size-adjust: 100%; |
|
101 | 101 | margin: 0; |
|
102 | 102 | padding: 0; |
|
103 | font-family: ${text_regular|n} | |
|
103 | font-family: ${text_regular|n}; | |
|
104 | 104 | } |
|
105 | 105 | |
|
106 | 106 | /* Prevent Webkit and Windows Mobile platforms from changing default font sizes.*/ |
@@ -184,6 +184,13 b' text_monospace = "\'Menlo\', \'Liberation M' | |||
|
184 | 184 | mso-table-rspace: 0pt; |
|
185 | 185 | } |
|
186 | 186 | |
|
187 | table tr { | |
|
188 | display: table-row; | |
|
189 | vertical-align: inherit; | |
|
190 | border-color: inherit; | |
|
191 | border-spacing: 0 3px; | |
|
192 | } | |
|
193 | ||
|
187 | 194 | table td { |
|
188 | 195 | padding: .65em 1em .65em 0; |
|
189 | 196 | border-collapse: collapse; |
@@ -202,6 +209,10 b' text_monospace = "\'Menlo\', \'Liberation M' | |||
|
202 | 209 | outline: 1px solid #979797 |
|
203 | 210 | } |
|
204 | 211 | |
|
212 | code { | |
|
213 | font-family: ${text_monospace|n}; | |
|
214 | } | |
|
215 | ||
|
205 | 216 | @media only screen and (-webkit-min-device-pixel-ratio: 2) { |
|
206 | 217 | /* Put your iPhone 4g styles in here */ |
|
207 | 218 | } |
@@ -283,7 +294,7 b' text_monospace = "\'Menlo\', \'Liberation M' | |||
|
283 | 294 | margin: 3px 0 13px 0 !important; |
|
284 | 295 | color: #424242 !important; |
|
285 | 296 | font-size: 13px !important; |
|
286 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; | |
|
297 | font-family: ${text_regular|n}; | |
|
287 | 298 | font-weight: normal !important; |
|
288 | 299 | overflow: visible !important; |
|
289 | 300 | line-height: 140% !important |
@@ -361,7 +372,7 b' text_monospace = "\'Menlo\', \'Liberation M' | |||
|
361 | 372 | } |
|
362 | 373 | |
|
363 | 374 | div.markdown-block code, div.markdown-block pre, div.markdown-block #ws, div.markdown-block #message { |
|
364 | font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace; | |
|
375 | font-family: ${text_monospace|n}; | |
|
365 | 376 | font-size: 11px; |
|
366 | 377 | -webkit-border-radius: 2px; |
|
367 | 378 | -moz-border-radius: 2px; |
@@ -490,8 +501,10 b' text_monospace = "\'Menlo\', \'Liberation M' | |||
|
490 | 501 | <![endif]--> |
|
491 | 502 | </head> |
|
492 | 503 | <body> |
|
504 | ||
|
505 | <div> | |
|
493 | 506 | <!-- Wrapper/Container Table: Use a wrapper table to control the width and the background color consistently of your email. Use this approach instead of setting attributes on the body tag. --> |
|
494 |
<table cellpadding="0" cellspacing="0" border="0" id="backgroundTable" align="left" style="margin:1%;width:97%;padding:0;font-family: |
|
|
507 | <table cellpadding="0" cellspacing="0" border="0" id="backgroundTable" align="left" style="margin:1%;width:97%;padding:0;font-family:${text_regular|n};font-weight:100;border:1px solid #dbd9da"> | |
|
495 | 508 | <tr> |
|
496 | 509 | <td valign="top" style="padding:0;"> |
|
497 | 510 | <table cellpadding="0" cellspacing="0" border="0" align="left" width="100%"> |
@@ -513,11 +526,13 b' text_monospace = "\'Menlo\', \'Liberation M' | |||
|
513 | 526 | </tr> |
|
514 | 527 | </table> |
|
515 | 528 | <!-- End of wrapper table --> |
|
529 | </div> | |
|
516 | 530 | |
|
517 | <div style="clear: both"></div> | |
|
518 | <div style="margin-left:1%;font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace}"> | |
|
531 | <div style="width:100%; clear: both; height: 1px"> </div> | |
|
532 | ||
|
533 | <div style="margin-left:1%;font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace};"> | |
|
519 | 534 | ${_('This is a notification from RhodeCode.')} |
|
520 | <a style="font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace}" href="${instance_url}"> | |
|
535 | <a style="font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace};" href="${instance_url}"> | |
|
521 | 536 | ${instance_url} |
|
522 | 537 | </a> |
|
523 | 538 | </div> |
@@ -58,7 +58,14 b'' | |||
|
58 | 58 | <div class="textarea editor"> |
|
59 | 59 | ${h.textarea('description',cols=23,rows=5,class_="medium")} |
|
60 | 60 | <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %> |
|
61 | <span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span> | |
|
61 | <span class="help-block"> | |
|
62 | % if c.visual.stylify_metatags: | |
|
63 | ${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n} | |
|
64 | % else: | |
|
65 | ${_('Plain text format.')} | |
|
66 | % endif | |
|
67 | ${_('Add a README file for longer descriptions')} | |
|
68 | </span> | |
|
62 | 69 | <span id="meta-tags-desc" style="display: none"> |
|
63 | 70 | <%namespace name="dt" file="/data_table/_dt_elements.mako"/> |
|
64 | 71 | ${dt.metatags_help()} |
@@ -14,32 +14,50 b'' | |||
|
14 | 14 | <div class="title"> |
|
15 | 15 | |
|
16 | 16 | </div> |
|
17 | ||
|
17 | 18 | <!-- end box / title --> |
|
18 | 19 | <div id="no_grid_data" class="table" style="display: none"> |
|
19 | <h2 class="no-object-border"> | |
|
20 | <h2> | |
|
20 | 21 | ${_('No repositories or repositories groups exists here.')} |
|
21 | 22 | </h2> |
|
22 | 23 | </div> |
|
23 | 24 | |
|
25 | <div id="grid_data_loading" class="table" style="display: none"> | |
|
26 | <i class="icon-spin animate-spin"></i> | |
|
27 | ${_('loading...')} | |
|
28 | </div> | |
|
29 | ||
|
24 | 30 | <div class="table"> |
|
25 | <div id="groups_list_wrap" style="min-height: 200px;"> | |
|
31 | <div id="groups_list_wrap" style="min-height: 200px;display: none"> | |
|
26 | 32 | <table id="group_list_table" class="display" style="width: 100%;"></table> |
|
27 | 33 | </div> |
|
28 | 34 | </div> |
|
29 | 35 | |
|
30 | 36 | <div class="table"> |
|
31 | <div id="repos_list_wrap" style="min-height: 200px;"> | |
|
37 | <div id="repos_list_wrap" style="min-height: 200px;display: none"> | |
|
32 | 38 | <table id="repo_list_table" class="display" style="width: 100%;"></table> |
|
33 | 39 | </div> |
|
34 | 40 | </div> |
|
35 | 41 | |
|
36 | 42 | </div> |
|
43 | ||
|
37 | 44 | <script> |
|
38 | 45 | $(document).ready(function () { |
|
46 | var noRepoData = null; | |
|
47 | var noGroupData = null; | |
|
48 | var $gridDataLoading = $('#grid_data_loading'); | |
|
39 | 49 | |
|
40 | // repo group list | |
|
50 | // global show loading of hidden grids | |
|
51 | $(document).on('preInit.dt', function (e, settings) { | |
|
52 | $gridDataLoading.show(); | |
|
53 | }); | |
|
54 | ||
|
55 | ## repo group list | |
|
41 | 56 | var $groupListTable = $('#group_list_table'); |
|
42 | 57 | |
|
58 | $groupListTable.on('xhr.dt', function (e, settings, json, xhr) { | |
|
59 | $gridDataLoading.hide(); | |
|
60 | }); | |
|
43 | 61 | $groupListTable.DataTable({ |
|
44 | 62 | processing: true, |
|
45 | 63 | serverSide: true, |
@@ -97,11 +115,12 b'' | |||
|
97 | 115 | emptyTable: _gettext("No repository groups present.") |
|
98 | 116 | }, |
|
99 | 117 | "drawCallback": function (settings, json) { |
|
118 | ||
|
100 | 119 | // hide grid if it's empty |
|
101 | 120 | if (settings.fnRecordsDisplay() === 0) { |
|
102 |
|
|
|
121 | noGroupData = true; | |
|
103 | 122 | // both hidden, show no-data |
|
104 |
if ( |
|
|
123 | if (noRepoData === true) { | |
|
105 | 124 | $('#no_grid_data').show(); |
|
106 | 125 | } |
|
107 | 126 | } else { |
@@ -119,18 +138,13 b'' | |||
|
119 | 138 | }, |
|
120 | 139 | }); |
|
121 | 140 | |
|
122 | $groupListTable.on('xhr.dt', function (e, settings, json, xhr) { | |
|
123 | $groupListTable.css('opacity', 1); | |
|
124 | }); | |
|
125 | 141 | |
|
126 | $groupListTable.on('preXhr.dt', function (e, settings, data) { | |
|
127 | $groupListTable.css('opacity', 0.3); | |
|
128 | }); | |
|
129 | ||
|
130 | ||
|
131 | ## // repo list | |
|
142 | ## repo list | |
|
132 | 143 | var $repoListTable = $('#repo_list_table'); |
|
133 | 144 | |
|
145 | $repoListTable.on('xhr.dt', function (e, settings, json, xhr) { | |
|
146 | $gridDataLoading.hide(); | |
|
147 | }); | |
|
134 | 148 | $repoListTable.DataTable({ |
|
135 | 149 | processing: true, |
|
136 | 150 | serverSide: true, |
@@ -188,11 +202,13 b'' | |||
|
188 | 202 | emptyTable: _gettext("No repositories present.") |
|
189 | 203 | }, |
|
190 | 204 | "drawCallback": function (settings, json) { |
|
205 | ||
|
191 | 206 | // hide grid if it's empty |
|
192 | 207 | if (settings.fnRecordsDisplay() == 0) { |
|
193 |
|
|
|
208 | noRepoData = true; | |
|
209 | ||
|
194 | 210 | // both hidden, show no-data |
|
195 |
if ( |
|
|
211 | if (noGroupData === true) { | |
|
196 | 212 | $('#no_grid_data').show() |
|
197 | 213 | } |
|
198 | 214 | } else { |
@@ -210,14 +226,6 b'' | |||
|
210 | 226 | }, |
|
211 | 227 | }); |
|
212 | 228 | |
|
213 | $repoListTable.on('xhr.dt', function (e, settings, json, xhr) { | |
|
214 | $repoListTable.css('opacity', 1); | |
|
215 | }); | |
|
216 | ||
|
217 | $repoListTable.on('preXhr.dt', function (e, settings, data) { | |
|
218 | $repoListTable.css('opacity', 0.3); | |
|
219 | }); | |
|
220 | ||
|
221 | 229 | }); |
|
222 | 230 | </script> |
|
223 | 231 | </%def> |
@@ -514,6 +514,7 b'' | |||
|
514 | 514 | // Flush changes into textarea |
|
515 | 515 | codeMirrorInstance.save(); |
|
516 | 516 | prButtonLock(true, null, 'all'); |
|
517 | $pullRequestSubmit.val(_gettext('Please wait creating pull request...')); | |
|
517 | 518 | }); |
|
518 | 519 | |
|
519 | 520 | prButtonLock(true, "${_('Please select source and target')}", 'all'); |
@@ -438,6 +438,11 b'' | |||
|
438 | 438 | |
|
439 | 439 | <h2 style="text-align: center"> |
|
440 | 440 | ${_('Cannot show diff when pull request state is changing. Current progress state')}: <span class="tag tag-merge-state-${c.pull_request.state}">${c.pull_request.state}</span> |
|
441 | ||
|
442 | % if c.is_super_admin: | |
|
443 | <br/> | |
|
444 | If you think this is an error try <a href="${h.current_route_path(request, force_state='created')}">forced state reset</a> to <span class="tag tag-merge-state-created">created</span> state. | |
|
445 | % endif | |
|
441 | 446 | </h2> |
|
442 | 447 | |
|
443 | 448 | % else: |
@@ -29,6 +29,7 b' import shutil' | |||
|
29 | 29 | |
|
30 | 30 | import configobj |
|
31 | 31 | |
|
32 | from rhodecode.model.settings import SettingsModel | |
|
32 | 33 | from rhodecode.tests import * |
|
33 | 34 | from rhodecode.model.db import Repository, User, RepoGroup, UserGroup, Gist, UserEmailMap |
|
34 | 35 | from rhodecode.model.meta import Session |
@@ -122,7 +123,7 b' class Fixture(object):' | |||
|
122 | 123 | |
|
123 | 124 | return context() |
|
124 | 125 | |
|
125 | def auth_restriction(self, auth_restriction): | |
|
126 | def auth_restriction(self, registry, auth_restriction): | |
|
126 | 127 | """ |
|
127 | 128 | Context process for changing the builtin rhodecode plugin auth restrictions. |
|
128 | 129 | Use like: |
@@ -135,26 +136,26 b' class Fixture(object):' | |||
|
135 | 136 | |
|
136 | 137 | class context(object): |
|
137 | 138 | def _get_pluing(self): |
|
138 | plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format( | |
|
139 | RhodeCodeAuthPlugin.uid) | |
|
139 | plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid) | |
|
140 | 140 | plugin = RhodeCodeAuthPlugin(plugin_id) |
|
141 | 141 | return plugin |
|
142 | 142 | |
|
143 | 143 | def __enter__(self): |
|
144 | 144 | plugin = self._get_pluing() |
|
145 | plugin.create_or_update_setting( | |
|
146 | 'auth_restriction', auth_restriction) | |
|
145 | plugin.create_or_update_setting('auth_restriction', auth_restriction) | |
|
147 | 146 | Session().commit() |
|
147 | SettingsModel().invalidate_settings_cache() | |
|
148 | 148 | |
|
149 | 149 | def __exit__(self, exc_type, exc_val, exc_tb): |
|
150 | 150 | plugin = self._get_pluing() |
|
151 | 151 | plugin.create_or_update_setting( |
|
152 | 152 | 'auth_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_NONE) |
|
153 | 153 | Session().commit() |
|
154 | SettingsModel().invalidate_settings_cache() | |
|
154 | 155 | |
|
155 | 156 | return context() |
|
156 | 157 | |
|
157 | def scope_restriction(self, scope_restriction): | |
|
158 | def scope_restriction(self, registry, scope_restriction): | |
|
158 | 159 | """ |
|
159 | 160 | Context process for changing the builtin rhodecode plugin scope restrictions. |
|
160 | 161 | Use like: |
@@ -167,22 +168,22 b' class Fixture(object):' | |||
|
167 | 168 | |
|
168 | 169 | class context(object): |
|
169 | 170 | def _get_pluing(self): |
|
170 | plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format( | |
|
171 | RhodeCodeAuthPlugin.uid) | |
|
171 | plugin_id = 'egg:rhodecode-enterprise-ce#{}'.format(RhodeCodeAuthPlugin.uid) | |
|
172 | 172 | plugin = RhodeCodeAuthPlugin(plugin_id) |
|
173 | 173 | return plugin |
|
174 | 174 | |
|
175 | 175 | def __enter__(self): |
|
176 | 176 | plugin = self._get_pluing() |
|
177 | plugin.create_or_update_setting( | |
|
178 | 'scope_restriction', scope_restriction) | |
|
177 | plugin.create_or_update_setting('scope_restriction', scope_restriction) | |
|
179 | 178 | Session().commit() |
|
179 | SettingsModel().invalidate_settings_cache() | |
|
180 | 180 | |
|
181 | 181 | def __exit__(self, exc_type, exc_val, exc_tb): |
|
182 | 182 | plugin = self._get_pluing() |
|
183 | 183 | plugin.create_or_update_setting( |
|
184 | 184 | 'scope_restriction', RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_ALL) |
|
185 | 185 | Session().commit() |
|
186 | SettingsModel().invalidate_settings_cache() | |
|
186 | 187 | |
|
187 | 188 | return context() |
|
188 | 189 |
@@ -43,6 +43,9 b' class TestIssueTrackerSettingsModel(obje' | |||
|
43 | 43 | settings_mock.return_value = input_settings |
|
44 | 44 | result = model.get_global_settings(cache=True) |
|
45 | 45 | get_settings.assert_called_once_with(cache=True) |
|
46 | for k, v in result.items(): | |
|
47 | v.pop('pat_compiled', None) | |
|
48 | ||
|
46 | 49 | assert expected_result == result |
|
47 | 50 | |
|
48 | 51 | def test_get_repo_settings_raise_exception_when_repo_is_not_set(self): |
@@ -68,6 +71,8 b' class TestIssueTrackerSettingsModel(obje' | |||
|
68 | 71 | settings_mock.return_value = input_settings |
|
69 | 72 | result = model.get_repo_settings(cache=True) |
|
70 | 73 | get_settings.assert_called_once_with(cache=True) |
|
74 | for k, v in result.items(): | |
|
75 | v.pop('pat_compiled', None) | |
|
71 | 76 | assert expected_result == result |
|
72 | 77 | |
|
73 | 78 | @pytest.mark.parametrize("inherit_settings, method", [ |
General Comments 0
You need to be logged in to leave comments.
Login now