##// END OF EJS Templates
release: merge back stable branch into default
marcink -
r4390:4a659147 merge default
parent child Browse files
Show More
@@ -0,0 +1,41 b''
1 |RCE| 4.19.1 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2020-05-25
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13
14
15 General
16 ^^^^^^^
17
18
19
20 Security
21 ^^^^^^^^
22
23 - issue-tracker: fixed XSS inside the newly generated description fields.
24
25
26 Performance
27 ^^^^^^^^^^^
28
29 -
30
31
32 Fixes
33 ^^^^^
34
35 - HTTP: fixed headers problems in the application.
36
37
38 Upgrade notes
39 ^^^^^^^^^^^^^
40
41 - Un-scheduled release addressing problems in 4.19.X releases.
@@ -0,0 +1,52 b''
1 |RCE| 4.19.2 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2020-06-10
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13 - Files: landing refs will be the default for files view, resulting in names of branches instead of hashes.
14 This fixes some problems reported with navigation, and also SVN.
15 - Diffs: expose per-file comment counts.
16
17
18 General
19 ^^^^^^^
20
21 - Navigation: explicitly link to summary page for summary link.
22 - Main Page: simplify footer, and expose docs link.
23 - Docs: added mention how to change default integration templates.
24 - Files: use ref names in the url, and make usage of default landing refs.
25 - Files: report the name of missing commit.
26 - Sweet alerts: reduced font size.
27
28
29 Security
30 ^^^^^^^^
31
32 - Branch permissions: fix XSS on branch permissions adding screen.
33
34
35 Performance
36 ^^^^^^^^^^^
37
38
39
40 Fixes
41 ^^^^^
42
43 - Emails: improved styling, and fixed problems with some email clients rendering.
44 - Files: fixed label for copy-path action.
45 - Files: use a common function to handle url-by-refs, and fix landing refs for SVN.
46
47
48 Upgrade notes
49 ^^^^^^^^^^^^^
50
51 - Un-scheduled release addressing problems in 4.19.X releases.
52 It brings some added features that weren't ready for 4.19.0.
@@ -1,64 +1,67 b''
1 1 1bd3e92b7e2e2d2024152b34bb88dff1db544a71 v4.0.0
2 2 170c5398320ea6cddd50955e88d408794c21d43a v4.0.1
3 3 c3fe200198f5aa34cf2e4066df2881a9cefe3704 v4.1.0
4 4 7fd5c850745e2ea821fb4406af5f4bff9b0a7526 v4.1.1
5 5 41c87da28a179953df86061d817bc35533c66dd2 v4.1.2
6 6 baaf9f5bcea3bae0ef12ae20c8b270482e62abb6 v4.2.0
7 7 32a70c7e56844a825f61df496ee5eaf8c3c4e189 v4.2.1
8 8 fa695cdb411d294679ac081d595ac654e5613b03 v4.3.0
9 9 0e4dc11b58cad833c513fe17bac39e6850edf959 v4.3.1
10 10 8a876f48f5cb1d018b837db28ff928500cb32cfb v4.4.0
11 11 8dd86b410b1aac086ffdfc524ef300f896af5047 v4.4.1
12 12 d2514226abc8d3b4f6fb57765f47d1b6fb360a05 v4.4.2
13 13 27d783325930af6dad2741476c0d0b1b7c8415c2 v4.5.0
14 14 7f2016f352abcbdba4a19d4039c386e9629449da v4.5.1
15 15 416fec799314c70a5c780fb28b3357b08869333a v4.5.2
16 16 27c3b85fafc83143e6678fbc3da69e1615bcac55 v4.6.0
17 17 5ad13deb9118c2a5243d4032d4d9cc174e5872db v4.6.1
18 18 2be921e01fa24bb102696ada596f87464c3666f6 v4.7.0
19 19 7198bdec29c2872c974431d55200d0398354cdb1 v4.7.1
20 20 bd1c8d230fe741c2dfd7100a0ef39fd0774fd581 v4.7.2
21 21 9731914f89765d9628dc4dddc84bc9402aa124c8 v4.8.0
22 22 c5a2b7d0e4bbdebc4a62d7b624befe375207b659 v4.9.0
23 23 d9aa3b27ac9f7e78359775c75fedf7bfece232f1 v4.9.1
24 24 4ba4d74981cec5d6b28b158f875a2540952c2f74 v4.10.0
25 25 0a6821cbd6b0b3c21503002f88800679fa35ab63 v4.10.1
26 26 434ad90ec8d621f4416074b84f6e9ce03964defb v4.10.2
27 27 68baee10e698da2724c6e0f698c03a6abb993bf2 v4.10.3
28 28 00821d3afd1dce3f4767cc353f84a17f7d5218a1 v4.10.4
29 29 22f6744ad8cc274311825f63f953e4dee2ea5cb9 v4.10.5
30 30 96eb24bea2f5f9258775245e3f09f6fa0a4dda01 v4.10.6
31 31 3121217a812c956d7dd5a5875821bd73e8002a32 v4.11.0
32 32 fa98b454715ac5b912f39e84af54345909a2a805 v4.11.1
33 33 3982abcfdcc229a723cebe52d3a9bcff10bba08e v4.11.2
34 34 33195f145db9172f0a8f1487e09207178a6ab065 v4.11.3
35 35 194c74f33e32bbae6fc4d71ec5a999cff3c13605 v4.11.4
36 36 8fbd8b0c3ddc2fa4ac9e4ca16942a03eb593df2d v4.11.5
37 37 f0609aa5d5d05a1ca2f97c3995542236131c9d8a v4.11.6
38 38 b5b30547d90d2e088472a70c84878f429ffbf40d v4.12.0
39 39 9072253aa8894d20c00b4a43dc61c2168c1eff94 v4.12.1
40 40 6a517543ea9ef9987d74371bd2a315eb0b232dc9 v4.12.2
41 41 7fc0731b024c3114be87865eda7ab621cc957e32 v4.12.3
42 42 6d531c0b068c6eda62dddceedc9f845ecb6feb6f v4.12.4
43 43 3d6bf2d81b1564830eb5e83396110d2a9a93eb1e v4.13.0
44 44 5468fc89e708bd90e413cd0d54350017abbdbc0e v4.13.1
45 45 610d621550521c314ee97b3d43473ac0bcf06fb8 v4.13.2
46 46 7dc62c090881fb5d03268141e71e0940d7c3295d v4.13.3
47 47 9151328c1c46b72ba6f00d7640d9141e75aa1ca2 v4.14.0
48 48 a47eeac5dfa41fa6779d90452affba4091c3ade8 v4.14.1
49 49 4b34ce0d2c3c10510626b3b65044939bb7a2cddf v4.15.0
50 50 14502561d22e6b70613674cd675ae9a604b7989f v4.15.1
51 51 4aaa40b605b01af78a9f6882eca561c54b525ef0 v4.15.2
52 52 797744642eca86640ed20bef2cd77445780abaec v4.16.0
53 53 6c3452c7c25ed35ff269690929e11960ed6ad7d3 v4.16.1
54 54 5d8057df561c4b6b81b6401aed7d2f911e6e77f7 v4.16.2
55 55 13acfc008896ef4c62546bab5074e8f6f89b4fa7 v4.17.0
56 56 45b9b610976f483877142fe75321808ce9ebac59 v4.17.1
57 57 ad5bd0c4bd322fdbd04bb825a3d027e08f7a3901 v4.17.2
58 58 037f5794b55a6236d68f6485a485372dde6566e0 v4.17.3
59 59 83bc3100cfd6094c1d04f475ddb299b7dc3d0b33 v4.17.4
60 60 e3de8c95baf8cc9109ca56aee8193a2cb6a54c8a v4.17.4
61 61 f37a3126570477543507f0bc9d245ce75546181a v4.18.0
62 62 71d8791463e87b64c1a18475de330ee600d37561 v4.18.1
63 63 4bd6b75dac1d25c64885d4d49385e5533f21c525 v4.18.2
64 64 12ed92fe57f2e9fc7b71dc0b65e26c2da5c7085f v4.18.3
65 ddef396a6567117de531d67d44c739cbbfc3eebb v4.19.0
66 c0c65acd73914bf4368222d510afe1161ab8c07c v4.19.1
67 7ac623a4a2405917e2af660d645ded662011e40d v4.19.2
@@ -1,27 +1,34 b''
1 1 .. _integrations-jira:
2 2
3 3 JIRA integration
4 4 ================
5 5
6 6 .. important::
7 7
8 8 JIRA integration is only available in |RCEE|.
9 9
10 10
11 11 .. important::
12 12
13 13 In order to make issue numbers clickable in commit messages, see the
14 14 :ref:`rhodecode-issue-trackers-ref` section. The JIRA integration
15 15 only deals with altering JIRA issues.
16 16
17 17
18 18 The JIRA integration allows you to reference and change issue statuses in
19 19 JIRA directly from commit messages using commit message patterns such as
20 20 ``fixes #JIRA-235`` in order to change the status of issue JIRA-235 to
21 21 eg. "Resolved".
22 22
23 23 In order to apply a status to a JIRA issue, it is necessary to find the
24 24 transition status id in the *Workflow* section of JIRA.
25 25
26 26 Once you have the transition status id, you can create a JIRA integration
27 27 as outlined in :ref:`creating-integrations`.
28
29
30 .. note::
31
32 There's an option to configure integration templates.
33 Please see :ref:`integrations-rcextensions` section.
34 rcextensions examples are here: https://code.rhodecode.com/rhodecode-enterprise-ce/files/default/rhodecode/config/rcextensions/examples/custom_integration_templates.py
@@ -1,28 +1,34 b''
1 1 .. _integrations-redmine:
2 2
3 3 Redmine integration
4 4 ===================
5 5
6 6 .. important::
7 7
8 8 Redmine integration is only available in |RCEE|.
9 9
10 10
11 11 .. important::
12 12
13 13 In order to make issue numbers clickable in commit messages, see the section
14 14 :ref:`rhodecode-issue-trackers-ref`. Redmine integration is specifically for
15 15 altering Redmine issues.
16 16
17 17
18 18 Redmine integration allows you to reference and change issue statuses in
19 19 Redmine directly from commit messages, using commit message patterns such as
20 20 ``fixes #235`` in order to change the status of issue 235 to eg. "Resolved".
21 21
22 22 To set a Redmine integration up, it is first necessary to obtain a Redmine API
23 23 key. This can be found under *My Account* in the Redmine application.
24 24 You may have to enable API Access in Redmine settings if it is not already
25 25 available.
26 26
27 27 Once you have the API key, create a Redmine integration as outlined in
28 28 :ref:`creating-integrations`.
29
30
31 .. note::
32
33 There's an option to configure integration templates. Please see :ref:`integrations-rcextensions` section.
34 rcextensions examples are here: https://code.rhodecode.com/rhodecode-enterprise-ce/files/default/rhodecode/config/rcextensions/examples/custom_integration_templates.py No newline at end of file
@@ -1,141 +1,143 b''
1 1 .. _rhodecode-release-notes-ref:
2 2
3 3 Release Notes
4 4 =============
5 5
6 6 |RCE| 4.x Versions
7 7 ------------------
8 8
9 9 .. toctree::
10 10 :maxdepth: 1
11 11
12 release-notes-4.19.2.rst
13 release-notes-4.19.1.rst
12 14 release-notes-4.19.0.rst
13 15 release-notes-4.18.3.rst
14 16 release-notes-4.18.2.rst
15 17 release-notes-4.18.1.rst
16 18 release-notes-4.18.0.rst
17 19 release-notes-4.17.4.rst
18 20 release-notes-4.17.3.rst
19 21 release-notes-4.17.2.rst
20 22 release-notes-4.17.1.rst
21 23 release-notes-4.17.0.rst
22 24 release-notes-4.16.2.rst
23 25 release-notes-4.16.1.rst
24 26 release-notes-4.16.0.rst
25 27 release-notes-4.15.2.rst
26 28 release-notes-4.15.1.rst
27 29 release-notes-4.15.0.rst
28 30 release-notes-4.14.1.rst
29 31 release-notes-4.14.0.rst
30 32 release-notes-4.13.3.rst
31 33 release-notes-4.13.2.rst
32 34 release-notes-4.13.1.rst
33 35 release-notes-4.13.0.rst
34 36 release-notes-4.12.4.rst
35 37 release-notes-4.12.3.rst
36 38 release-notes-4.12.2.rst
37 39 release-notes-4.12.1.rst
38 40 release-notes-4.12.0.rst
39 41 release-notes-4.11.6.rst
40 42 release-notes-4.11.5.rst
41 43 release-notes-4.11.4.rst
42 44 release-notes-4.11.3.rst
43 45 release-notes-4.11.2.rst
44 46 release-notes-4.11.1.rst
45 47 release-notes-4.11.0.rst
46 48 release-notes-4.10.6.rst
47 49 release-notes-4.10.5.rst
48 50 release-notes-4.10.4.rst
49 51 release-notes-4.10.3.rst
50 52 release-notes-4.10.2.rst
51 53 release-notes-4.10.1.rst
52 54 release-notes-4.10.0.rst
53 55 release-notes-4.9.1.rst
54 56 release-notes-4.9.0.rst
55 57 release-notes-4.8.0.rst
56 58 release-notes-4.7.2.rst
57 59 release-notes-4.7.1.rst
58 60 release-notes-4.7.0.rst
59 61 release-notes-4.6.1.rst
60 62 release-notes-4.6.0.rst
61 63 release-notes-4.5.2.rst
62 64 release-notes-4.5.1.rst
63 65 release-notes-4.5.0.rst
64 66 release-notes-4.4.2.rst
65 67 release-notes-4.4.1.rst
66 68 release-notes-4.4.0.rst
67 69 release-notes-4.3.1.rst
68 70 release-notes-4.3.0.rst
69 71 release-notes-4.2.1.rst
70 72 release-notes-4.2.0.rst
71 73 release-notes-4.1.2.rst
72 74 release-notes-4.1.1.rst
73 75 release-notes-4.1.0.rst
74 76 release-notes-4.0.1.rst
75 77 release-notes-4.0.0.rst
76 78
77 79 |RCE| 3.x Versions
78 80 ------------------
79 81
80 82 .. toctree::
81 83 :maxdepth: 1
82 84
83 85 release-notes-3.8.4.rst
84 86 release-notes-3.8.3.rst
85 87 release-notes-3.8.2.rst
86 88 release-notes-3.8.1.rst
87 89 release-notes-3.8.0.rst
88 90 release-notes-3.7.1.rst
89 91 release-notes-3.7.0.rst
90 92 release-notes-3.6.1.rst
91 93 release-notes-3.6.0.rst
92 94 release-notes-3.5.2.rst
93 95 release-notes-3.5.1.rst
94 96 release-notes-3.5.0.rst
95 97 release-notes-3.4.1.rst
96 98 release-notes-3.4.0.rst
97 99 release-notes-3.3.4.rst
98 100 release-notes-3.3.3.rst
99 101 release-notes-3.3.2.rst
100 102 release-notes-3.3.1.rst
101 103 release-notes-3.3.0.rst
102 104 release-notes-3.2.3.rst
103 105 release-notes-3.2.2.rst
104 106 release-notes-3.2.1.rst
105 107 release-notes-3.2.0.rst
106 108 release-notes-3.1.1.rst
107 109 release-notes-3.1.0.rst
108 110 release-notes-3.0.2.rst
109 111 release-notes-3.0.1.rst
110 112 release-notes-3.0.0.rst
111 113
112 114 |RCE| 2.x Versions
113 115 ------------------
114 116
115 117 .. toctree::
116 118 :maxdepth: 1
117 119
118 120 release-notes-2.2.8.rst
119 121 release-notes-2.2.7.rst
120 122 release-notes-2.2.6.rst
121 123 release-notes-2.2.5.rst
122 124 release-notes-2.2.4.rst
123 125 release-notes-2.2.3.rst
124 126 release-notes-2.2.2.rst
125 127 release-notes-2.2.1.rst
126 128 release-notes-2.2.0.rst
127 129 release-notes-2.1.0.rst
128 130 release-notes-2.0.2.rst
129 131 release-notes-2.0.1.rst
130 132 release-notes-2.0.0.rst
131 133
132 134 |RCE| 1.x Versions
133 135 ------------------
134 136
135 137 .. toctree::
136 138 :maxdepth: 1
137 139
138 140 release-notes-1.7.2.rst
139 141 release-notes-1.7.1.rst
140 142 release-notes-1.7.0.rst
141 143 release-notes-1.6.0.rst
@@ -1,807 +1,808 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 import time
22 22 import logging
23 23 import operator
24 24
25 25 from pyramid import compat
26 26 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPBadRequest
27 27
28 28 from rhodecode.lib import helpers as h, diffs, rc_cache
29 29 from rhodecode.lib.utils2 import (
30 30 StrictAttributeDict, str2bool, safe_int, datetime_to_time, safe_unicode)
31 31 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
32 32 from rhodecode.lib.vcs.backends.base import EmptyCommit
33 33 from rhodecode.lib.vcs.exceptions import RepositoryRequirementError
34 34 from rhodecode.model import repo
35 35 from rhodecode.model import repo_group
36 36 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 40 from rhodecode.model.settings import VcsSettingsModel, IssueTrackerSettingsModel
41 41 from rhodecode.model.repo import ReadmeFinder
42 42
43 43 log = logging.getLogger(__name__)
44 44
45 45
46 46 ADMIN_PREFIX = '/_admin'
47 47 STATIC_FILE_PREFIX = '/_static'
48 48
49 49 URL_NAME_REQUIREMENTS = {
50 50 # group name can have a slash in them, but they must not end with a slash
51 51 'group_name': r'.*?[^/]',
52 52 'repo_group_name': r'.*?[^/]',
53 53 # repo names can have a slash in them, but they must not end with a slash
54 54 'repo_name': r'.*?[^/]',
55 55 # file path eats up everything at the end
56 56 'f_path': r'.*',
57 57 # reference types
58 58 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
59 59 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
60 60 }
61 61
62 62
63 63 def add_route_with_slash(config,name, pattern, **kw):
64 64 config.add_route(name, pattern, **kw)
65 65 if not pattern.endswith('/'):
66 66 config.add_route(name + '_slash', pattern + '/', **kw)
67 67
68 68
69 69 def add_route_requirements(route_path, requirements=None):
70 70 """
71 71 Adds regex requirements to pyramid routes using a mapping dict
72 72 e.g::
73 73 add_route_requirements('{repo_name}/settings')
74 74 """
75 75 requirements = requirements or URL_NAME_REQUIREMENTS
76 76 for key, regex in requirements.items():
77 77 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
78 78 return route_path
79 79
80 80
81 81 def get_format_ref_id(repo):
82 82 """Returns a `repo` specific reference formatter function"""
83 83 if h.is_svn(repo):
84 84 return _format_ref_id_svn
85 85 else:
86 86 return _format_ref_id
87 87
88 88
89 89 def _format_ref_id(name, raw_id):
90 90 """Default formatting of a given reference `name`"""
91 91 return name
92 92
93 93
94 94 def _format_ref_id_svn(name, raw_id):
95 95 """Special way of formatting a reference for Subversion including path"""
96 96 return '%s@%s' % (name, raw_id)
97 97
98 98
99 99 class TemplateArgs(StrictAttributeDict):
100 100 pass
101 101
102 102
103 103 class BaseAppView(object):
104 104
105 105 def __init__(self, context, request):
106 106 self.request = request
107 107 self.context = context
108 108 self.session = request.session
109 109 if not hasattr(request, 'user'):
110 110 # NOTE(marcink): edge case, we ended up in matched route
111 111 # but probably of web-app context, e.g API CALL/VCS CALL
112 112 if hasattr(request, 'vcs_call') or hasattr(request, 'rpc_method'):
113 113 log.warning('Unable to process request `%s` in this scope', request)
114 114 raise HTTPBadRequest()
115 115
116 116 self._rhodecode_user = request.user # auth user
117 117 self._rhodecode_db_user = self._rhodecode_user.get_instance()
118 118 self._maybe_needs_password_change(
119 119 request.matched_route.name, self._rhodecode_db_user)
120 120
121 121 def _maybe_needs_password_change(self, view_name, user_obj):
122 122 log.debug('Checking if user %s needs password change on view %s',
123 123 user_obj, view_name)
124 124 skip_user_views = [
125 125 'logout', 'login',
126 126 'my_account_password', 'my_account_password_update'
127 127 ]
128 128
129 129 if not user_obj:
130 130 return
131 131
132 132 if user_obj.username == User.DEFAULT_USER:
133 133 return
134 134
135 135 now = time.time()
136 136 should_change = user_obj.user_data.get('force_password_change')
137 137 change_after = safe_int(should_change) or 0
138 138 if should_change and now > change_after:
139 139 log.debug('User %s requires password change', user_obj)
140 140 h.flash('You are required to change your password', 'warning',
141 141 ignore_duplicate=True)
142 142
143 143 if view_name not in skip_user_views:
144 144 raise HTTPFound(
145 145 self.request.route_path('my_account_password'))
146 146
147 147 def _log_creation_exception(self, e, repo_name):
148 148 _ = self.request.translate
149 149 reason = None
150 150 if len(e.args) == 2:
151 151 reason = e.args[1]
152 152
153 153 if reason == 'INVALID_CERTIFICATE':
154 154 log.exception(
155 155 'Exception creating a repository: invalid certificate')
156 156 msg = (_('Error creating repository %s: invalid certificate')
157 157 % repo_name)
158 158 else:
159 159 log.exception("Exception creating a repository")
160 160 msg = (_('Error creating repository %s')
161 161 % repo_name)
162 162 return msg
163 163
164 164 def _get_local_tmpl_context(self, include_app_defaults=True):
165 165 c = TemplateArgs()
166 166 c.auth_user = self.request.user
167 167 # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user
168 168 c.rhodecode_user = self.request.user
169 169
170 170 if include_app_defaults:
171 171 from rhodecode.lib.base import attach_context_attributes
172 172 attach_context_attributes(c, self.request, self.request.user.user_id)
173 173
174 174 c.is_super_admin = c.auth_user.is_admin
175 175
176 176 c.can_create_repo = c.is_super_admin
177 177 c.can_create_repo_group = c.is_super_admin
178 178 c.can_create_user_group = c.is_super_admin
179 179
180 180 c.is_delegated_admin = False
181 181
182 182 if not c.auth_user.is_default and not c.is_super_admin:
183 183 c.can_create_repo = h.HasPermissionAny('hg.create.repository')(
184 184 user=self.request.user)
185 185 repositories = c.auth_user.repositories_admin or c.can_create_repo
186 186
187 187 c.can_create_repo_group = h.HasPermissionAny('hg.repogroup.create.true')(
188 188 user=self.request.user)
189 189 repository_groups = c.auth_user.repository_groups_admin or c.can_create_repo_group
190 190
191 191 c.can_create_user_group = h.HasPermissionAny('hg.usergroup.create.true')(
192 192 user=self.request.user)
193 193 user_groups = c.auth_user.user_groups_admin or c.can_create_user_group
194 194 # delegated admin can create, or manage some objects
195 195 c.is_delegated_admin = repositories or repository_groups or user_groups
196 196 return c
197 197
198 198 def _get_template_context(self, tmpl_args, **kwargs):
199 199
200 200 local_tmpl_args = {
201 201 'defaults': {},
202 202 'errors': {},
203 203 'c': tmpl_args
204 204 }
205 205 local_tmpl_args.update(kwargs)
206 206 return local_tmpl_args
207 207
208 208 def load_default_context(self):
209 209 """
210 210 example:
211 211
212 212 def load_default_context(self):
213 213 c = self._get_local_tmpl_context()
214 214 c.custom_var = 'foobar'
215 215
216 216 return c
217 217 """
218 218 raise NotImplementedError('Needs implementation in view class')
219 219
220 220
221 221 class RepoAppView(BaseAppView):
222 222
223 223 def __init__(self, context, request):
224 224 super(RepoAppView, self).__init__(context, request)
225 225 self.db_repo = request.db_repo
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 229 self.db_repo_patterns = IssueTrackerSettingsModel(repo=self.db_repo)
230 230
231 231 def _handle_missing_requirements(self, error):
232 232 log.error(
233 233 'Requirements are missing for repository %s: %s',
234 234 self.db_repo_name, safe_unicode(error))
235 235
236 236 def _get_local_tmpl_context(self, include_app_defaults=True):
237 237 _ = self.request.translate
238 238 c = super(RepoAppView, self)._get_local_tmpl_context(
239 239 include_app_defaults=include_app_defaults)
240 240
241 241 # register common vars for this type of view
242 242 c.rhodecode_db_repo = self.db_repo
243 243 c.repo_name = self.db_repo_name
244 244 c.repository_pull_requests = self.db_repo_pull_requests
245 245 c.repository_artifacts = self.db_repo_artifacts
246 246 c.repository_is_user_following = ScmModel().is_following_repo(
247 247 self.db_repo_name, self._rhodecode_user.user_id)
248 248 self.path_filter = PathFilter(None)
249 249
250 250 c.repository_requirements_missing = {}
251 251 try:
252 252 self.rhodecode_vcs_repo = self.db_repo.scm_instance()
253 253 # NOTE(marcink):
254 254 # comparison to None since if it's an object __bool__ is expensive to
255 255 # calculate
256 256 if self.rhodecode_vcs_repo is not None:
257 257 path_perms = self.rhodecode_vcs_repo.get_path_permissions(
258 258 c.auth_user.username)
259 259 self.path_filter = PathFilter(path_perms)
260 260 except RepositoryRequirementError as e:
261 261 c.repository_requirements_missing = {'error': str(e)}
262 262 self._handle_missing_requirements(e)
263 263 self.rhodecode_vcs_repo = None
264 264
265 265 c.path_filter = self.path_filter # used by atom_feed_entry.mako
266 266
267 267 if self.rhodecode_vcs_repo is None:
268 268 # unable to fetch this repo as vcs instance, report back to user
269 269 h.flash(_(
270 270 "The repository `%(repo_name)s` cannot be loaded in filesystem. "
271 271 "Please check if it exist, or is not damaged.") %
272 272 {'repo_name': c.repo_name},
273 273 category='error', ignore_duplicate=True)
274 274 if c.repository_requirements_missing:
275 275 route = self.request.matched_route.name
276 276 if route.startswith(('edit_repo', 'repo_summary')):
277 277 # allow summary and edit repo on missing requirements
278 278 return c
279 279
280 280 raise HTTPFound(
281 281 h.route_path('repo_summary', repo_name=self.db_repo_name))
282 282
283 283 else: # redirect if we don't show missing requirements
284 284 raise HTTPFound(h.route_path('home'))
285 285
286 286 c.has_origin_repo_read_perm = False
287 287 if self.db_repo.fork:
288 288 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
289 289 'repository.write', 'repository.read', 'repository.admin')(
290 290 self.db_repo.fork.repo_name, 'summary fork link')
291 291
292 292 return c
293 293
294 294 def _get_f_path_unchecked(self, matchdict, default=None):
295 295 """
296 296 Should only be used by redirects, everything else should call _get_f_path
297 297 """
298 298 f_path = matchdict.get('f_path')
299 299 if f_path:
300 300 # fix for multiple initial slashes that causes errors for GIT
301 301 return f_path.lstrip('/')
302 302
303 303 return default
304 304
305 305 def _get_f_path(self, matchdict, default=None):
306 306 f_path_match = self._get_f_path_unchecked(matchdict, default)
307 307 return self.path_filter.assert_path_permissions(f_path_match)
308 308
309 309 def _get_general_setting(self, target_repo, settings_key, default=False):
310 310 settings_model = VcsSettingsModel(repo=target_repo)
311 311 settings = settings_model.get_general_settings()
312 312 return settings.get(settings_key, default)
313 313
314 314 def _get_repo_setting(self, target_repo, settings_key, default=False):
315 315 settings_model = VcsSettingsModel(repo=target_repo)
316 316 settings = settings_model.get_repo_settings_inherited()
317 317 return settings.get(settings_key, default)
318 318
319 319 def _get_readme_data(self, db_repo, renderer_type, commit_id=None, path='/'):
320 320 log.debug('Looking for README file at path %s', path)
321 321 if commit_id:
322 322 landing_commit_id = commit_id
323 323 else:
324 324 landing_commit = db_repo.get_landing_commit()
325 325 if isinstance(landing_commit, EmptyCommit):
326 326 return None, None
327 327 landing_commit_id = landing_commit.raw_id
328 328
329 329 cache_namespace_uid = 'cache_repo.{}'.format(db_repo.repo_id)
330 330 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
331 331 start = time.time()
332 332
333 333 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
334 334 def generate_repo_readme(repo_id, _commit_id, _repo_name, _readme_search_path, _renderer_type):
335 335 readme_data = None
336 336 readme_filename = None
337 337
338 338 commit = db_repo.get_commit(_commit_id)
339 339 log.debug("Searching for a README file at commit %s.", _commit_id)
340 340 readme_node = ReadmeFinder(_renderer_type).search(commit, path=_readme_search_path)
341 341
342 342 if readme_node:
343 343 log.debug('Found README node: %s', readme_node)
344 344 relative_urls = {
345 345 'raw': h.route_path(
346 346 'repo_file_raw', repo_name=_repo_name,
347 347 commit_id=commit.raw_id, f_path=readme_node.path),
348 348 'standard': h.route_path(
349 349 'repo_files', repo_name=_repo_name,
350 350 commit_id=commit.raw_id, f_path=readme_node.path),
351 351 }
352 352 readme_data = self._render_readme_or_none(commit, readme_node, relative_urls)
353 353 readme_filename = readme_node.unicode_path
354 354
355 355 return readme_data, readme_filename
356 356
357 357 readme_data, readme_filename = generate_repo_readme(
358 358 db_repo.repo_id, landing_commit_id, db_repo.repo_name, path, renderer_type,)
359 359 compute_time = time.time() - start
360 360 log.debug('Repo README for path %s generated and computed in %.4fs',
361 361 path, compute_time)
362 362 return readme_data, readme_filename
363 363
364 364 def _render_readme_or_none(self, commit, readme_node, relative_urls):
365 365 log.debug('Found README file `%s` rendering...', readme_node.path)
366 366 renderer = MarkupRenderer()
367 367 try:
368 368 html_source = renderer.render(
369 369 readme_node.content, filename=readme_node.path)
370 370 if relative_urls:
371 371 return relative_links(html_source, relative_urls)
372 372 return html_source
373 373 except Exception:
374 374 log.exception(
375 375 "Exception while trying to render the README")
376 376
377 377 def get_recache_flag(self):
378 378 for flag_name in ['force_recache', 'force-recache', 'no-cache']:
379 379 flag_val = self.request.GET.get(flag_name)
380 380 if str2bool(flag_val):
381 381 return True
382 382 return False
383 383
384 384
385 385 class PathFilter(object):
386 386
387 387 # Expects and instance of BasePathPermissionChecker or None
388 388 def __init__(self, permission_checker):
389 389 self.permission_checker = permission_checker
390 390
391 391 def assert_path_permissions(self, path):
392 392 if self.path_access_allowed(path):
393 393 return path
394 394 raise HTTPForbidden()
395 395
396 396 def path_access_allowed(self, path):
397 397 log.debug('Checking ACL permissions for PathFilter for `%s`', path)
398 398 if self.permission_checker:
399 399 has_access = path and self.permission_checker.has_access(path)
400 400 log.debug('ACL Permissions checker enabled, ACL Check has_access: %s', has_access)
401 401 return has_access
402 402
403 403 log.debug('ACL permissions checker not enabled, skipping...')
404 404 return True
405 405
406 406 def filter_patchset(self, patchset):
407 407 if not self.permission_checker or not patchset:
408 408 return patchset, False
409 409 had_filtered = False
410 410 filtered_patchset = []
411 411 for patch in patchset:
412 412 filename = patch.get('filename', None)
413 413 if not filename or self.permission_checker.has_access(filename):
414 414 filtered_patchset.append(patch)
415 415 else:
416 416 had_filtered = True
417 417 if had_filtered:
418 418 if isinstance(patchset, diffs.LimitedDiffContainer):
419 419 filtered_patchset = diffs.LimitedDiffContainer(patchset.diff_limit, patchset.cur_diff_size, filtered_patchset)
420 420 return filtered_patchset, True
421 421 else:
422 422 return patchset, False
423 423
424 424 def render_patchset_filtered(self, diffset, patchset, source_ref=None, target_ref=None):
425 425 filtered_patchset, has_hidden_changes = self.filter_patchset(patchset)
426 426 result = diffset.render_patchset(
427 427 filtered_patchset, source_ref=source_ref, target_ref=target_ref)
428 428 result.has_hidden_changes = has_hidden_changes
429 429 return result
430 430
431 431 def get_raw_patch(self, diff_processor):
432 432 if self.permission_checker is None:
433 433 return diff_processor.as_raw()
434 434 elif self.permission_checker.has_full_access:
435 435 return diff_processor.as_raw()
436 436 else:
437 437 return '# Repository has user-specific filters, raw patch generation is disabled.'
438 438
439 439 @property
440 440 def is_enabled(self):
441 441 return self.permission_checker is not None
442 442
443 443
444 444 class RepoGroupAppView(BaseAppView):
445 445 def __init__(self, context, request):
446 446 super(RepoGroupAppView, self).__init__(context, request)
447 447 self.db_repo_group = request.db_repo_group
448 448 self.db_repo_group_name = self.db_repo_group.group_name
449 449
450 450 def _get_local_tmpl_context(self, include_app_defaults=True):
451 451 _ = self.request.translate
452 452 c = super(RepoGroupAppView, self)._get_local_tmpl_context(
453 453 include_app_defaults=include_app_defaults)
454 454 c.repo_group = self.db_repo_group
455 455 return c
456 456
457 457 def _revoke_perms_on_yourself(self, form_result):
458 458 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
459 459 form_result['perm_updates'])
460 460 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
461 461 form_result['perm_additions'])
462 462 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
463 463 form_result['perm_deletions'])
464 464 admin_perm = 'group.admin'
465 465 if _updates and _updates[0][1] != admin_perm or \
466 466 _additions and _additions[0][1] != admin_perm or \
467 467 _deletions and _deletions[0][1] != admin_perm:
468 468 return True
469 469 return False
470 470
471 471
472 472 class UserGroupAppView(BaseAppView):
473 473 def __init__(self, context, request):
474 474 super(UserGroupAppView, self).__init__(context, request)
475 475 self.db_user_group = request.db_user_group
476 476 self.db_user_group_name = self.db_user_group.users_group_name
477 477
478 478
479 479 class UserAppView(BaseAppView):
480 480 def __init__(self, context, request):
481 481 super(UserAppView, self).__init__(context, request)
482 482 self.db_user = request.db_user
483 483 self.db_user_id = self.db_user.user_id
484 484
485 485 _ = self.request.translate
486 486 if not request.db_user_supports_default:
487 487 if self.db_user.username == User.DEFAULT_USER:
488 488 h.flash(_("Editing user `{}` is disabled.".format(
489 489 User.DEFAULT_USER)), category='warning')
490 490 raise HTTPFound(h.route_path('users'))
491 491
492 492
493 493 class DataGridAppView(object):
494 494 """
495 495 Common class to have re-usable grid rendering components
496 496 """
497 497
498 498 def _extract_ordering(self, request, column_map=None):
499 499 column_map = column_map or {}
500 500 column_index = safe_int(request.GET.get('order[0][column]'))
501 501 order_dir = request.GET.get(
502 502 'order[0][dir]', 'desc')
503 503 order_by = request.GET.get(
504 504 'columns[%s][data][sort]' % column_index, 'name_raw')
505 505
506 506 # translate datatable to DB columns
507 507 order_by = column_map.get(order_by) or order_by
508 508
509 509 search_q = request.GET.get('search[value]')
510 510 return search_q, order_by, order_dir
511 511
512 512 def _extract_chunk(self, request):
513 513 start = safe_int(request.GET.get('start'), 0)
514 514 length = safe_int(request.GET.get('length'), 25)
515 515 draw = safe_int(request.GET.get('draw'))
516 516 return draw, start, length
517 517
518 518 def _get_order_col(self, order_by, model):
519 519 if isinstance(order_by, compat.string_types):
520 520 try:
521 521 return operator.attrgetter(order_by)(model)
522 522 except AttributeError:
523 523 return None
524 524 else:
525 525 return order_by
526 526
527 527
528 528 class BaseReferencesView(RepoAppView):
529 529 """
530 530 Base for reference view for branches, tags and bookmarks.
531 531 """
532 532 def load_default_context(self):
533 533 c = self._get_local_tmpl_context()
534
535
536 534 return c
537 535
538 536 def load_refs_context(self, ref_items, partials_template):
539 537 _render = self.request.get_partial_renderer(partials_template)
540 538 pre_load = ["author", "date", "message", "parents"]
541 539
542 540 is_svn = h.is_svn(self.rhodecode_vcs_repo)
543 541 is_hg = h.is_hg(self.rhodecode_vcs_repo)
544 542
545 543 format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo)
546 544
547 545 closed_refs = {}
548 546 if is_hg:
549 547 closed_refs = self.rhodecode_vcs_repo.branches_closed
550 548
551 549 data = []
552 550 for ref_name, commit_id in ref_items:
553 551 commit = self.rhodecode_vcs_repo.get_commit(
554 552 commit_id=commit_id, pre_load=pre_load)
555 553 closed = ref_name in closed_refs
556 554
557 555 # TODO: johbo: Unify generation of reference links
558 556 use_commit_id = '/' in ref_name or is_svn
559 557
560 558 if use_commit_id:
561 559 files_url = h.route_path(
562 560 'repo_files',
563 561 repo_name=self.db_repo_name,
564 562 f_path=ref_name if is_svn else '',
565 commit_id=commit_id)
563 commit_id=commit_id,
564 _query=dict(at=ref_name)
565 )
566 566
567 567 else:
568 568 files_url = h.route_path(
569 569 'repo_files',
570 570 repo_name=self.db_repo_name,
571 571 f_path=ref_name if is_svn else '',
572 572 commit_id=ref_name,
573 _query=dict(at=ref_name))
573 _query=dict(at=ref_name)
574 )
574 575
575 576 data.append({
576 577 "name": _render('name', ref_name, files_url, closed),
577 578 "name_raw": ref_name,
578 579 "date": _render('date', commit.date),
579 580 "date_raw": datetime_to_time(commit.date),
580 581 "author": _render('author', commit.author),
581 582 "commit": _render(
582 583 'commit', commit.message, commit.raw_id, commit.idx),
583 584 "commit_raw": commit.idx,
584 585 "compare": _render(
585 586 'compare', format_ref_id(ref_name, commit.raw_id)),
586 587 })
587 588
588 589 return data
589 590
590 591
591 592 class RepoRoutePredicate(object):
592 593 def __init__(self, val, config):
593 594 self.val = val
594 595
595 596 def text(self):
596 597 return 'repo_route = %s' % self.val
597 598
598 599 phash = text
599 600
600 601 def __call__(self, info, request):
601 602 if hasattr(request, 'vcs_call'):
602 603 # skip vcs calls
603 604 return
604 605
605 606 repo_name = info['match']['repo_name']
606 607 repo_model = repo.RepoModel()
607 608
608 609 by_name_match = repo_model.get_by_repo_name(repo_name, cache=False)
609 610
610 611 def redirect_if_creating(route_info, db_repo):
611 612 skip_views = ['edit_repo_advanced_delete']
612 613 route = route_info['route']
613 614 # we should skip delete view so we can actually "remove" repositories
614 615 # if they get stuck in creating state.
615 616 if route.name in skip_views:
616 617 return
617 618
618 619 if db_repo.repo_state in [repo.Repository.STATE_PENDING]:
619 620 repo_creating_url = request.route_path(
620 621 'repo_creating', repo_name=db_repo.repo_name)
621 622 raise HTTPFound(repo_creating_url)
622 623
623 624 if by_name_match:
624 625 # register this as request object we can re-use later
625 626 request.db_repo = by_name_match
626 627 redirect_if_creating(info, by_name_match)
627 628 return True
628 629
629 630 by_id_match = repo_model.get_repo_by_id(repo_name)
630 631 if by_id_match:
631 632 request.db_repo = by_id_match
632 633 redirect_if_creating(info, by_id_match)
633 634 return True
634 635
635 636 return False
636 637
637 638
638 639 class RepoForbidArchivedRoutePredicate(object):
639 640 def __init__(self, val, config):
640 641 self.val = val
641 642
642 643 def text(self):
643 644 return 'repo_forbid_archived = %s' % self.val
644 645
645 646 phash = text
646 647
647 648 def __call__(self, info, request):
648 649 _ = request.translate
649 650 rhodecode_db_repo = request.db_repo
650 651
651 652 log.debug(
652 653 '%s checking if archived flag for repo for %s',
653 654 self.__class__.__name__, rhodecode_db_repo.repo_name)
654 655
655 656 if rhodecode_db_repo.archived:
656 657 log.warning('Current view is not supported for archived repo:%s',
657 658 rhodecode_db_repo.repo_name)
658 659
659 660 h.flash(
660 661 h.literal(_('Action not supported for archived repository.')),
661 662 category='warning')
662 663 summary_url = request.route_path(
663 664 'repo_summary', repo_name=rhodecode_db_repo.repo_name)
664 665 raise HTTPFound(summary_url)
665 666 return True
666 667
667 668
668 669 class RepoTypeRoutePredicate(object):
669 670 def __init__(self, val, config):
670 671 self.val = val or ['hg', 'git', 'svn']
671 672
672 673 def text(self):
673 674 return 'repo_accepted_type = %s' % self.val
674 675
675 676 phash = text
676 677
677 678 def __call__(self, info, request):
678 679 if hasattr(request, 'vcs_call'):
679 680 # skip vcs calls
680 681 return
681 682
682 683 rhodecode_db_repo = request.db_repo
683 684
684 685 log.debug(
685 686 '%s checking repo type for %s in %s',
686 687 self.__class__.__name__, rhodecode_db_repo.repo_type, self.val)
687 688
688 689 if rhodecode_db_repo.repo_type in self.val:
689 690 return True
690 691 else:
691 692 log.warning('Current view is not supported for repo type:%s',
692 693 rhodecode_db_repo.repo_type)
693 694 return False
694 695
695 696
696 697 class RepoGroupRoutePredicate(object):
697 698 def __init__(self, val, config):
698 699 self.val = val
699 700
700 701 def text(self):
701 702 return 'repo_group_route = %s' % self.val
702 703
703 704 phash = text
704 705
705 706 def __call__(self, info, request):
706 707 if hasattr(request, 'vcs_call'):
707 708 # skip vcs calls
708 709 return
709 710
710 711 repo_group_name = info['match']['repo_group_name']
711 712 repo_group_model = repo_group.RepoGroupModel()
712 713 by_name_match = repo_group_model.get_by_group_name(repo_group_name, cache=False)
713 714
714 715 if by_name_match:
715 716 # register this as request object we can re-use later
716 717 request.db_repo_group = by_name_match
717 718 return True
718 719
719 720 return False
720 721
721 722
722 723 class UserGroupRoutePredicate(object):
723 724 def __init__(self, val, config):
724 725 self.val = val
725 726
726 727 def text(self):
727 728 return 'user_group_route = %s' % self.val
728 729
729 730 phash = text
730 731
731 732 def __call__(self, info, request):
732 733 if hasattr(request, 'vcs_call'):
733 734 # skip vcs calls
734 735 return
735 736
736 737 user_group_id = info['match']['user_group_id']
737 738 user_group_model = user_group.UserGroup()
738 739 by_id_match = user_group_model.get(user_group_id, cache=False)
739 740
740 741 if by_id_match:
741 742 # register this as request object we can re-use later
742 743 request.db_user_group = by_id_match
743 744 return True
744 745
745 746 return False
746 747
747 748
748 749 class UserRoutePredicateBase(object):
749 750 supports_default = None
750 751
751 752 def __init__(self, val, config):
752 753 self.val = val
753 754
754 755 def text(self):
755 756 raise NotImplementedError()
756 757
757 758 def __call__(self, info, request):
758 759 if hasattr(request, 'vcs_call'):
759 760 # skip vcs calls
760 761 return
761 762
762 763 user_id = info['match']['user_id']
763 764 user_model = user.User()
764 765 by_id_match = user_model.get(user_id, cache=False)
765 766
766 767 if by_id_match:
767 768 # register this as request object we can re-use later
768 769 request.db_user = by_id_match
769 770 request.db_user_supports_default = self.supports_default
770 771 return True
771 772
772 773 return False
773 774
774 775
775 776 class UserRoutePredicate(UserRoutePredicateBase):
776 777 supports_default = False
777 778
778 779 def text(self):
779 780 return 'user_route = %s' % self.val
780 781
781 782 phash = text
782 783
783 784
784 785 class UserRouteWithDefaultPredicate(UserRoutePredicateBase):
785 786 supports_default = True
786 787
787 788 def text(self):
788 789 return 'user_with_default_route = %s' % self.val
789 790
790 791 phash = text
791 792
792 793
793 794 def includeme(config):
794 795 config.add_route_predicate(
795 796 'repo_route', RepoRoutePredicate)
796 797 config.add_route_predicate(
797 798 'repo_accepted_types', RepoTypeRoutePredicate)
798 799 config.add_route_predicate(
799 800 'repo_forbid_when_archived', RepoForbidArchivedRoutePredicate)
800 801 config.add_route_predicate(
801 802 'repo_group_route', RepoGroupRoutePredicate)
802 803 config.add_route_predicate(
803 804 'user_group_route', UserGroupRoutePredicate)
804 805 config.add_route_predicate(
805 806 'user_route_with_default', UserRouteWithDefaultPredicate)
806 807 config.add_route_predicate(
807 808 'user_route', UserRoutePredicate)
@@ -1,402 +1,419 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 import os
22 22 import logging
23 23 import datetime
24 24
25 25 from pyramid.view import view_config
26 26 from pyramid.renderers import render_to_response
27 27 from rhodecode.apps._base import BaseAppView
28 28 from rhodecode.lib.celerylib import run_task, tasks
29 29 from rhodecode.lib.utils2 import AttributeDict
30 30 from rhodecode.model.db import User
31 31 from rhodecode.model.notification import EmailNotificationModel
32 32
33 33 log = logging.getLogger(__name__)
34 34
35 35
36 36 class DebugStyleView(BaseAppView):
37 37 def load_default_context(self):
38 38 c = self._get_local_tmpl_context()
39 39
40 40 return c
41 41
42 42 @view_config(
43 43 route_name='debug_style_home', request_method='GET',
44 44 renderer=None)
45 45 def index(self):
46 46 c = self.load_default_context()
47 47 c.active = 'index'
48 48
49 49 return render_to_response(
50 50 'debug_style/index.html', self._get_template_context(c),
51 51 request=self.request)
52 52
53 53 @view_config(
54 54 route_name='debug_style_email', request_method='GET',
55 55 renderer=None)
56 56 @view_config(
57 57 route_name='debug_style_email_plain_rendered', request_method='GET',
58 58 renderer=None)
59 59 def render_email(self):
60 60 c = self.load_default_context()
61 61 email_id = self.request.matchdict['email_id']
62 62 c.active = 'emails'
63 63
64 64 pr = AttributeDict(
65 65 pull_request_id=123,
66 66 title='digital_ocean: fix redis, elastic search start on boot, '
67 67 'fix fd limits on supervisor, set postgres 11 version',
68 68 description='''
69 69 Check if we should use full-topic or mini-topic.
70 70
71 71 - full topic produces some problems with merge states etc
72 72 - server-mini-topic needs probably tweeks.
73 73 ''',
74 74 repo_name='foobar',
75 75 source_ref_parts=AttributeDict(type='branch', name='fix-ticket-2000'),
76 76 target_ref_parts=AttributeDict(type='branch', name='master'),
77 77 )
78 78 target_repo = AttributeDict(repo_name='repo_group/target_repo')
79 79 source_repo = AttributeDict(repo_name='repo_group/source_repo')
80 80 user = User.get_by_username(self.request.GET.get('user')) or self._rhodecode_db_user
81 81 # file/commit changes for PR update
82 82 commit_changes = AttributeDict({
83 83 'added': ['aaaaaaabbbbb', 'cccccccddddddd'],
84 84 'removed': ['eeeeeeeeeee'],
85 85 })
86 86 file_changes = AttributeDict({
87 87 'added': ['a/file1.md', 'file2.py'],
88 88 'modified': ['b/modified_file.rst'],
89 89 'removed': ['.idea'],
90 90 })
91 91
92 92 exc_traceback = {
93 93 'exc_utc_date': '2020-03-26T12:54:50.683281',
94 94 'exc_id': 139638856342656,
95 95 'exc_timestamp': '1585227290.683288',
96 96 'version': 'v1',
97 97 'exc_message': 'Traceback (most recent call last):\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/tweens.py", line 41, in excview_tween\n response = handler(request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/router.py", line 148, in handle_request\n registry, request, context, context_iface, view_name\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/view.py", line 667, in _call_view\n response = view_callable(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/config/views.py", line 188, in attr_view\n return view(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/config/views.py", line 214, in predicate_wrapper\n return view(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/viewderivers.py", line 401, in viewresult_to_response\n result = view(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/viewderivers.py", line 132, in _class_view\n response = getattr(inst, attr)()\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/apps/debug_style/views.py", line 355, in render_email\n template_type, **email_kwargs.get(email_id, {}))\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/model/notification.py", line 402, in render_email\n body = email_template.render(None, **_kwargs)\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/lib/partial_renderer.py", line 95, in render\n return self._render_with_exc(tmpl, args, kwargs)\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/lib/partial_renderer.py", line 79, in _render_with_exc\n return render_func.render(*args, **kwargs)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/template.py", line 476, in render\n return runtime._render(self, self.callable_, args, data)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/runtime.py", line 883, in _render\n **_kwargs_for_callable(callable_, data)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/runtime.py", line 920, in _render_context\n _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/runtime.py", line 947, in _exec_template\n callable_(context, *args, **kwargs)\n File "rhodecode_templates_email_templates_base_mako", line 63, in render_body\n File "rhodecode_templates_email_templates_exception_tracker_mako", line 43, in render_body\nAttributeError: \'str\' object has no attribute \'get\'\n',
98 98 'exc_type': 'AttributeError'
99 99 }
100 100 email_kwargs = {
101 101 'test': {},
102 102 'message': {
103 103 'body': 'message body !'
104 104 },
105 105 'email_test': {
106 106 'user': user,
107 107 'date': datetime.datetime.now(),
108 108 },
109 109 'exception': {
110 110 'email_prefix': '[RHODECODE ERROR]',
111 111 'exc_id': exc_traceback['exc_id'],
112 112 'exc_url': 'http://server-url/{}'.format(exc_traceback['exc_id']),
113 113 'exc_type_name': 'NameError',
114 114 'exc_traceback': exc_traceback,
115 115 },
116 116 'password_reset': {
117 117 'password_reset_url': 'http://example.com/reset-rhodecode-password/token',
118 118
119 119 'user': user,
120 120 'date': datetime.datetime.now(),
121 121 'email': 'test@rhodecode.com',
122 122 'first_admin_email': User.get_first_super_admin().email
123 123 },
124 124 'password_reset_confirmation': {
125 125 'new_password': 'new-password-example',
126 126 'user': user,
127 127 'date': datetime.datetime.now(),
128 128 'email': 'test@rhodecode.com',
129 129 'first_admin_email': User.get_first_super_admin().email
130 130 },
131 131 'registration': {
132 132 'user': user,
133 133 'date': datetime.datetime.now(),
134 134 },
135 135
136 136 'pull_request_comment': {
137 137 'user': user,
138 138
139 139 'status_change': None,
140 140 'status_change_type': None,
141 141
142 142 'pull_request': pr,
143 143 'pull_request_commits': [],
144 144
145 145 'pull_request_target_repo': target_repo,
146 146 'pull_request_target_repo_url': 'http://target-repo/url',
147 147
148 148 'pull_request_source_repo': source_repo,
149 149 'pull_request_source_repo_url': 'http://source-repo/url',
150 150
151 151 'pull_request_url': 'http://localhost/pr1',
152 152 'pr_comment_url': 'http://comment-url',
153 153 'pr_comment_reply_url': 'http://comment-url#reply',
154 154
155 155 'comment_file': None,
156 156 'comment_line': None,
157 157 'comment_type': 'note',
158 158 'comment_body': 'This is my comment body. *I like !*',
159 159 'comment_id': 2048,
160 160 'renderer_type': 'markdown',
161 161 'mention': True,
162 162
163 163 },
164 164 'pull_request_comment+status': {
165 165 'user': user,
166 166
167 167 'status_change': 'approved',
168 168 'status_change_type': 'approved',
169 169
170 170 'pull_request': pr,
171 171 'pull_request_commits': [],
172 172
173 173 'pull_request_target_repo': target_repo,
174 174 'pull_request_target_repo_url': 'http://target-repo/url',
175 175
176 176 'pull_request_source_repo': source_repo,
177 177 'pull_request_source_repo_url': 'http://source-repo/url',
178 178
179 179 'pull_request_url': 'http://localhost/pr1',
180 180 'pr_comment_url': 'http://comment-url',
181 181 'pr_comment_reply_url': 'http://comment-url#reply',
182 182
183 183 'comment_type': 'todo',
184 184 'comment_file': None,
185 185 'comment_line': None,
186 186 'comment_body': '''
187 187 I think something like this would be better
188 188
189 189 ```py
190 // markdown renderer
190 191
191 192 def db():
192 193 global connection
193 194 return connection
194 195
195 196 ```
196 197
197 198 ''',
198 199 'comment_id': 2048,
199 200 'renderer_type': 'markdown',
200 201 'mention': True,
201 202
202 203 },
203 204 'pull_request_comment+file': {
204 205 'user': user,
205 206
206 207 'status_change': None,
207 208 'status_change_type': None,
208 209
209 210 'pull_request': pr,
210 211 'pull_request_commits': [],
211 212
212 213 'pull_request_target_repo': target_repo,
213 214 'pull_request_target_repo_url': 'http://target-repo/url',
214 215
215 216 'pull_request_source_repo': source_repo,
216 217 'pull_request_source_repo_url': 'http://source-repo/url',
217 218
218 219 'pull_request_url': 'http://localhost/pr1',
219 220
220 221 'pr_comment_url': 'http://comment-url',
221 222 'pr_comment_reply_url': 'http://comment-url#reply',
222 223
223 224 'comment_file': 'rhodecode/model/get_flow_commits',
224 225 'comment_line': 'o1210',
225 226 'comment_type': 'todo',
226 227 'comment_body': '''
227 228 I like this !
228 229
229 But please check this code::
230
231 def main():
232 print 'ok'
230 But please check this code
231
232 .. code-block:: javascript
233
234 // THIS IS RST CODE
235
236 this.createResolutionComment = function(commentId) {
237 // hide the trigger text
238 $('#resolve-comment-{0}'.format(commentId)).hide();
239
240 var comment = $('#comment-'+commentId);
241 var commentData = comment.data();
242 if (commentData.commentInline) {
243 this.createComment(comment, commentId)
244 } else {
245 Rhodecode.comments.createGeneralComment('general', "$placeholder", commentId)
246 }
247
248 return false;
249 };
233 250
234 251 This should work better !
235 252 ''',
236 253 'comment_id': 2048,
237 254 'renderer_type': 'rst',
238 255 'mention': True,
239 256
240 257 },
241 258
242 259 'pull_request_update': {
243 260 'updating_user': user,
244 261
245 262 'status_change': None,
246 263 'status_change_type': None,
247 264
248 265 'pull_request': pr,
249 266 'pull_request_commits': [],
250 267
251 268 'pull_request_target_repo': target_repo,
252 269 'pull_request_target_repo_url': 'http://target-repo/url',
253 270
254 271 'pull_request_source_repo': source_repo,
255 272 'pull_request_source_repo_url': 'http://source-repo/url',
256 273
257 274 'pull_request_url': 'http://localhost/pr1',
258 275
259 276 # update comment links
260 277 'pr_comment_url': 'http://comment-url',
261 278 'pr_comment_reply_url': 'http://comment-url#reply',
262 279 'ancestor_commit_id': 'f39bd443',
263 280 'added_commits': commit_changes.added,
264 281 'removed_commits': commit_changes.removed,
265 282 'changed_files': (file_changes.added + file_changes.modified + file_changes.removed),
266 283 'added_files': file_changes.added,
267 284 'modified_files': file_changes.modified,
268 285 'removed_files': file_changes.removed,
269 286 },
270 287
271 288 'cs_comment': {
272 289 'user': user,
273 290 'commit': AttributeDict(idx=123, raw_id='a'*40, message='Commit message'),
274 291 'status_change': None,
275 292 'status_change_type': None,
276 293
277 294 'commit_target_repo_url': 'http://foo.example.com/#comment1',
278 295 'repo_name': 'test-repo',
279 296 'comment_type': 'note',
280 297 'comment_file': None,
281 298 'comment_line': None,
282 299 'commit_comment_url': 'http://comment-url',
283 300 'commit_comment_reply_url': 'http://comment-url#reply',
284 301 'comment_body': 'This is my comment body. *I like !*',
285 302 'comment_id': 2048,
286 303 'renderer_type': 'markdown',
287 304 'mention': True,
288 305 },
289 306 'cs_comment+status': {
290 307 'user': user,
291 308 'commit': AttributeDict(idx=123, raw_id='a' * 40, message='Commit message'),
292 309 'status_change': 'approved',
293 310 'status_change_type': 'approved',
294 311
295 312 'commit_target_repo_url': 'http://foo.example.com/#comment1',
296 313 'repo_name': 'test-repo',
297 314 'comment_type': 'note',
298 315 'comment_file': None,
299 316 'comment_line': None,
300 317 'commit_comment_url': 'http://comment-url',
301 318 'commit_comment_reply_url': 'http://comment-url#reply',
302 319 'comment_body': '''
303 320 Hello **world**
304 321
305 322 This is a multiline comment :)
306 323
307 324 - list
308 325 - list2
309 326 ''',
310 327 'comment_id': 2048,
311 328 'renderer_type': 'markdown',
312 329 'mention': True,
313 330 },
314 331 'cs_comment+file': {
315 332 'user': user,
316 333 'commit': AttributeDict(idx=123, raw_id='a' * 40, message='Commit message'),
317 334 'status_change': None,
318 335 'status_change_type': None,
319 336
320 337 'commit_target_repo_url': 'http://foo.example.com/#comment1',
321 338 'repo_name': 'test-repo',
322 339
323 340 'comment_type': 'note',
324 341 'comment_file': 'test-file.py',
325 342 'comment_line': 'n100',
326 343
327 344 'commit_comment_url': 'http://comment-url',
328 345 'commit_comment_reply_url': 'http://comment-url#reply',
329 346 'comment_body': 'This is my comment body. *I like !*',
330 347 'comment_id': 2048,
331 348 'renderer_type': 'markdown',
332 349 'mention': True,
333 350 },
334 351
335 352 'pull_request': {
336 353 'user': user,
337 354 'pull_request': pr,
338 355 'pull_request_commits': [
339 356 ('472d1df03bf7206e278fcedc6ac92b46b01c4e21', '''\
340 357 my-account: moved email closer to profile as it's similar data just moved outside.
341 358 '''),
342 359 ('cbfa3061b6de2696c7161ed15ba5c6a0045f90a7', '''\
343 360 users: description edit fixes
344 361
345 362 - tests
346 363 - added metatags info
347 364 '''),
348 365 ],
349 366
350 367 'pull_request_target_repo': target_repo,
351 368 'pull_request_target_repo_url': 'http://target-repo/url',
352 369
353 370 'pull_request_source_repo': source_repo,
354 371 'pull_request_source_repo_url': 'http://source-repo/url',
355 372
356 373 'pull_request_url': 'http://code.rhodecode.com/_pull-request/123',
357 374 }
358 375
359 376 }
360 377
361 378 template_type = email_id.split('+')[0]
362 379 (c.subject, c.headers, c.email_body,
363 380 c.email_body_plaintext) = EmailNotificationModel().render_email(
364 381 template_type, **email_kwargs.get(email_id, {}))
365 382
366 383 test_email = self.request.GET.get('email')
367 384 if test_email:
368 385 recipients = [test_email]
369 386 run_task(tasks.send_email, recipients, c.subject,
370 387 c.email_body_plaintext, c.email_body)
371 388
372 389 if self.request.matched_route.name == 'debug_style_email_plain_rendered':
373 390 template = 'debug_style/email_plain_rendered.mako'
374 391 else:
375 392 template = 'debug_style/email.mako'
376 393 return render_to_response(
377 394 template, self._get_template_context(c),
378 395 request=self.request)
379 396
380 397 @view_config(
381 398 route_name='debug_style_template', request_method='GET',
382 399 renderer=None)
383 400 def template(self):
384 401 t_path = self.request.matchdict['t_path']
385 402 c = self.load_default_context()
386 403 c.active = os.path.splitext(t_path)[0]
387 404 c.came_from = ''
388 405 c.email_types = {
389 406 'cs_comment+file': {},
390 407 'cs_comment+status': {},
391 408
392 409 'pull_request_comment+file': {},
393 410 'pull_request_comment+status': {},
394 411
395 412 'pull_request_update': {},
396 413 }
397 414 c.email_types.update(EmailNotificationModel.email_types)
398 415
399 416 return render_to_response(
400 417 'debug_style/' + t_path, self._get_template_context(c),
401 418 request=self.request)
402 419
@@ -1,179 +1,179 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21
22 22 import pytest
23 23
24 24 import rhodecode
25 25 from rhodecode.model.db import Repository, RepoGroup, User
26 26 from rhodecode.model.meta import Session
27 27 from rhodecode.model.repo import RepoModel
28 28 from rhodecode.model.repo_group import RepoGroupModel
29 29 from rhodecode.model.settings import SettingsModel
30 30 from rhodecode.tests import TestController
31 31 from rhodecode.tests.fixture import Fixture
32 32 from rhodecode.lib import helpers as h
33 33
34 34 fixture = Fixture()
35 35
36 36
37 37 def route_path(name, **kwargs):
38 38 return {
39 39 'home': '/',
40 40 'main_page_repos_data': '/_home_repos',
41 41 'main_page_repo_groups_data': '/_home_repo_groups',
42 42 'repo_group_home': '/{repo_group_name}'
43 43 }[name].format(**kwargs)
44 44
45 45
46 46 class TestHomeController(TestController):
47 47
48 48 def test_index(self):
49 49 self.log_user()
50 50 response = self.app.get(route_path('home'))
51 51 # if global permission is set
52 52 response.mustcontain('New Repository')
53 53
54 54 def test_index_grid_repos(self, xhr_header):
55 55 self.log_user()
56 56 response = self.app.get(route_path('main_page_repos_data'), extra_environ=xhr_header)
57 57 # search for objects inside the JavaScript JSON
58 58 for obj in Repository.getAll():
59 59 response.mustcontain('<a href=\\"/{}\\">'.format(obj.repo_name))
60 60
61 61 def test_index_grid_repo_groups(self, xhr_header):
62 62 self.log_user()
63 63 response = self.app.get(route_path('main_page_repo_groups_data'),
64 64 extra_environ=xhr_header,)
65 65
66 66 # search for objects inside the JavaScript JSON
67 67 for obj in RepoGroup.getAll():
68 68 response.mustcontain('<a href=\\"/{}\\">'.format(obj.group_name))
69 69
70 70 def test_index_grid_repo_groups_without_access(self, xhr_header, user_util):
71 71 user = user_util.create_user(password='qweqwe')
72 72 group_ok = user_util.create_repo_group(owner=user)
73 73 group_id_ok = group_ok.group_id
74 74
75 75 group_forbidden = user_util.create_repo_group(owner=User.get_first_super_admin())
76 76 group_id_forbidden = group_forbidden.group_id
77 77
78 78 user_util.grant_user_permission_to_repo_group(group_forbidden, user, 'group.none')
79 79 self.log_user(user.username, 'qweqwe')
80 80
81 81 self.app.get(route_path('main_page_repo_groups_data'),
82 82 extra_environ=xhr_header,
83 83 params={'repo_group_id': group_id_ok}, status=200)
84 84
85 85 self.app.get(route_path('main_page_repo_groups_data'),
86 86 extra_environ=xhr_header,
87 87 params={'repo_group_id': group_id_forbidden}, status=404)
88 88
89 89 def test_index_contains_statics_with_ver(self):
90 90 from rhodecode.lib.base import calculate_version_hash
91 91
92 92 self.log_user()
93 93 response = self.app.get(route_path('home'))
94 94
95 95 rhodecode_version_hash = calculate_version_hash(
96 96 {'beaker.session.secret': 'test-rc-uytcxaz'})
97 97 response.mustcontain('style.css?ver={0}'.format(rhodecode_version_hash))
98 98 response.mustcontain('scripts.min.js?ver={0}'.format(rhodecode_version_hash))
99 99
100 100 def test_index_contains_backend_specific_details(self, backend, xhr_header):
101 101 self.log_user()
102 102 response = self.app.get(route_path('main_page_repos_data'), extra_environ=xhr_header)
103 103 tip = backend.repo.get_commit().raw_id
104 104
105 105 # html in javascript variable:
106 106 response.mustcontain(r'<i class=\"icon-%s\"' % (backend.alias, ))
107 107 response.mustcontain(r'href=\"/%s\"' % (backend.repo_name, ))
108 108
109 109 response.mustcontain("""/%s/changeset/%s""" % (backend.repo_name, tip))
110 110 response.mustcontain("""Added a symlink""")
111 111
112 112 def test_index_with_anonymous_access_disabled(self):
113 113 with fixture.anon_access(False):
114 114 response = self.app.get(route_path('home'), status=302)
115 115 assert 'login' in response.location
116 116
117 117 def test_index_page_on_groups_with_wrong_group_id(self, autologin_user, xhr_header):
118 118 group_id = 918123
119 119 self.app.get(
120 120 route_path('main_page_repo_groups_data'),
121 121 params={'repo_group_id': group_id},
122 122 status=404, extra_environ=xhr_header)
123 123
124 124 def test_index_page_on_groups(self, autologin_user, user_util, xhr_header):
125 125 gr = user_util.create_repo_group()
126 126 repo = user_util.create_repo(parent=gr)
127 127 repo_name = repo.repo_name
128 128 group_id = gr.group_id
129 129
130 130 response = self.app.get(route_path(
131 131 'repo_group_home', repo_group_name=gr.group_name))
132 132 response.mustcontain('d.repo_group_id = {}'.format(group_id))
133 133
134 134 response = self.app.get(
135 135 route_path('main_page_repos_data'),
136 136 params={'repo_group_id': group_id},
137 137 extra_environ=xhr_header,)
138 138 response.mustcontain(repo_name)
139 139
140 140 def test_index_page_on_group_with_trailing_slash(self, autologin_user, user_util, xhr_header):
141 141 gr = user_util.create_repo_group()
142 142 repo = user_util.create_repo(parent=gr)
143 143 repo_name = repo.repo_name
144 144 group_id = gr.group_id
145 145
146 146 response = self.app.get(route_path(
147 147 'repo_group_home', repo_group_name=gr.group_name+'/'))
148 148 response.mustcontain('d.repo_group_id = {}'.format(group_id))
149 149
150 150 response = self.app.get(
151 151 route_path('main_page_repos_data'),
152 152 params={'repo_group_id': group_id},
153 153 extra_environ=xhr_header, )
154 154 response.mustcontain(repo_name)
155 155
156 156 @pytest.mark.parametrize("name, state", [
157 157 ('Disabled', False),
158 158 ('Enabled', True),
159 159 ])
160 160 def test_index_show_version(self, autologin_user, name, state):
161 version_string = 'RhodeCode Enterprise %s' % rhodecode.__version__
161 version_string = 'RhodeCode %s' % rhodecode.__version__
162 162
163 163 sett = SettingsModel().create_or_update_setting(
164 164 'show_version', state, 'bool')
165 165 Session().add(sett)
166 166 Session().commit()
167 167 SettingsModel().invalidate_settings_cache()
168 168
169 169 response = self.app.get(route_path('home'))
170 170 if state is True:
171 171 response.mustcontain(version_string)
172 172 if state is False:
173 173 response.mustcontain(no=[version_string])
174 174
175 175 def test_logout_form_contains_csrf(self, autologin_user, csrf_token):
176 176 response = self.app.get(route_path('home'))
177 177 assert_response = response.assert_response()
178 178 element = assert_response.get_element('.logout [name=csrf_token]')
179 179 assert element.value == csrf_token
@@ -1,1070 +1,1070 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 import os
22 22
23 23 import mock
24 24 import pytest
25 25
26 26 from rhodecode.apps.repository.tests.test_repo_compare import ComparePage
27 27 from rhodecode.apps.repository.views.repo_files import RepoFilesView
28 28 from rhodecode.lib import helpers as h
29 29 from rhodecode.lib.compat import OrderedDict
30 30 from rhodecode.lib.ext_json import json
31 31 from rhodecode.lib.vcs import nodes
32 32
33 33 from rhodecode.lib.vcs.conf import settings
34 34 from rhodecode.tests import assert_session_flash
35 35 from rhodecode.tests.fixture import Fixture
36 36 from rhodecode.model.db import Session
37 37
38 38 fixture = Fixture()
39 39
40 40
41 41 def get_node_history(backend_type):
42 42 return {
43 43 'hg': json.loads(fixture.load_resource('hg_node_history_response.json')),
44 44 'git': json.loads(fixture.load_resource('git_node_history_response.json')),
45 45 'svn': json.loads(fixture.load_resource('svn_node_history_response.json')),
46 46 }[backend_type]
47 47
48 48
49 49 def route_path(name, params=None, **kwargs):
50 50 import urllib
51 51
52 52 base_url = {
53 53 'repo_summary': '/{repo_name}',
54 54 'repo_archivefile': '/{repo_name}/archive/{fname}',
55 55 'repo_files_diff': '/{repo_name}/diff/{f_path}',
56 56 'repo_files_diff_2way_redirect': '/{repo_name}/diff-2way/{f_path}',
57 57 'repo_files': '/{repo_name}/files/{commit_id}/{f_path}',
58 58 'repo_files:default_path': '/{repo_name}/files/{commit_id}/',
59 59 'repo_files:default_commit': '/{repo_name}/files',
60 60 'repo_files:rendered': '/{repo_name}/render/{commit_id}/{f_path}',
61 61 'repo_files:annotated': '/{repo_name}/annotate/{commit_id}/{f_path}',
62 62 'repo_files:annotated_previous': '/{repo_name}/annotate-previous/{commit_id}/{f_path}',
63 63 'repo_files_nodelist': '/{repo_name}/nodelist/{commit_id}/{f_path}',
64 64 'repo_file_raw': '/{repo_name}/raw/{commit_id}/{f_path}',
65 65 'repo_file_download': '/{repo_name}/download/{commit_id}/{f_path}',
66 66 'repo_file_history': '/{repo_name}/history/{commit_id}/{f_path}',
67 67 'repo_file_authors': '/{repo_name}/authors/{commit_id}/{f_path}',
68 68 'repo_files_remove_file': '/{repo_name}/remove_file/{commit_id}/{f_path}',
69 69 'repo_files_delete_file': '/{repo_name}/delete_file/{commit_id}/{f_path}',
70 70 'repo_files_edit_file': '/{repo_name}/edit_file/{commit_id}/{f_path}',
71 71 'repo_files_update_file': '/{repo_name}/update_file/{commit_id}/{f_path}',
72 72 'repo_files_add_file': '/{repo_name}/add_file/{commit_id}/{f_path}',
73 73 'repo_files_create_file': '/{repo_name}/create_file/{commit_id}/{f_path}',
74 74 'repo_nodetree_full': '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
75 75 'repo_nodetree_full:default_path': '/{repo_name}/nodetree_full/{commit_id}/',
76 76 }[name].format(**kwargs)
77 77
78 78 if params:
79 79 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
80 80 return base_url
81 81
82 82
83 83 def assert_files_in_response(response, files, params):
84 84 template = (
85 85 'href="/%(repo_name)s/files/%(commit_id)s/%(name)s"')
86 86 _assert_items_in_response(response, files, template, params)
87 87
88 88
89 89 def assert_dirs_in_response(response, dirs, params):
90 90 template = (
91 91 'href="/%(repo_name)s/files/%(commit_id)s/%(name)s"')
92 92 _assert_items_in_response(response, dirs, template, params)
93 93
94 94
95 95 def _assert_items_in_response(response, items, template, params):
96 96 for item in items:
97 97 item_params = {'name': item}
98 98 item_params.update(params)
99 99 response.mustcontain(template % item_params)
100 100
101 101
102 102 def assert_timeago_in_response(response, items, params):
103 103 for item in items:
104 104 response.mustcontain(h.age_component(params['date']))
105 105
106 106
107 107 @pytest.mark.usefixtures("app")
108 108 class TestFilesViews(object):
109 109
110 110 def test_show_files(self, backend):
111 111 response = self.app.get(
112 112 route_path('repo_files',
113 113 repo_name=backend.repo_name,
114 114 commit_id='tip', f_path='/'))
115 115 commit = backend.repo.get_commit()
116 116
117 117 params = {
118 118 'repo_name': backend.repo_name,
119 119 'commit_id': commit.raw_id,
120 120 'date': commit.date
121 121 }
122 122 assert_dirs_in_response(response, ['docs', 'vcs'], params)
123 123 files = [
124 124 '.gitignore',
125 125 '.hgignore',
126 126 '.hgtags',
127 127 # TODO: missing in Git
128 128 # '.travis.yml',
129 129 'MANIFEST.in',
130 130 'README.rst',
131 131 # TODO: File is missing in svn repository
132 132 # 'run_test_and_report.sh',
133 133 'setup.cfg',
134 134 'setup.py',
135 135 'test_and_report.sh',
136 136 'tox.ini',
137 137 ]
138 138 assert_files_in_response(response, files, params)
139 139 assert_timeago_in_response(response, files, params)
140 140
141 141 def test_show_files_links_submodules_with_absolute_url(self, backend_hg):
142 142 repo = backend_hg['subrepos']
143 143 response = self.app.get(
144 144 route_path('repo_files',
145 145 repo_name=repo.repo_name,
146 146 commit_id='tip', f_path='/'))
147 147 assert_response = response.assert_response()
148 148 assert_response.contains_one_link(
149 149 'absolute-path @ 000000000000', 'http://example.com/absolute-path')
150 150
151 151 def test_show_files_links_submodules_with_absolute_url_subpaths(
152 152 self, backend_hg):
153 153 repo = backend_hg['subrepos']
154 154 response = self.app.get(
155 155 route_path('repo_files',
156 156 repo_name=repo.repo_name,
157 157 commit_id='tip', f_path='/'))
158 158 assert_response = response.assert_response()
159 159 assert_response.contains_one_link(
160 160 'subpaths-path @ 000000000000',
161 161 'http://sub-base.example.com/subpaths-path')
162 162
163 163 @pytest.mark.xfail_backends("svn", reason="Depends on branch support")
164 164 def test_files_menu(self, backend):
165 165 new_branch = "temp_branch_name"
166 166 commits = [
167 167 {'message': 'a'},
168 168 {'message': 'b', 'branch': new_branch}
169 169 ]
170 170 backend.create_repo(commits)
171 171 backend.repo.landing_rev = "branch:%s" % new_branch
172 172 Session().commit()
173 173
174 174 # get response based on tip and not new commit
175 175 response = self.app.get(
176 176 route_path('repo_files',
177 177 repo_name=backend.repo_name,
178 178 commit_id='tip', f_path='/'))
179 179
180 180 # make sure Files menu url is not tip but new commit
181 landing_rev = backend.repo.landing_rev[1]
181 landing_rev = backend.repo.landing_ref_name
182 182 files_url = route_path('repo_files:default_path',
183 183 repo_name=backend.repo_name,
184 commit_id=landing_rev)
184 commit_id=landing_rev, params={'at': landing_rev})
185 185
186 186 assert landing_rev != 'tip'
187 187 response.mustcontain(
188 188 '<li class="active"><a class="menulink" href="%s">' % files_url)
189 189
190 190 def test_show_files_commit(self, backend):
191 191 commit = backend.repo.get_commit(commit_idx=32)
192 192
193 193 response = self.app.get(
194 194 route_path('repo_files',
195 195 repo_name=backend.repo_name,
196 196 commit_id=commit.raw_id, f_path='/'))
197 197
198 198 dirs = ['docs', 'tests']
199 199 files = ['README.rst']
200 200 params = {
201 201 'repo_name': backend.repo_name,
202 202 'commit_id': commit.raw_id,
203 203 }
204 204 assert_dirs_in_response(response, dirs, params)
205 205 assert_files_in_response(response, files, params)
206 206
207 207 def test_show_files_different_branch(self, backend):
208 208 branches = dict(
209 209 hg=(150, ['git']),
210 210 # TODO: Git test repository does not contain other branches
211 211 git=(633, ['master']),
212 212 # TODO: Branch support in Subversion
213 213 svn=(150, [])
214 214 )
215 215 idx, branches = branches[backend.alias]
216 216 commit = backend.repo.get_commit(commit_idx=idx)
217 217 response = self.app.get(
218 218 route_path('repo_files',
219 219 repo_name=backend.repo_name,
220 220 commit_id=commit.raw_id, f_path='/'))
221 221
222 222 assert_response = response.assert_response()
223 223 for branch in branches:
224 224 assert_response.element_contains('.tags .branchtag', branch)
225 225
226 226 def test_show_files_paging(self, backend):
227 227 repo = backend.repo
228 228 indexes = [73, 92, 109, 1, 0]
229 229 idx_map = [(rev, repo.get_commit(commit_idx=rev).raw_id)
230 230 for rev in indexes]
231 231
232 232 for idx in idx_map:
233 233 response = self.app.get(
234 234 route_path('repo_files',
235 235 repo_name=backend.repo_name,
236 236 commit_id=idx[1], f_path='/'))
237 237
238 238 response.mustcontain("""r%s:%s""" % (idx[0], idx[1][:8]))
239 239
240 240 def test_file_source(self, backend):
241 241 commit = backend.repo.get_commit(commit_idx=167)
242 242 response = self.app.get(
243 243 route_path('repo_files',
244 244 repo_name=backend.repo_name,
245 245 commit_id=commit.raw_id, f_path='vcs/nodes.py'))
246 246
247 247 msgbox = """<div class="commit">%s</div>"""
248 248 response.mustcontain(msgbox % (commit.message, ))
249 249
250 250 assert_response = response.assert_response()
251 251 if commit.branch:
252 252 assert_response.element_contains(
253 253 '.tags.tags-main .branchtag', commit.branch)
254 254 if commit.tags:
255 255 for tag in commit.tags:
256 256 assert_response.element_contains('.tags.tags-main .tagtag', tag)
257 257
258 258 def test_file_source_annotated(self, backend):
259 259 response = self.app.get(
260 260 route_path('repo_files:annotated',
261 261 repo_name=backend.repo_name,
262 262 commit_id='tip', f_path='vcs/nodes.py'))
263 263 expected_commits = {
264 264 'hg': 'r356',
265 265 'git': 'r345',
266 266 'svn': 'r208',
267 267 }
268 268 response.mustcontain(expected_commits[backend.alias])
269 269
270 270 def test_file_source_authors(self, backend):
271 271 response = self.app.get(
272 272 route_path('repo_file_authors',
273 273 repo_name=backend.repo_name,
274 274 commit_id='tip', f_path='vcs/nodes.py'))
275 275 expected_authors = {
276 276 'hg': ('Marcin Kuzminski', 'Lukasz Balcerzak'),
277 277 'git': ('Marcin Kuzminski', 'Lukasz Balcerzak'),
278 278 'svn': ('marcin', 'lukasz'),
279 279 }
280 280
281 281 for author in expected_authors[backend.alias]:
282 282 response.mustcontain(author)
283 283
284 284 def test_file_source_authors_with_annotation(self, backend):
285 285 response = self.app.get(
286 286 route_path('repo_file_authors',
287 287 repo_name=backend.repo_name,
288 288 commit_id='tip', f_path='vcs/nodes.py',
289 289 params=dict(annotate=1)))
290 290 expected_authors = {
291 291 'hg': ('Marcin Kuzminski', 'Lukasz Balcerzak'),
292 292 'git': ('Marcin Kuzminski', 'Lukasz Balcerzak'),
293 293 'svn': ('marcin', 'lukasz'),
294 294 }
295 295
296 296 for author in expected_authors[backend.alias]:
297 297 response.mustcontain(author)
298 298
299 299 def test_file_source_history(self, backend, xhr_header):
300 300 response = self.app.get(
301 301 route_path('repo_file_history',
302 302 repo_name=backend.repo_name,
303 303 commit_id='tip', f_path='vcs/nodes.py'),
304 304 extra_environ=xhr_header)
305 305 assert get_node_history(backend.alias) == json.loads(response.body)
306 306
307 307 def test_file_source_history_svn(self, backend_svn, xhr_header):
308 308 simple_repo = backend_svn['svn-simple-layout']
309 309 response = self.app.get(
310 310 route_path('repo_file_history',
311 311 repo_name=simple_repo.repo_name,
312 312 commit_id='tip', f_path='trunk/example.py'),
313 313 extra_environ=xhr_header)
314 314
315 315 expected_data = json.loads(
316 316 fixture.load_resource('svn_node_history_branches.json'))
317 317
318 318 assert expected_data == response.json
319 319
320 320 def test_file_source_history_with_annotation(self, backend, xhr_header):
321 321 response = self.app.get(
322 322 route_path('repo_file_history',
323 323 repo_name=backend.repo_name,
324 324 commit_id='tip', f_path='vcs/nodes.py',
325 325 params=dict(annotate=1)),
326 326
327 327 extra_environ=xhr_header)
328 328 assert get_node_history(backend.alias) == json.loads(response.body)
329 329
330 330 def test_tree_search_top_level(self, backend, xhr_header):
331 331 commit = backend.repo.get_commit(commit_idx=173)
332 332 response = self.app.get(
333 333 route_path('repo_files_nodelist',
334 334 repo_name=backend.repo_name,
335 335 commit_id=commit.raw_id, f_path='/'),
336 336 extra_environ=xhr_header)
337 337 assert 'nodes' in response.json
338 338 assert {'name': 'docs', 'type': 'dir'} in response.json['nodes']
339 339
340 340 def test_tree_search_missing_xhr(self, backend):
341 341 self.app.get(
342 342 route_path('repo_files_nodelist',
343 343 repo_name=backend.repo_name,
344 344 commit_id='tip', f_path='/'),
345 345 status=404)
346 346
347 347 def test_tree_search_at_path(self, backend, xhr_header):
348 348 commit = backend.repo.get_commit(commit_idx=173)
349 349 response = self.app.get(
350 350 route_path('repo_files_nodelist',
351 351 repo_name=backend.repo_name,
352 352 commit_id=commit.raw_id, f_path='/docs'),
353 353 extra_environ=xhr_header)
354 354 assert 'nodes' in response.json
355 355 nodes = response.json['nodes']
356 356 assert {'name': 'docs/api', 'type': 'dir'} in nodes
357 357 assert {'name': 'docs/index.rst', 'type': 'file'} in nodes
358 358
359 359 def test_tree_search_at_path_2nd_level(self, backend, xhr_header):
360 360 commit = backend.repo.get_commit(commit_idx=173)
361 361 response = self.app.get(
362 362 route_path('repo_files_nodelist',
363 363 repo_name=backend.repo_name,
364 364 commit_id=commit.raw_id, f_path='/docs/api'),
365 365 extra_environ=xhr_header)
366 366 assert 'nodes' in response.json
367 367 nodes = response.json['nodes']
368 368 assert {'name': 'docs/api/index.rst', 'type': 'file'} in nodes
369 369
370 370 def test_tree_search_at_path_missing_xhr(self, backend):
371 371 self.app.get(
372 372 route_path('repo_files_nodelist',
373 373 repo_name=backend.repo_name,
374 374 commit_id='tip', f_path='/docs'),
375 375 status=404)
376 376
377 377 def test_nodetree(self, backend, xhr_header):
378 378 commit = backend.repo.get_commit(commit_idx=173)
379 379 response = self.app.get(
380 380 route_path('repo_nodetree_full',
381 381 repo_name=backend.repo_name,
382 382 commit_id=commit.raw_id, f_path='/'),
383 383 extra_environ=xhr_header)
384 384
385 385 assert_response = response.assert_response()
386 386
387 387 for attr in ['data-commit-id', 'data-date', 'data-author']:
388 388 elements = assert_response.get_elements('[{}]'.format(attr))
389 389 assert len(elements) > 1
390 390
391 391 for element in elements:
392 392 assert element.get(attr)
393 393
394 394 def test_nodetree_if_file(self, backend, xhr_header):
395 395 commit = backend.repo.get_commit(commit_idx=173)
396 396 response = self.app.get(
397 397 route_path('repo_nodetree_full',
398 398 repo_name=backend.repo_name,
399 399 commit_id=commit.raw_id, f_path='README.rst'),
400 400 extra_environ=xhr_header)
401 401 assert response.body == ''
402 402
403 403 def test_nodetree_wrong_path(self, backend, xhr_header):
404 404 commit = backend.repo.get_commit(commit_idx=173)
405 405 response = self.app.get(
406 406 route_path('repo_nodetree_full',
407 407 repo_name=backend.repo_name,
408 408 commit_id=commit.raw_id, f_path='/dont-exist'),
409 409 extra_environ=xhr_header)
410 410
411 411 err = 'error: There is no file nor ' \
412 412 'directory at the given path'
413 413 assert err in response.body
414 414
415 415 def test_nodetree_missing_xhr(self, backend):
416 416 self.app.get(
417 417 route_path('repo_nodetree_full',
418 418 repo_name=backend.repo_name,
419 419 commit_id='tip', f_path='/'),
420 420 status=404)
421 421
422 422
423 423 @pytest.mark.usefixtures("app", "autologin_user")
424 424 class TestRawFileHandling(object):
425 425
426 426 def test_download_file(self, backend):
427 427 commit = backend.repo.get_commit(commit_idx=173)
428 428 response = self.app.get(
429 429 route_path('repo_file_download',
430 430 repo_name=backend.repo_name,
431 431 commit_id=commit.raw_id, f_path='vcs/nodes.py'),)
432 432
433 433 assert response.content_disposition == 'attachment; filename="nodes.py"; filename*=UTF-8\'\'nodes.py'
434 434 assert response.content_type == "text/x-python"
435 435
436 436 def test_download_file_wrong_cs(self, backend):
437 437 raw_id = u'ERRORce30c96924232dffcd24178a07ffeb5dfc'
438 438
439 439 response = self.app.get(
440 440 route_path('repo_file_download',
441 441 repo_name=backend.repo_name,
442 442 commit_id=raw_id, f_path='vcs/nodes.svg'),
443 443 status=404)
444 444
445 445 msg = """No such commit exists for this repository"""
446 446 response.mustcontain(msg)
447 447
448 448 def test_download_file_wrong_f_path(self, backend):
449 449 commit = backend.repo.get_commit(commit_idx=173)
450 450 f_path = 'vcs/ERRORnodes.py'
451 451
452 452 response = self.app.get(
453 453 route_path('repo_file_download',
454 454 repo_name=backend.repo_name,
455 455 commit_id=commit.raw_id, f_path=f_path),
456 456 status=404)
457 457
458 458 msg = (
459 459 "There is no file nor directory at the given path: "
460 460 "`%s` at commit %s" % (f_path, commit.short_id))
461 461 response.mustcontain(msg)
462 462
463 463 def test_file_raw(self, backend):
464 464 commit = backend.repo.get_commit(commit_idx=173)
465 465 response = self.app.get(
466 466 route_path('repo_file_raw',
467 467 repo_name=backend.repo_name,
468 468 commit_id=commit.raw_id, f_path='vcs/nodes.py'),)
469 469
470 470 assert response.content_type == "text/plain"
471 471
472 472 def test_file_raw_binary(self, backend):
473 473 commit = backend.repo.get_commit()
474 474 response = self.app.get(
475 475 route_path('repo_file_raw',
476 476 repo_name=backend.repo_name,
477 477 commit_id=commit.raw_id,
478 478 f_path='docs/theme/ADC/static/breadcrumb_background.png'),)
479 479
480 480 assert response.content_disposition == 'inline'
481 481
482 482 def test_raw_file_wrong_cs(self, backend):
483 483 raw_id = u'ERRORcce30c96924232dffcd24178a07ffeb5dfc'
484 484
485 485 response = self.app.get(
486 486 route_path('repo_file_raw',
487 487 repo_name=backend.repo_name,
488 488 commit_id=raw_id, f_path='vcs/nodes.svg'),
489 489 status=404)
490 490
491 491 msg = """No such commit exists for this repository"""
492 492 response.mustcontain(msg)
493 493
494 494 def test_raw_wrong_f_path(self, backend):
495 495 commit = backend.repo.get_commit(commit_idx=173)
496 496 f_path = 'vcs/ERRORnodes.py'
497 497 response = self.app.get(
498 498 route_path('repo_file_raw',
499 499 repo_name=backend.repo_name,
500 500 commit_id=commit.raw_id, f_path=f_path),
501 501 status=404)
502 502
503 503 msg = (
504 504 "There is no file nor directory at the given path: "
505 505 "`%s` at commit %s" % (f_path, commit.short_id))
506 506 response.mustcontain(msg)
507 507
508 508 def test_raw_svg_should_not_be_rendered(self, backend):
509 509 backend.create_repo()
510 510 backend.ensure_file("xss.svg")
511 511 response = self.app.get(
512 512 route_path('repo_file_raw',
513 513 repo_name=backend.repo_name,
514 514 commit_id='tip', f_path='xss.svg'),)
515 515 # If the content type is image/svg+xml then it allows to render HTML
516 516 # and malicious SVG.
517 517 assert response.content_type == "text/plain"
518 518
519 519
520 520 @pytest.mark.usefixtures("app")
521 521 class TestRepositoryArchival(object):
522 522
523 523 def test_archival(self, backend):
524 524 backend.enable_downloads()
525 525 commit = backend.repo.get_commit(commit_idx=173)
526 526 for a_type, content_type, extension in settings.ARCHIVE_SPECS:
527 527
528 528 short = commit.short_id + extension
529 529 fname = commit.raw_id + extension
530 530 filename = '%s-%s' % (backend.repo_name, short)
531 531 response = self.app.get(
532 532 route_path('repo_archivefile',
533 533 repo_name=backend.repo_name,
534 534 fname=fname))
535 535
536 536 assert response.status == '200 OK'
537 537 headers = [
538 538 ('Content-Disposition', 'attachment; filename=%s' % filename),
539 539 ('Content-Type', '%s' % content_type),
540 540 ]
541 541
542 542 for header in headers:
543 543 assert header in response.headers.items()
544 544
545 545 @pytest.mark.parametrize('arch_ext',[
546 546 'tar', 'rar', 'x', '..ax', '.zipz', 'tar.gz.tar'])
547 547 def test_archival_wrong_ext(self, backend, arch_ext):
548 548 backend.enable_downloads()
549 549 commit = backend.repo.get_commit(commit_idx=173)
550 550
551 551 fname = commit.raw_id + '.' + arch_ext
552 552
553 553 response = self.app.get(
554 554 route_path('repo_archivefile',
555 555 repo_name=backend.repo_name,
556 556 fname=fname))
557 557 response.mustcontain(
558 558 'Unknown archive type for: `{}`'.format(fname))
559 559
560 560 @pytest.mark.parametrize('commit_id', [
561 561 '00x000000', 'tar', 'wrong', '@$@$42413232', '232dffcd'])
562 562 def test_archival_wrong_commit_id(self, backend, commit_id):
563 563 backend.enable_downloads()
564 564 fname = '%s.zip' % commit_id
565 565
566 566 response = self.app.get(
567 567 route_path('repo_archivefile',
568 568 repo_name=backend.repo_name,
569 569 fname=fname))
570 570 response.mustcontain('Unknown commit_id')
571 571
572 572
573 573 @pytest.mark.usefixtures("app")
574 574 class TestFilesDiff(object):
575 575
576 576 @pytest.mark.parametrize("diff", ['diff', 'download', 'raw'])
577 577 def test_file_full_diff(self, backend, diff):
578 578 commit1 = backend.repo.get_commit(commit_idx=-1)
579 579 commit2 = backend.repo.get_commit(commit_idx=-2)
580 580
581 581 response = self.app.get(
582 582 route_path('repo_files_diff',
583 583 repo_name=backend.repo_name,
584 584 f_path='README'),
585 585 params={
586 586 'diff1': commit2.raw_id,
587 587 'diff2': commit1.raw_id,
588 588 'fulldiff': '1',
589 589 'diff': diff,
590 590 })
591 591
592 592 if diff == 'diff':
593 593 # use redirect since this is OLD view redirecting to compare page
594 594 response = response.follow()
595 595
596 596 # It's a symlink to README.rst
597 597 response.mustcontain('README.rst')
598 598 response.mustcontain('No newline at end of file')
599 599
600 600 def test_file_binary_diff(self, backend):
601 601 commits = [
602 602 {'message': 'First commit'},
603 603 {'message': 'Commit with binary',
604 604 'added': [nodes.FileNode('file.bin', content='\0BINARY\0')]},
605 605 ]
606 606 repo = backend.create_repo(commits=commits)
607 607
608 608 response = self.app.get(
609 609 route_path('repo_files_diff',
610 610 repo_name=backend.repo_name,
611 611 f_path='file.bin'),
612 612 params={
613 613 'diff1': repo.get_commit(commit_idx=0).raw_id,
614 614 'diff2': repo.get_commit(commit_idx=1).raw_id,
615 615 'fulldiff': '1',
616 616 'diff': 'diff',
617 617 })
618 618 # use redirect since this is OLD view redirecting to compare page
619 619 response = response.follow()
620 620 response.mustcontain('Collapse 1 commit')
621 621 file_changes = (1, 0, 0)
622 622
623 623 compare_page = ComparePage(response)
624 624 compare_page.contains_change_summary(*file_changes)
625 625
626 626 if backend.alias == 'svn':
627 627 response.mustcontain('new file 10644')
628 628 # TODO(marcink): SVN doesn't yet detect binary changes
629 629 else:
630 630 response.mustcontain('new file 100644')
631 631 response.mustcontain('binary diff hidden')
632 632
633 633 def test_diff_2way(self, backend):
634 634 commit1 = backend.repo.get_commit(commit_idx=-1)
635 635 commit2 = backend.repo.get_commit(commit_idx=-2)
636 636 response = self.app.get(
637 637 route_path('repo_files_diff_2way_redirect',
638 638 repo_name=backend.repo_name,
639 639 f_path='README'),
640 640 params={
641 641 'diff1': commit2.raw_id,
642 642 'diff2': commit1.raw_id,
643 643 })
644 644 # use redirect since this is OLD view redirecting to compare page
645 645 response = response.follow()
646 646
647 647 # It's a symlink to README.rst
648 648 response.mustcontain('README.rst')
649 649 response.mustcontain('No newline at end of file')
650 650
651 651 def test_requires_one_commit_id(self, backend, autologin_user):
652 652 response = self.app.get(
653 653 route_path('repo_files_diff',
654 654 repo_name=backend.repo_name,
655 655 f_path='README.rst'),
656 656 status=400)
657 657 response.mustcontain(
658 658 'Need query parameter', 'diff1', 'diff2', 'to generate a diff.')
659 659
660 660 def test_returns_no_files_if_file_does_not_exist(self, vcsbackend):
661 661 repo = vcsbackend.repo
662 662 response = self.app.get(
663 663 route_path('repo_files_diff',
664 664 repo_name=repo.name,
665 665 f_path='does-not-exist-in-any-commit'),
666 666 params={
667 667 'diff1': repo[0].raw_id,
668 668 'diff2': repo[1].raw_id
669 669 })
670 670
671 671 response = response.follow()
672 672 response.mustcontain('No files')
673 673
674 674 def test_returns_redirect_if_file_not_changed(self, backend):
675 675 commit = backend.repo.get_commit(commit_idx=-1)
676 676 response = self.app.get(
677 677 route_path('repo_files_diff_2way_redirect',
678 678 repo_name=backend.repo_name,
679 679 f_path='README'),
680 680 params={
681 681 'diff1': commit.raw_id,
682 682 'diff2': commit.raw_id,
683 683 })
684 684
685 685 response = response.follow()
686 686 response.mustcontain('No files')
687 687 response.mustcontain('No commits in this compare')
688 688
689 689 def test_supports_diff_to_different_path_svn(self, backend_svn):
690 690 #TODO: check this case
691 691 return
692 692
693 693 repo = backend_svn['svn-simple-layout'].scm_instance()
694 694 commit_id_1 = '24'
695 695 commit_id_2 = '26'
696 696
697 697 response = self.app.get(
698 698 route_path('repo_files_diff',
699 699 repo_name=backend_svn.repo_name,
700 700 f_path='trunk/example.py'),
701 701 params={
702 702 'diff1': 'tags/v0.2/example.py@' + commit_id_1,
703 703 'diff2': commit_id_2,
704 704 })
705 705
706 706 response = response.follow()
707 707 response.mustcontain(
708 708 # diff contains this
709 709 "Will print out a useful message on invocation.")
710 710
711 711 # Note: Expecting that we indicate the user what's being compared
712 712 response.mustcontain("trunk/example.py")
713 713 response.mustcontain("tags/v0.2/example.py")
714 714
715 715 def test_show_rev_redirects_to_svn_path(self, backend_svn):
716 716 #TODO: check this case
717 717 return
718 718
719 719 repo = backend_svn['svn-simple-layout'].scm_instance()
720 720 commit_id = repo[-1].raw_id
721 721
722 722 response = self.app.get(
723 723 route_path('repo_files_diff',
724 724 repo_name=backend_svn.repo_name,
725 725 f_path='trunk/example.py'),
726 726 params={
727 727 'diff1': 'branches/argparse/example.py@' + commit_id,
728 728 'diff2': commit_id,
729 729 },
730 730 status=302)
731 731 response = response.follow()
732 732 assert response.headers['Location'].endswith(
733 733 'svn-svn-simple-layout/files/26/branches/argparse/example.py')
734 734
735 735 def test_show_rev_and_annotate_redirects_to_svn_path(self, backend_svn):
736 736 #TODO: check this case
737 737 return
738 738
739 739 repo = backend_svn['svn-simple-layout'].scm_instance()
740 740 commit_id = repo[-1].raw_id
741 741 response = self.app.get(
742 742 route_path('repo_files_diff',
743 743 repo_name=backend_svn.repo_name,
744 744 f_path='trunk/example.py'),
745 745 params={
746 746 'diff1': 'branches/argparse/example.py@' + commit_id,
747 747 'diff2': commit_id,
748 748 'show_rev': 'Show at Revision',
749 749 'annotate': 'true',
750 750 },
751 751 status=302)
752 752 response = response.follow()
753 753 assert response.headers['Location'].endswith(
754 754 'svn-svn-simple-layout/annotate/26/branches/argparse/example.py')
755 755
756 756
757 757 @pytest.mark.usefixtures("app", "autologin_user")
758 758 class TestModifyFilesWithWebInterface(object):
759 759
760 760 def test_add_file_view(self, backend):
761 761 self.app.get(
762 762 route_path('repo_files_add_file',
763 763 repo_name=backend.repo_name,
764 764 commit_id='tip', f_path='/')
765 765 )
766 766
767 767 @pytest.mark.xfail_backends("svn", reason="Depends on online editing")
768 768 def test_add_file_into_repo_missing_content(self, backend, csrf_token):
769 769 backend.create_repo()
770 770 filename = 'init.py'
771 771 response = self.app.post(
772 772 route_path('repo_files_create_file',
773 773 repo_name=backend.repo_name,
774 774 commit_id='tip', f_path='/'),
775 775 params={
776 776 'content': "",
777 777 'filename': filename,
778 778 'csrf_token': csrf_token,
779 779 },
780 780 status=302)
781 781 expected_msg = 'Successfully committed new file `{}`'.format(os.path.join(filename))
782 782 assert_session_flash(response, expected_msg)
783 783
784 784 def test_add_file_into_repo_missing_filename(self, backend, csrf_token):
785 785 commit_id = backend.repo.get_commit().raw_id
786 786 response = self.app.post(
787 787 route_path('repo_files_create_file',
788 788 repo_name=backend.repo_name,
789 789 commit_id=commit_id, f_path='/'),
790 790 params={
791 791 'content': "foo",
792 792 'csrf_token': csrf_token,
793 793 },
794 794 status=302)
795 795
796 796 assert_session_flash(response, 'No filename specified')
797 797
798 798 def test_add_file_into_repo_errors_and_no_commits(
799 799 self, backend, csrf_token):
800 800 repo = backend.create_repo()
801 801 # Create a file with no filename, it will display an error but
802 802 # the repo has no commits yet
803 803 response = self.app.post(
804 804 route_path('repo_files_create_file',
805 805 repo_name=repo.repo_name,
806 806 commit_id='tip', f_path='/'),
807 807 params={
808 808 'content': "foo",
809 809 'csrf_token': csrf_token,
810 810 },
811 811 status=302)
812 812
813 813 assert_session_flash(response, 'No filename specified')
814 814
815 815 # Not allowed, redirect to the summary
816 816 redirected = response.follow()
817 817 summary_url = h.route_path('repo_summary', repo_name=repo.repo_name)
818 818
819 819 # As there are no commits, displays the summary page with the error of
820 820 # creating a file with no filename
821 821
822 822 assert redirected.request.path == summary_url
823 823
824 824 @pytest.mark.parametrize("filename, clean_filename", [
825 825 ('/abs/foo', 'abs/foo'),
826 826 ('../rel/foo', 'rel/foo'),
827 827 ('file/../foo/foo', 'file/foo/foo'),
828 828 ])
829 829 def test_add_file_into_repo_bad_filenames(self, filename, clean_filename, backend, csrf_token):
830 830 repo = backend.create_repo()
831 831 commit_id = repo.get_commit().raw_id
832 832
833 833 response = self.app.post(
834 834 route_path('repo_files_create_file',
835 835 repo_name=repo.repo_name,
836 836 commit_id=commit_id, f_path='/'),
837 837 params={
838 838 'content': "foo",
839 839 'filename': filename,
840 840 'csrf_token': csrf_token,
841 841 },
842 842 status=302)
843 843
844 844 expected_msg = 'Successfully committed new file `{}`'.format(clean_filename)
845 845 assert_session_flash(response, expected_msg)
846 846
847 847 @pytest.mark.parametrize("cnt, filename, content", [
848 848 (1, 'foo.txt', "Content"),
849 849 (2, 'dir/foo.rst', "Content"),
850 850 (3, 'dir/foo-second.rst', "Content"),
851 851 (4, 'rel/dir/foo.bar', "Content"),
852 852 ])
853 853 def test_add_file_into_empty_repo(self, cnt, filename, content, backend, csrf_token):
854 854 repo = backend.create_repo()
855 855 commit_id = repo.get_commit().raw_id
856 856 response = self.app.post(
857 857 route_path('repo_files_create_file',
858 858 repo_name=repo.repo_name,
859 859 commit_id=commit_id, f_path='/'),
860 860 params={
861 861 'content': content,
862 862 'filename': filename,
863 863 'csrf_token': csrf_token,
864 864 },
865 865 status=302)
866 866
867 867 expected_msg = 'Successfully committed new file `{}`'.format(filename)
868 868 assert_session_flash(response, expected_msg)
869 869
870 870 def test_edit_file_view(self, backend):
871 871 response = self.app.get(
872 872 route_path('repo_files_edit_file',
873 873 repo_name=backend.repo_name,
874 874 commit_id=backend.default_head_id,
875 875 f_path='vcs/nodes.py'),
876 876 status=200)
877 877 response.mustcontain("Module holding everything related to vcs nodes.")
878 878
879 879 def test_edit_file_view_not_on_branch(self, backend):
880 880 repo = backend.create_repo()
881 881 backend.ensure_file("vcs/nodes.py")
882 882
883 883 response = self.app.get(
884 884 route_path('repo_files_edit_file',
885 885 repo_name=repo.repo_name,
886 886 commit_id='tip',
887 887 f_path='vcs/nodes.py'),
888 888 status=302)
889 889 assert_session_flash(
890 890 response, 'Cannot modify file. Given commit `tip` is not head of a branch.')
891 891
892 892 def test_edit_file_view_commit_changes(self, backend, csrf_token):
893 893 repo = backend.create_repo()
894 894 backend.ensure_file("vcs/nodes.py", content="print 'hello'")
895 895
896 896 response = self.app.post(
897 897 route_path('repo_files_update_file',
898 898 repo_name=repo.repo_name,
899 899 commit_id=backend.default_head_id,
900 900 f_path='vcs/nodes.py'),
901 901 params={
902 902 'content': "print 'hello world'",
903 903 'message': 'I committed',
904 904 'filename': "vcs/nodes.py",
905 905 'csrf_token': csrf_token,
906 906 },
907 907 status=302)
908 908 assert_session_flash(
909 909 response, 'Successfully committed changes to file `vcs/nodes.py`')
910 910 tip = repo.get_commit(commit_idx=-1)
911 911 assert tip.message == 'I committed'
912 912
913 913 def test_edit_file_view_commit_changes_default_message(self, backend,
914 914 csrf_token):
915 915 repo = backend.create_repo()
916 916 backend.ensure_file("vcs/nodes.py", content="print 'hello'")
917 917
918 918 commit_id = (
919 919 backend.default_branch_name or
920 920 backend.repo.scm_instance().commit_ids[-1])
921 921
922 922 response = self.app.post(
923 923 route_path('repo_files_update_file',
924 924 repo_name=repo.repo_name,
925 925 commit_id=commit_id,
926 926 f_path='vcs/nodes.py'),
927 927 params={
928 928 'content': "print 'hello world'",
929 929 'message': '',
930 930 'filename': "vcs/nodes.py",
931 931 'csrf_token': csrf_token,
932 932 },
933 933 status=302)
934 934 assert_session_flash(
935 935 response, 'Successfully committed changes to file `vcs/nodes.py`')
936 936 tip = repo.get_commit(commit_idx=-1)
937 937 assert tip.message == 'Edited file vcs/nodes.py via RhodeCode Enterprise'
938 938
939 939 def test_delete_file_view(self, backend):
940 940 self.app.get(
941 941 route_path('repo_files_remove_file',
942 942 repo_name=backend.repo_name,
943 943 commit_id=backend.default_head_id,
944 944 f_path='vcs/nodes.py'),
945 945 status=200)
946 946
947 947 def test_delete_file_view_not_on_branch(self, backend):
948 948 repo = backend.create_repo()
949 949 backend.ensure_file('vcs/nodes.py')
950 950
951 951 response = self.app.get(
952 952 route_path('repo_files_remove_file',
953 953 repo_name=repo.repo_name,
954 954 commit_id='tip',
955 955 f_path='vcs/nodes.py'),
956 956 status=302)
957 957 assert_session_flash(
958 958 response, 'Cannot modify file. Given commit `tip` is not head of a branch.')
959 959
960 960 def test_delete_file_view_commit_changes(self, backend, csrf_token):
961 961 repo = backend.create_repo()
962 962 backend.ensure_file("vcs/nodes.py")
963 963
964 964 response = self.app.post(
965 965 route_path('repo_files_delete_file',
966 966 repo_name=repo.repo_name,
967 967 commit_id=backend.default_head_id,
968 968 f_path='vcs/nodes.py'),
969 969 params={
970 970 'message': 'i commited',
971 971 'csrf_token': csrf_token,
972 972 },
973 973 status=302)
974 974 assert_session_flash(
975 975 response, 'Successfully deleted file `vcs/nodes.py`')
976 976
977 977
978 978 @pytest.mark.usefixtures("app")
979 979 class TestFilesViewOtherCases(object):
980 980
981 981 def test_access_empty_repo_redirect_to_summary_with_alert_write_perms(
982 982 self, backend_stub, autologin_regular_user, user_regular,
983 983 user_util):
984 984
985 985 repo = backend_stub.create_repo()
986 986 user_util.grant_user_permission_to_repo(
987 987 repo, user_regular, 'repository.write')
988 988 response = self.app.get(
989 989 route_path('repo_files',
990 990 repo_name=repo.repo_name,
991 991 commit_id='tip', f_path='/'))
992 992
993 993 repo_file_add_url = route_path(
994 994 'repo_files_add_file',
995 995 repo_name=repo.repo_name,
996 996 commit_id=0, f_path='')
997 997
998 998 assert_session_flash(
999 999 response,
1000 1000 'There are no files yet. <a class="alert-link" '
1001 1001 'href="{}">Click here to add a new file.</a>'
1002 1002 .format(repo_file_add_url))
1003 1003
1004 1004 def test_access_empty_repo_redirect_to_summary_with_alert_no_write_perms(
1005 1005 self, backend_stub, autologin_regular_user):
1006 1006 repo = backend_stub.create_repo()
1007 1007 # init session for anon user
1008 1008 route_path('repo_summary', repo_name=repo.repo_name)
1009 1009
1010 1010 repo_file_add_url = route_path(
1011 1011 'repo_files_add_file',
1012 1012 repo_name=repo.repo_name,
1013 1013 commit_id=0, f_path='')
1014 1014
1015 1015 response = self.app.get(
1016 1016 route_path('repo_files',
1017 1017 repo_name=repo.repo_name,
1018 1018 commit_id='tip', f_path='/'))
1019 1019
1020 1020 assert_session_flash(response, no_=repo_file_add_url)
1021 1021
1022 1022 @pytest.mark.parametrize('file_node', [
1023 1023 'archive/file.zip',
1024 1024 'diff/my-file.txt',
1025 1025 'render.py',
1026 1026 'render',
1027 1027 'remove_file',
1028 1028 'remove_file/to-delete.txt',
1029 1029 ])
1030 1030 def test_file_names_equal_to_routes_parts(self, backend, file_node):
1031 1031 backend.create_repo()
1032 1032 backend.ensure_file(file_node)
1033 1033
1034 1034 self.app.get(
1035 1035 route_path('repo_files',
1036 1036 repo_name=backend.repo_name,
1037 1037 commit_id='tip', f_path=file_node),
1038 1038 status=200)
1039 1039
1040 1040
1041 1041 class TestAdjustFilePathForSvn(object):
1042 1042 """
1043 1043 SVN specific adjustments of node history in RepoFilesView.
1044 1044 """
1045 1045
1046 1046 def test_returns_path_relative_to_matched_reference(self):
1047 1047 repo = self._repo(branches=['trunk'])
1048 1048 self.assert_file_adjustment('trunk/file', 'file', repo)
1049 1049
1050 1050 def test_does_not_modify_file_if_no_reference_matches(self):
1051 1051 repo = self._repo(branches=['trunk'])
1052 1052 self.assert_file_adjustment('notes/file', 'notes/file', repo)
1053 1053
1054 1054 def test_does_not_adjust_partial_directory_names(self):
1055 1055 repo = self._repo(branches=['trun'])
1056 1056 self.assert_file_adjustment('trunk/file', 'trunk/file', repo)
1057 1057
1058 1058 def test_is_robust_to_patterns_which_prefix_other_patterns(self):
1059 1059 repo = self._repo(branches=['trunk', 'trunk/new', 'trunk/old'])
1060 1060 self.assert_file_adjustment('trunk/new/file', 'file', repo)
1061 1061
1062 1062 def assert_file_adjustment(self, f_path, expected, repo):
1063 1063 result = RepoFilesView.adjust_file_path_for_svn(f_path, repo)
1064 1064 assert result == expected
1065 1065
1066 1066 def _repo(self, branches=None):
1067 1067 repo = mock.Mock()
1068 1068 repo.branches = OrderedDict((name, '0') for name in branches or [])
1069 1069 repo.tags = {}
1070 1070 return repo
@@ -1,1603 +1,1618 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 import itertools
22 22 import logging
23 23 import os
24 24 import shutil
25 25 import tempfile
26 26 import collections
27 27 import urllib
28 28 import pathlib2
29 29
30 30 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
31 31 from pyramid.view import view_config
32 32 from pyramid.renderers import render
33 33 from pyramid.response import Response
34 34
35 35 import rhodecode
36 36 from rhodecode.apps._base import RepoAppView
37 37
38 38
39 39 from rhodecode.lib import diffs, helpers as h, rc_cache
40 40 from rhodecode.lib import audit_logger
41 41 from rhodecode.lib.view_utils import parse_path_ref
42 42 from rhodecode.lib.exceptions import NonRelativePathError
43 43 from rhodecode.lib.codeblocks import (
44 44 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
45 45 from rhodecode.lib.utils2 import (
46 46 convert_line_endings, detect_mode, safe_str, str2bool, safe_int, sha1, safe_unicode)
47 47 from rhodecode.lib.auth import (
48 48 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
49 49 from rhodecode.lib.vcs import path as vcspath
50 50 from rhodecode.lib.vcs.backends.base import EmptyCommit
51 51 from rhodecode.lib.vcs.conf import settings
52 52 from rhodecode.lib.vcs.nodes import FileNode
53 53 from rhodecode.lib.vcs.exceptions import (
54 54 RepositoryError, CommitDoesNotExistError, EmptyRepositoryError,
55 55 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,
56 56 NodeDoesNotExistError, CommitError, NodeError)
57 57
58 58 from rhodecode.model.scm import ScmModel
59 59 from rhodecode.model.db import Repository
60 60
61 61 log = logging.getLogger(__name__)
62 62
63 63
64 64 class RepoFilesView(RepoAppView):
65 65
66 66 @staticmethod
67 67 def adjust_file_path_for_svn(f_path, repo):
68 68 """
69 69 Computes the relative path of `f_path`.
70 70
71 71 This is mainly based on prefix matching of the recognized tags and
72 72 branches in the underlying repository.
73 73 """
74 74 tags_and_branches = itertools.chain(
75 75 repo.branches.iterkeys(),
76 76 repo.tags.iterkeys())
77 77 tags_and_branches = sorted(tags_and_branches, key=len, reverse=True)
78 78
79 79 for name in tags_and_branches:
80 80 if f_path.startswith('{}/'.format(name)):
81 81 f_path = vcspath.relpath(f_path, name)
82 82 break
83 83 return f_path
84 84
85 85 def load_default_context(self):
86 86 c = self._get_local_tmpl_context(include_app_defaults=True)
87 87 c.rhodecode_repo = self.rhodecode_vcs_repo
88 88 c.enable_downloads = self.db_repo.enable_downloads
89 89 return c
90 90
91 91 def _ensure_not_locked(self, commit_id='tip'):
92 92 _ = self.request.translate
93 93
94 94 repo = self.db_repo
95 95 if repo.enable_locking and repo.locked[0]:
96 96 h.flash(_('This repository has been locked by %s on %s')
97 97 % (h.person_by_id(repo.locked[0]),
98 98 h.format_date(h.time_to_datetime(repo.locked[1]))),
99 99 'warning')
100 100 files_url = h.route_path(
101 101 'repo_files:default_path',
102 102 repo_name=self.db_repo_name, commit_id=commit_id)
103 103 raise HTTPFound(files_url)
104 104
105 105 def forbid_non_head(self, is_head, f_path, commit_id='tip', json_mode=False):
106 106 _ = self.request.translate
107 107
108 108 if not is_head:
109 109 message = _('Cannot modify file. '
110 110 'Given commit `{}` is not head of a branch.').format(commit_id)
111 111 h.flash(message, category='warning')
112 112
113 113 if json_mode:
114 114 return message
115 115
116 116 files_url = h.route_path(
117 117 'repo_files', repo_name=self.db_repo_name, commit_id=commit_id,
118 118 f_path=f_path)
119 119 raise HTTPFound(files_url)
120 120
121 121 def check_branch_permission(self, branch_name, commit_id='tip', json_mode=False):
122 122 _ = self.request.translate
123 123
124 124 rule, branch_perm = self._rhodecode_user.get_rule_and_branch_permission(
125 125 self.db_repo_name, branch_name)
126 126 if branch_perm and branch_perm not in ['branch.push', 'branch.push_force']:
127 127 message = _('Branch `{}` changes forbidden by rule {}.').format(
128 branch_name, rule)
128 h.escape(branch_name), rule)
129 129 h.flash(message, 'warning')
130 130
131 131 if json_mode:
132 132 return message
133 133
134 134 files_url = h.route_path(
135 135 'repo_files:default_path', repo_name=self.db_repo_name, commit_id=commit_id)
136 136
137 137 raise HTTPFound(files_url)
138 138
139 139 def _get_commit_and_path(self):
140 default_commit_id = self.db_repo.landing_rev[1]
140 default_commit_id = self.db_repo.landing_ref_name
141 141 default_f_path = '/'
142 142
143 143 commit_id = self.request.matchdict.get(
144 144 'commit_id', default_commit_id)
145 145 f_path = self._get_f_path(self.request.matchdict, default_f_path)
146 146 return commit_id, f_path
147 147
148 148 def _get_default_encoding(self, c):
149 149 enc_list = getattr(c, 'default_encodings', [])
150 150 return enc_list[0] if enc_list else 'UTF-8'
151 151
152 152 def _get_commit_or_redirect(self, commit_id, redirect_after=True):
153 153 """
154 154 This is a safe way to get commit. If an error occurs it redirects to
155 155 tip with proper message
156 156
157 157 :param commit_id: id of commit to fetch
158 158 :param redirect_after: toggle redirection
159 159 """
160 160 _ = self.request.translate
161 161
162 162 try:
163 163 return self.rhodecode_vcs_repo.get_commit(commit_id)
164 164 except EmptyRepositoryError:
165 165 if not redirect_after:
166 166 return None
167 167
168 168 _url = h.route_path(
169 169 'repo_files_add_file',
170 170 repo_name=self.db_repo_name, commit_id=0, f_path='')
171 171
172 172 if h.HasRepoPermissionAny(
173 173 'repository.write', 'repository.admin')(self.db_repo_name):
174 174 add_new = h.link_to(
175 175 _('Click here to add a new file.'), _url, class_="alert-link")
176 176 else:
177 177 add_new = ""
178 178
179 179 h.flash(h.literal(
180 180 _('There are no files yet. %s') % add_new), category='warning')
181 181 raise HTTPFound(
182 182 h.route_path('repo_summary', repo_name=self.db_repo_name))
183 183
184 except (CommitDoesNotExistError, LookupError):
185 msg = _('No such commit exists for this repository')
184 except (CommitDoesNotExistError, LookupError) as e:
185 msg = _('No such commit exists for this repository. Commit: {}').format(commit_id)
186 186 h.flash(msg, category='error')
187 187 raise HTTPNotFound()
188 188 except RepositoryError as e:
189 189 h.flash(safe_str(h.escape(e)), category='error')
190 190 raise HTTPNotFound()
191 191
192 192 def _get_filenode_or_redirect(self, commit_obj, path):
193 193 """
194 194 Returns file_node, if error occurs or given path is directory,
195 195 it'll redirect to top level path
196 196 """
197 197 _ = self.request.translate
198 198
199 199 try:
200 200 file_node = commit_obj.get_node(path)
201 201 if file_node.is_dir():
202 202 raise RepositoryError('The given path is a directory')
203 203 except CommitDoesNotExistError:
204 204 log.exception('No such commit exists for this repository')
205 205 h.flash(_('No such commit exists for this repository'), category='error')
206 206 raise HTTPNotFound()
207 207 except RepositoryError as e:
208 208 log.warning('Repository error while fetching filenode `%s`. Err:%s', path, e)
209 209 h.flash(safe_str(h.escape(e)), category='error')
210 210 raise HTTPNotFound()
211 211
212 212 return file_node
213 213
214 214 def _is_valid_head(self, commit_id, repo):
215 215 branch_name = sha_commit_id = ''
216 216 is_head = False
217 217 log.debug('Checking if commit_id `%s` is a head for %s.', commit_id, repo)
218 218
219 219 for _branch_name, branch_commit_id in repo.branches.items():
220 220 # simple case we pass in branch name, it's a HEAD
221 221 if commit_id == _branch_name:
222 222 is_head = True
223 223 branch_name = _branch_name
224 224 sha_commit_id = branch_commit_id
225 225 break
226 226 # case when we pass in full sha commit_id, which is a head
227 227 elif commit_id == branch_commit_id:
228 228 is_head = True
229 229 branch_name = _branch_name
230 230 sha_commit_id = branch_commit_id
231 231 break
232 232
233 233 if h.is_svn(repo) and not repo.is_empty():
234 234 # Note: Subversion only has one head.
235 235 if commit_id == repo.get_commit(commit_idx=-1).raw_id:
236 236 is_head = True
237 237 return branch_name, sha_commit_id, is_head
238 238
239 239 # checked branches, means we only need to try to get the branch/commit_sha
240 240 if not repo.is_empty():
241 241 commit = repo.get_commit(commit_id=commit_id)
242 242 if commit:
243 243 branch_name = commit.branch
244 244 sha_commit_id = commit.raw_id
245 245
246 246 return branch_name, sha_commit_id, is_head
247 247
248 248 def _get_tree_at_commit(self, c, commit_id, f_path, full_load=False, at_rev=None):
249 249
250 250 repo_id = self.db_repo.repo_id
251 251 force_recache = self.get_recache_flag()
252 252
253 253 cache_seconds = safe_int(
254 254 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
255 255 cache_on = not force_recache and cache_seconds > 0
256 256 log.debug(
257 257 'Computing FILE TREE for repo_id %s commit_id `%s` and path `%s`'
258 258 'with caching: %s[TTL: %ss]' % (
259 259 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
260 260
261 261 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
262 262 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
263 263
264 264 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid, condition=cache_on)
265 265 def compute_file_tree(ver, _name_hash, _repo_id, _commit_id, _f_path, _full_load, _at_rev):
266 266 log.debug('Generating cached file tree at ver:%s for repo_id: %s, %s, %s',
267 267 ver, _repo_id, _commit_id, _f_path)
268 268
269 269 c.full_load = _full_load
270 270 return render(
271 271 'rhodecode:templates/files/files_browser_tree.mako',
272 272 self._get_template_context(c), self.request, _at_rev)
273 273
274 274 return compute_file_tree(
275 275 rc_cache.FILE_TREE_CACHE_VER, self.db_repo.repo_name_hash,
276 276 self.db_repo.repo_id, commit_id, f_path, full_load, at_rev)
277 277
278 278 def _get_archive_spec(self, fname):
279 279 log.debug('Detecting archive spec for: `%s`', fname)
280 280
281 281 fileformat = None
282 282 ext = None
283 283 content_type = None
284 284 for a_type, content_type, extension in settings.ARCHIVE_SPECS:
285 285
286 286 if fname.endswith(extension):
287 287 fileformat = a_type
288 288 log.debug('archive is of type: %s', fileformat)
289 289 ext = extension
290 290 break
291 291
292 292 if not fileformat:
293 293 raise ValueError()
294 294
295 295 # left over part of whole fname is the commit
296 296 commit_id = fname[:-len(ext)]
297 297
298 298 return commit_id, ext, fileformat, content_type
299 299
300 300 def create_pure_path(self, *parts):
301 301 # Split paths and sanitize them, removing any ../ etc
302 302 sanitized_path = [
303 303 x for x in pathlib2.PurePath(*parts).parts
304 304 if x not in ['.', '..']]
305 305
306 306 pure_path = pathlib2.PurePath(*sanitized_path)
307 307 return pure_path
308 308
309 309 def _is_lf_enabled(self, target_repo):
310 310 lf_enabled = False
311 311
312 312 lf_key_for_vcs_map = {
313 313 'hg': 'extensions_largefiles',
314 314 'git': 'vcs_git_lfs_enabled'
315 315 }
316 316
317 317 lf_key_for_vcs = lf_key_for_vcs_map.get(target_repo.repo_type)
318 318
319 319 if lf_key_for_vcs:
320 320 lf_enabled = self._get_repo_setting(target_repo, lf_key_for_vcs)
321 321
322 322 return lf_enabled
323 323
324 324 @LoginRequired()
325 325 @HasRepoPermissionAnyDecorator(
326 326 'repository.read', 'repository.write', 'repository.admin')
327 327 @view_config(
328 328 route_name='repo_archivefile', request_method='GET',
329 329 renderer=None)
330 330 def repo_archivefile(self):
331 331 # archive cache config
332 332 from rhodecode import CONFIG
333 333 _ = self.request.translate
334 334 self.load_default_context()
335 335 default_at_path = '/'
336 336 fname = self.request.matchdict['fname']
337 337 subrepos = self.request.GET.get('subrepos') == 'true'
338 338 at_path = self.request.GET.get('at_path') or default_at_path
339 339
340 340 if not self.db_repo.enable_downloads:
341 341 return Response(_('Downloads disabled'))
342 342
343 343 try:
344 344 commit_id, ext, fileformat, content_type = \
345 345 self._get_archive_spec(fname)
346 346 except ValueError:
347 347 return Response(_('Unknown archive type for: `{}`').format(
348 348 h.escape(fname)))
349 349
350 350 try:
351 351 commit = self.rhodecode_vcs_repo.get_commit(commit_id)
352 352 except CommitDoesNotExistError:
353 353 return Response(_('Unknown commit_id {}').format(
354 354 h.escape(commit_id)))
355 355 except EmptyRepositoryError:
356 356 return Response(_('Empty repository'))
357 357
358 358 try:
359 359 at_path = commit.get_node(at_path).path or default_at_path
360 360 except Exception:
361 361 return Response(_('No node at path {} for this repository').format(at_path))
362 362
363 363 path_sha = sha1(at_path)[:8]
364 364
365 365 # original backward compat name of archive
366 366 clean_name = safe_str(self.db_repo_name.replace('/', '_'))
367 367 short_sha = safe_str(commit.short_id)
368 368
369 369 if at_path == default_at_path:
370 370 archive_name = '{}-{}{}{}'.format(
371 371 clean_name,
372 372 '-sub' if subrepos else '',
373 373 short_sha,
374 374 ext)
375 375 # custom path and new name
376 376 else:
377 377 archive_name = '{}-{}{}-{}{}'.format(
378 378 clean_name,
379 379 '-sub' if subrepos else '',
380 380 short_sha,
381 381 path_sha,
382 382 ext)
383 383
384 384 use_cached_archive = False
385 385 archive_cache_enabled = CONFIG.get(
386 386 'archive_cache_dir') and not self.request.GET.get('no_cache')
387 387 cached_archive_path = None
388 388
389 389 if archive_cache_enabled:
390 390 # check if we it's ok to write
391 391 if not os.path.isdir(CONFIG['archive_cache_dir']):
392 392 os.makedirs(CONFIG['archive_cache_dir'])
393 393 cached_archive_path = os.path.join(
394 394 CONFIG['archive_cache_dir'], archive_name)
395 395 if os.path.isfile(cached_archive_path):
396 396 log.debug('Found cached archive in %s', cached_archive_path)
397 397 fd, archive = None, cached_archive_path
398 398 use_cached_archive = True
399 399 else:
400 400 log.debug('Archive %s is not yet cached', archive_name)
401 401
402 402 if not use_cached_archive:
403 403 # generate new archive
404 404 fd, archive = tempfile.mkstemp()
405 405 log.debug('Creating new temp archive in %s', archive)
406 406 try:
407 407 commit.archive_repo(archive, kind=fileformat, subrepos=subrepos,
408 408 archive_at_path=at_path)
409 409 except ImproperArchiveTypeError:
410 410 return _('Unknown archive type')
411 411 if archive_cache_enabled:
412 412 # if we generated the archive and we have cache enabled
413 413 # let's use this for future
414 414 log.debug('Storing new archive in %s', cached_archive_path)
415 415 shutil.move(archive, cached_archive_path)
416 416 archive = cached_archive_path
417 417
418 418 # store download action
419 419 audit_logger.store_web(
420 420 'repo.archive.download', action_data={
421 421 'user_agent': self.request.user_agent,
422 422 'archive_name': archive_name,
423 423 'archive_spec': fname,
424 424 'archive_cached': use_cached_archive},
425 425 user=self._rhodecode_user,
426 426 repo=self.db_repo,
427 427 commit=True
428 428 )
429 429
430 430 def get_chunked_archive(archive_path):
431 431 with open(archive_path, 'rb') as stream:
432 432 while True:
433 433 data = stream.read(16 * 1024)
434 434 if not data:
435 435 if fd: # fd means we used temporary file
436 436 os.close(fd)
437 437 if not archive_cache_enabled:
438 438 log.debug('Destroying temp archive %s', archive_path)
439 439 os.remove(archive_path)
440 440 break
441 441 yield data
442 442
443 443 response = Response(app_iter=get_chunked_archive(archive))
444 444 response.content_disposition = str(
445 445 'attachment; filename=%s' % archive_name)
446 446 response.content_type = str(content_type)
447 447
448 448 return response
449 449
450 450 def _get_file_node(self, commit_id, f_path):
451 451 if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]:
452 452 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
453 453 try:
454 454 node = commit.get_node(f_path)
455 455 if node.is_dir():
456 456 raise NodeError('%s path is a %s not a file'
457 457 % (node, type(node)))
458 458 except NodeDoesNotExistError:
459 459 commit = EmptyCommit(
460 460 commit_id=commit_id,
461 461 idx=commit.idx,
462 462 repo=commit.repository,
463 463 alias=commit.repository.alias,
464 464 message=commit.message,
465 465 author=commit.author,
466 466 date=commit.date)
467 467 node = FileNode(f_path, '', commit=commit)
468 468 else:
469 469 commit = EmptyCommit(
470 470 repo=self.rhodecode_vcs_repo,
471 471 alias=self.rhodecode_vcs_repo.alias)
472 472 node = FileNode(f_path, '', commit=commit)
473 473 return node
474 474
475 475 @LoginRequired()
476 476 @HasRepoPermissionAnyDecorator(
477 477 'repository.read', 'repository.write', 'repository.admin')
478 478 @view_config(
479 479 route_name='repo_files_diff', request_method='GET',
480 480 renderer=None)
481 481 def repo_files_diff(self):
482 482 c = self.load_default_context()
483 483 f_path = self._get_f_path(self.request.matchdict)
484 484 diff1 = self.request.GET.get('diff1', '')
485 485 diff2 = self.request.GET.get('diff2', '')
486 486
487 487 path1, diff1 = parse_path_ref(diff1, default_path=f_path)
488 488
489 489 ignore_whitespace = str2bool(self.request.GET.get('ignorews'))
490 490 line_context = self.request.GET.get('context', 3)
491 491
492 492 if not any((diff1, diff2)):
493 493 h.flash(
494 494 'Need query parameter "diff1" or "diff2" to generate a diff.',
495 495 category='error')
496 496 raise HTTPBadRequest()
497 497
498 498 c.action = self.request.GET.get('diff')
499 499 if c.action not in ['download', 'raw']:
500 500 compare_url = h.route_path(
501 501 'repo_compare',
502 502 repo_name=self.db_repo_name,
503 503 source_ref_type='rev',
504 504 source_ref=diff1,
505 505 target_repo=self.db_repo_name,
506 506 target_ref_type='rev',
507 507 target_ref=diff2,
508 508 _query=dict(f_path=f_path))
509 509 # redirect to new view if we render diff
510 510 raise HTTPFound(compare_url)
511 511
512 512 try:
513 513 node1 = self._get_file_node(diff1, path1)
514 514 node2 = self._get_file_node(diff2, f_path)
515 515 except (RepositoryError, NodeError):
516 516 log.exception("Exception while trying to get node from repository")
517 517 raise HTTPFound(
518 518 h.route_path('repo_files', repo_name=self.db_repo_name,
519 519 commit_id='tip', f_path=f_path))
520 520
521 521 if all(isinstance(node.commit, EmptyCommit)
522 522 for node in (node1, node2)):
523 523 raise HTTPNotFound()
524 524
525 525 c.commit_1 = node1.commit
526 526 c.commit_2 = node2.commit
527 527
528 528 if c.action == 'download':
529 529 _diff = diffs.get_gitdiff(node1, node2,
530 530 ignore_whitespace=ignore_whitespace,
531 531 context=line_context)
532 532 diff = diffs.DiffProcessor(_diff, format='gitdiff')
533 533
534 534 response = Response(self.path_filter.get_raw_patch(diff))
535 535 response.content_type = 'text/plain'
536 536 response.content_disposition = (
537 537 'attachment; filename=%s_%s_vs_%s.diff' % (f_path, diff1, diff2)
538 538 )
539 539 charset = self._get_default_encoding(c)
540 540 if charset:
541 541 response.charset = charset
542 542 return response
543 543
544 544 elif c.action == 'raw':
545 545 _diff = diffs.get_gitdiff(node1, node2,
546 546 ignore_whitespace=ignore_whitespace,
547 547 context=line_context)
548 548 diff = diffs.DiffProcessor(_diff, format='gitdiff')
549 549
550 550 response = Response(self.path_filter.get_raw_patch(diff))
551 551 response.content_type = 'text/plain'
552 552 charset = self._get_default_encoding(c)
553 553 if charset:
554 554 response.charset = charset
555 555 return response
556 556
557 557 # in case we ever end up here
558 558 raise HTTPNotFound()
559 559
560 560 @LoginRequired()
561 561 @HasRepoPermissionAnyDecorator(
562 562 'repository.read', 'repository.write', 'repository.admin')
563 563 @view_config(
564 564 route_name='repo_files_diff_2way_redirect', request_method='GET',
565 565 renderer=None)
566 566 def repo_files_diff_2way_redirect(self):
567 567 """
568 568 Kept only to make OLD links work
569 569 """
570 570 f_path = self._get_f_path_unchecked(self.request.matchdict)
571 571 diff1 = self.request.GET.get('diff1', '')
572 572 diff2 = self.request.GET.get('diff2', '')
573 573
574 574 if not any((diff1, diff2)):
575 575 h.flash(
576 576 'Need query parameter "diff1" or "diff2" to generate a diff.',
577 577 category='error')
578 578 raise HTTPBadRequest()
579 579
580 580 compare_url = h.route_path(
581 581 'repo_compare',
582 582 repo_name=self.db_repo_name,
583 583 source_ref_type='rev',
584 584 source_ref=diff1,
585 585 target_ref_type='rev',
586 586 target_ref=diff2,
587 587 _query=dict(f_path=f_path, diffmode='sideside',
588 588 target_repo=self.db_repo_name,))
589 589 raise HTTPFound(compare_url)
590 590
591 591 @LoginRequired()
592 @view_config(
593 route_name='repo_files:default_commit', request_method='GET',
594 renderer=None)
595 def repo_files_default(self):
596 c = self.load_default_context()
597 ref_name = c.rhodecode_db_repo.landing_ref_name
598 landing_url = h.repo_files_by_ref_url(
599 c.rhodecode_db_repo.repo_name,
600 c.rhodecode_db_repo.repo_type,
601 f_path='',
602 ref_name=ref_name,
603 commit_id='tip',
604 query=dict(at=ref_name)
605 )
606
607 raise HTTPFound(landing_url)
608
609 @LoginRequired()
592 610 @HasRepoPermissionAnyDecorator(
593 611 'repository.read', 'repository.write', 'repository.admin')
594 612 @view_config(
595 613 route_name='repo_files', request_method='GET',
596 614 renderer=None)
597 615 @view_config(
598 616 route_name='repo_files:default_path', request_method='GET',
599 617 renderer=None)
600 618 @view_config(
601 route_name='repo_files:default_commit', request_method='GET',
602 renderer=None)
603 @view_config(
604 619 route_name='repo_files:rendered', request_method='GET',
605 620 renderer=None)
606 621 @view_config(
607 622 route_name='repo_files:annotated', request_method='GET',
608 623 renderer=None)
609 624 def repo_files(self):
610 625 c = self.load_default_context()
611 626
612 627 view_name = getattr(self.request.matched_route, 'name', None)
613 628
614 629 c.annotate = view_name == 'repo_files:annotated'
615 630 # default is false, but .rst/.md files later are auto rendered, we can
616 631 # overwrite auto rendering by setting this GET flag
617 632 c.renderer = view_name == 'repo_files:rendered' or \
618 633 not self.request.GET.get('no-render', False)
619 634
620 635 commit_id, f_path = self._get_commit_and_path()
621 636
622 637 c.commit = self._get_commit_or_redirect(commit_id)
623 638 c.branch = self.request.GET.get('branch', None)
624 639 c.f_path = f_path
625 640 at_rev = self.request.GET.get('at')
626 641
627 642 # prev link
628 643 try:
629 644 prev_commit = c.commit.prev(c.branch)
630 645 c.prev_commit = prev_commit
631 646 c.url_prev = h.route_path(
632 647 'repo_files', repo_name=self.db_repo_name,
633 648 commit_id=prev_commit.raw_id, f_path=f_path)
634 649 if c.branch:
635 650 c.url_prev += '?branch=%s' % c.branch
636 651 except (CommitDoesNotExistError, VCSError):
637 652 c.url_prev = '#'
638 653 c.prev_commit = EmptyCommit()
639 654
640 655 # next link
641 656 try:
642 657 next_commit = c.commit.next(c.branch)
643 658 c.next_commit = next_commit
644 659 c.url_next = h.route_path(
645 660 'repo_files', repo_name=self.db_repo_name,
646 661 commit_id=next_commit.raw_id, f_path=f_path)
647 662 if c.branch:
648 663 c.url_next += '?branch=%s' % c.branch
649 664 except (CommitDoesNotExistError, VCSError):
650 665 c.url_next = '#'
651 666 c.next_commit = EmptyCommit()
652 667
653 668 # files or dirs
654 669 try:
655 670 c.file = c.commit.get_node(f_path)
656 671 c.file_author = True
657 672 c.file_tree = ''
658 673
659 674 # load file content
660 675 if c.file.is_file():
661 676 c.lf_node = {}
662 677
663 678 has_lf_enabled = self._is_lf_enabled(self.db_repo)
664 679 if has_lf_enabled:
665 680 c.lf_node = c.file.get_largefile_node()
666 681
667 682 c.file_source_page = 'true'
668 683 c.file_last_commit = c.file.last_commit
669 684
670 685 c.file_size_too_big = c.file.size > c.visual.cut_off_limit_file
671 686
672 687 if not (c.file_size_too_big or c.file.is_binary):
673 688 if c.annotate: # annotation has precedence over renderer
674 689 c.annotated_lines = filenode_as_annotated_lines_tokens(
675 690 c.file
676 691 )
677 692 else:
678 693 c.renderer = (
679 694 c.renderer and h.renderer_from_filename(c.file.path)
680 695 )
681 696 if not c.renderer:
682 697 c.lines = filenode_as_lines_tokens(c.file)
683 698
684 699 _branch_name, _sha_commit_id, is_head = self._is_valid_head(
685 700 commit_id, self.rhodecode_vcs_repo)
686 701 c.on_branch_head = is_head
687 702
688 703 branch = c.commit.branch if (
689 704 c.commit.branch and '/' not in c.commit.branch) else None
690 705 c.branch_or_raw_id = branch or c.commit.raw_id
691 706 c.branch_name = c.commit.branch or h.short_id(c.commit.raw_id)
692 707
693 708 author = c.file_last_commit.author
694 709 c.authors = [[
695 710 h.email(author),
696 711 h.person(author, 'username_or_name_or_email'),
697 712 1
698 713 ]]
699 714
700 715 else: # load tree content at path
701 716 c.file_source_page = 'false'
702 717 c.authors = []
703 718 # this loads a simple tree without metadata to speed things up
704 719 # later via ajax we call repo_nodetree_full and fetch whole
705 720 c.file_tree = self._get_tree_at_commit(c, c.commit.raw_id, f_path, at_rev=at_rev)
706 721
707 722 c.readme_data, c.readme_file = \
708 723 self._get_readme_data(self.db_repo, c.visual.default_renderer,
709 724 c.commit.raw_id, f_path)
710 725
711 726 except RepositoryError as e:
712 727 h.flash(safe_str(h.escape(e)), category='error')
713 728 raise HTTPNotFound()
714 729
715 730 if self.request.environ.get('HTTP_X_PJAX'):
716 731 html = render('rhodecode:templates/files/files_pjax.mako',
717 732 self._get_template_context(c), self.request)
718 733 else:
719 734 html = render('rhodecode:templates/files/files.mako',
720 735 self._get_template_context(c), self.request)
721 736 return Response(html)
722 737
723 738 @HasRepoPermissionAnyDecorator(
724 739 'repository.read', 'repository.write', 'repository.admin')
725 740 @view_config(
726 741 route_name='repo_files:annotated_previous', request_method='GET',
727 742 renderer=None)
728 743 def repo_files_annotated_previous(self):
729 744 self.load_default_context()
730 745
731 746 commit_id, f_path = self._get_commit_and_path()
732 747 commit = self._get_commit_or_redirect(commit_id)
733 748 prev_commit_id = commit.raw_id
734 749 line_anchor = self.request.GET.get('line_anchor')
735 750 is_file = False
736 751 try:
737 752 _file = commit.get_node(f_path)
738 753 is_file = _file.is_file()
739 754 except (NodeDoesNotExistError, CommitDoesNotExistError, VCSError):
740 755 pass
741 756
742 757 if is_file:
743 758 history = commit.get_path_history(f_path)
744 759 prev_commit_id = history[1].raw_id \
745 760 if len(history) > 1 else prev_commit_id
746 761 prev_url = h.route_path(
747 762 'repo_files:annotated', repo_name=self.db_repo_name,
748 763 commit_id=prev_commit_id, f_path=f_path,
749 764 _anchor='L{}'.format(line_anchor))
750 765
751 766 raise HTTPFound(prev_url)
752 767
753 768 @LoginRequired()
754 769 @HasRepoPermissionAnyDecorator(
755 770 'repository.read', 'repository.write', 'repository.admin')
756 771 @view_config(
757 772 route_name='repo_nodetree_full', request_method='GET',
758 773 renderer=None, xhr=True)
759 774 @view_config(
760 775 route_name='repo_nodetree_full:default_path', request_method='GET',
761 776 renderer=None, xhr=True)
762 777 def repo_nodetree_full(self):
763 778 """
764 779 Returns rendered html of file tree that contains commit date,
765 780 author, commit_id for the specified combination of
766 781 repo, commit_id and file path
767 782 """
768 783 c = self.load_default_context()
769 784
770 785 commit_id, f_path = self._get_commit_and_path()
771 786 commit = self._get_commit_or_redirect(commit_id)
772 787 try:
773 788 dir_node = commit.get_node(f_path)
774 789 except RepositoryError as e:
775 790 return Response('error: {}'.format(h.escape(safe_str(e))))
776 791
777 792 if dir_node.is_file():
778 793 return Response('')
779 794
780 795 c.file = dir_node
781 796 c.commit = commit
782 797 at_rev = self.request.GET.get('at')
783 798
784 799 html = self._get_tree_at_commit(
785 800 c, commit.raw_id, dir_node.path, full_load=True, at_rev=at_rev)
786 801
787 802 return Response(html)
788 803
789 804 def _get_attachement_headers(self, f_path):
790 805 f_name = safe_str(f_path.split(Repository.NAME_SEP)[-1])
791 806 safe_path = f_name.replace('"', '\\"')
792 807 encoded_path = urllib.quote(f_name)
793 808
794 809 return "attachment; " \
795 810 "filename=\"{}\"; " \
796 811 "filename*=UTF-8\'\'{}".format(safe_path, encoded_path)
797 812
798 813 @LoginRequired()
799 814 @HasRepoPermissionAnyDecorator(
800 815 'repository.read', 'repository.write', 'repository.admin')
801 816 @view_config(
802 817 route_name='repo_file_raw', request_method='GET',
803 818 renderer=None)
804 819 def repo_file_raw(self):
805 820 """
806 821 Action for show as raw, some mimetypes are "rendered",
807 822 those include images, icons.
808 823 """
809 824 c = self.load_default_context()
810 825
811 826 commit_id, f_path = self._get_commit_and_path()
812 827 commit = self._get_commit_or_redirect(commit_id)
813 828 file_node = self._get_filenode_or_redirect(commit, f_path)
814 829
815 830 raw_mimetype_mapping = {
816 831 # map original mimetype to a mimetype used for "show as raw"
817 832 # you can also provide a content-disposition to override the
818 833 # default "attachment" disposition.
819 834 # orig_type: (new_type, new_dispo)
820 835
821 836 # show images inline:
822 837 # Do not re-add SVG: it is unsafe and permits XSS attacks. One can
823 838 # for example render an SVG with javascript inside or even render
824 839 # HTML.
825 840 'image/x-icon': ('image/x-icon', 'inline'),
826 841 'image/png': ('image/png', 'inline'),
827 842 'image/gif': ('image/gif', 'inline'),
828 843 'image/jpeg': ('image/jpeg', 'inline'),
829 844 'application/pdf': ('application/pdf', 'inline'),
830 845 }
831 846
832 847 mimetype = file_node.mimetype
833 848 try:
834 849 mimetype, disposition = raw_mimetype_mapping[mimetype]
835 850 except KeyError:
836 851 # we don't know anything special about this, handle it safely
837 852 if file_node.is_binary:
838 853 # do same as download raw for binary files
839 854 mimetype, disposition = 'application/octet-stream', 'attachment'
840 855 else:
841 856 # do not just use the original mimetype, but force text/plain,
842 857 # otherwise it would serve text/html and that might be unsafe.
843 858 # Note: underlying vcs library fakes text/plain mimetype if the
844 859 # mimetype can not be determined and it thinks it is not
845 860 # binary.This might lead to erroneous text display in some
846 861 # cases, but helps in other cases, like with text files
847 862 # without extension.
848 863 mimetype, disposition = 'text/plain', 'inline'
849 864
850 865 if disposition == 'attachment':
851 866 disposition = self._get_attachement_headers(f_path)
852 867
853 868 stream_content = file_node.stream_bytes()
854 869
855 870 response = Response(app_iter=stream_content)
856 871 response.content_disposition = disposition
857 872 response.content_type = mimetype
858 873
859 874 charset = self._get_default_encoding(c)
860 875 if charset:
861 876 response.charset = charset
862 877
863 878 return response
864 879
865 880 @LoginRequired()
866 881 @HasRepoPermissionAnyDecorator(
867 882 'repository.read', 'repository.write', 'repository.admin')
868 883 @view_config(
869 884 route_name='repo_file_download', request_method='GET',
870 885 renderer=None)
871 886 @view_config(
872 887 route_name='repo_file_download:legacy', request_method='GET',
873 888 renderer=None)
874 889 def repo_file_download(self):
875 890 c = self.load_default_context()
876 891
877 892 commit_id, f_path = self._get_commit_and_path()
878 893 commit = self._get_commit_or_redirect(commit_id)
879 894 file_node = self._get_filenode_or_redirect(commit, f_path)
880 895
881 896 if self.request.GET.get('lf'):
882 897 # only if lf get flag is passed, we download this file
883 898 # as LFS/Largefile
884 899 lf_node = file_node.get_largefile_node()
885 900 if lf_node:
886 901 # overwrite our pointer with the REAL large-file
887 902 file_node = lf_node
888 903
889 904 disposition = self._get_attachement_headers(f_path)
890 905
891 906 stream_content = file_node.stream_bytes()
892 907
893 908 response = Response(app_iter=stream_content)
894 909 response.content_disposition = disposition
895 910 response.content_type = file_node.mimetype
896 911
897 912 charset = self._get_default_encoding(c)
898 913 if charset:
899 914 response.charset = charset
900 915
901 916 return response
902 917
903 918 def _get_nodelist_at_commit(self, repo_name, repo_id, commit_id, f_path):
904 919
905 920 cache_seconds = safe_int(
906 921 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
907 922 cache_on = cache_seconds > 0
908 923 log.debug(
909 924 'Computing FILE SEARCH for repo_id %s commit_id `%s` and path `%s`'
910 925 'with caching: %s[TTL: %ss]' % (
911 926 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
912 927
913 928 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
914 929 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
915 930
916 931 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid, condition=cache_on)
917 932 def compute_file_search(_name_hash, _repo_id, _commit_id, _f_path):
918 933 log.debug('Generating cached nodelist for repo_id:%s, %s, %s',
919 934 _repo_id, commit_id, f_path)
920 935 try:
921 936 _d, _f = ScmModel().get_quick_filter_nodes(repo_name, _commit_id, _f_path)
922 937 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
923 938 log.exception(safe_str(e))
924 939 h.flash(safe_str(h.escape(e)), category='error')
925 940 raise HTTPFound(h.route_path(
926 941 'repo_files', repo_name=self.db_repo_name,
927 942 commit_id='tip', f_path='/'))
928 943
929 944 return _d + _f
930 945
931 946 result = compute_file_search(self.db_repo.repo_name_hash, self.db_repo.repo_id,
932 947 commit_id, f_path)
933 948 return filter(lambda n: self.path_filter.path_access_allowed(n['name']), result)
934 949
935 950 @LoginRequired()
936 951 @HasRepoPermissionAnyDecorator(
937 952 'repository.read', 'repository.write', 'repository.admin')
938 953 @view_config(
939 954 route_name='repo_files_nodelist', request_method='GET',
940 955 renderer='json_ext', xhr=True)
941 956 def repo_nodelist(self):
942 957 self.load_default_context()
943 958
944 959 commit_id, f_path = self._get_commit_and_path()
945 960 commit = self._get_commit_or_redirect(commit_id)
946 961
947 962 metadata = self._get_nodelist_at_commit(
948 963 self.db_repo_name, self.db_repo.repo_id, commit.raw_id, f_path)
949 964 return {'nodes': metadata}
950 965
951 966 def _create_references(self, branches_or_tags, symbolic_reference, f_path, ref_type):
952 967 items = []
953 968 for name, commit_id in branches_or_tags.items():
954 969 sym_ref = symbolic_reference(commit_id, name, f_path, ref_type)
955 970 items.append((sym_ref, name, ref_type))
956 971 return items
957 972
958 973 def _symbolic_reference(self, commit_id, name, f_path, ref_type):
959 974 return commit_id
960 975
961 976 def _symbolic_reference_svn(self, commit_id, name, f_path, ref_type):
962 977 return commit_id
963 978
964 979 # NOTE(dan): old code we used in "diff" mode compare
965 980 new_f_path = vcspath.join(name, f_path)
966 981 return u'%s@%s' % (new_f_path, commit_id)
967 982
968 983 def _get_node_history(self, commit_obj, f_path, commits=None):
969 984 """
970 985 get commit history for given node
971 986
972 987 :param commit_obj: commit to calculate history
973 988 :param f_path: path for node to calculate history for
974 989 :param commits: if passed don't calculate history and take
975 990 commits defined in this list
976 991 """
977 992 _ = self.request.translate
978 993
979 994 # calculate history based on tip
980 995 tip = self.rhodecode_vcs_repo.get_commit()
981 996 if commits is None:
982 997 pre_load = ["author", "branch"]
983 998 try:
984 999 commits = tip.get_path_history(f_path, pre_load=pre_load)
985 1000 except (NodeDoesNotExistError, CommitError):
986 1001 # this node is not present at tip!
987 1002 commits = commit_obj.get_path_history(f_path, pre_load=pre_load)
988 1003
989 1004 history = []
990 1005 commits_group = ([], _("Changesets"))
991 1006 for commit in commits:
992 1007 branch = ' (%s)' % commit.branch if commit.branch else ''
993 1008 n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch)
994 1009 commits_group[0].append((commit.raw_id, n_desc, 'sha'))
995 1010 history.append(commits_group)
996 1011
997 1012 symbolic_reference = self._symbolic_reference
998 1013
999 1014 if self.rhodecode_vcs_repo.alias == 'svn':
1000 1015 adjusted_f_path = RepoFilesView.adjust_file_path_for_svn(
1001 1016 f_path, self.rhodecode_vcs_repo)
1002 1017 if adjusted_f_path != f_path:
1003 1018 log.debug(
1004 1019 'Recognized svn tag or branch in file "%s", using svn '
1005 1020 'specific symbolic references', f_path)
1006 1021 f_path = adjusted_f_path
1007 1022 symbolic_reference = self._symbolic_reference_svn
1008 1023
1009 1024 branches = self._create_references(
1010 1025 self.rhodecode_vcs_repo.branches, symbolic_reference, f_path, 'branch')
1011 1026 branches_group = (branches, _("Branches"))
1012 1027
1013 1028 tags = self._create_references(
1014 1029 self.rhodecode_vcs_repo.tags, symbolic_reference, f_path, 'tag')
1015 1030 tags_group = (tags, _("Tags"))
1016 1031
1017 1032 history.append(branches_group)
1018 1033 history.append(tags_group)
1019 1034
1020 1035 return history, commits
1021 1036
1022 1037 @LoginRequired()
1023 1038 @HasRepoPermissionAnyDecorator(
1024 1039 'repository.read', 'repository.write', 'repository.admin')
1025 1040 @view_config(
1026 1041 route_name='repo_file_history', request_method='GET',
1027 1042 renderer='json_ext')
1028 1043 def repo_file_history(self):
1029 1044 self.load_default_context()
1030 1045
1031 1046 commit_id, f_path = self._get_commit_and_path()
1032 1047 commit = self._get_commit_or_redirect(commit_id)
1033 1048 file_node = self._get_filenode_or_redirect(commit, f_path)
1034 1049
1035 1050 if file_node.is_file():
1036 1051 file_history, _hist = self._get_node_history(commit, f_path)
1037 1052
1038 1053 res = []
1039 1054 for section_items, section in file_history:
1040 1055 items = []
1041 1056 for obj_id, obj_text, obj_type in section_items:
1042 1057 at_rev = ''
1043 1058 if obj_type in ['branch', 'bookmark', 'tag']:
1044 1059 at_rev = obj_text
1045 1060 entry = {
1046 1061 'id': obj_id,
1047 1062 'text': obj_text,
1048 1063 'type': obj_type,
1049 1064 'at_rev': at_rev
1050 1065 }
1051 1066
1052 1067 items.append(entry)
1053 1068
1054 1069 res.append({
1055 1070 'text': section,
1056 1071 'children': items
1057 1072 })
1058 1073
1059 1074 data = {
1060 1075 'more': False,
1061 1076 'results': res
1062 1077 }
1063 1078 return data
1064 1079
1065 1080 log.warning('Cannot fetch history for directory')
1066 1081 raise HTTPBadRequest()
1067 1082
1068 1083 @LoginRequired()
1069 1084 @HasRepoPermissionAnyDecorator(
1070 1085 'repository.read', 'repository.write', 'repository.admin')
1071 1086 @view_config(
1072 1087 route_name='repo_file_authors', request_method='GET',
1073 1088 renderer='rhodecode:templates/files/file_authors_box.mako')
1074 1089 def repo_file_authors(self):
1075 1090 c = self.load_default_context()
1076 1091
1077 1092 commit_id, f_path = self._get_commit_and_path()
1078 1093 commit = self._get_commit_or_redirect(commit_id)
1079 1094 file_node = self._get_filenode_or_redirect(commit, f_path)
1080 1095
1081 1096 if not file_node.is_file():
1082 1097 raise HTTPBadRequest()
1083 1098
1084 1099 c.file_last_commit = file_node.last_commit
1085 1100 if self.request.GET.get('annotate') == '1':
1086 1101 # use _hist from annotation if annotation mode is on
1087 1102 commit_ids = set(x[1] for x in file_node.annotate)
1088 1103 _hist = (
1089 1104 self.rhodecode_vcs_repo.get_commit(commit_id)
1090 1105 for commit_id in commit_ids)
1091 1106 else:
1092 1107 _f_history, _hist = self._get_node_history(commit, f_path)
1093 1108 c.file_author = False
1094 1109
1095 1110 unique = collections.OrderedDict()
1096 1111 for commit in _hist:
1097 1112 author = commit.author
1098 1113 if author not in unique:
1099 1114 unique[commit.author] = [
1100 1115 h.email(author),
1101 1116 h.person(author, 'username_or_name_or_email'),
1102 1117 1 # counter
1103 1118 ]
1104 1119
1105 1120 else:
1106 1121 # increase counter
1107 1122 unique[commit.author][2] += 1
1108 1123
1109 1124 c.authors = [val for val in unique.values()]
1110 1125
1111 1126 return self._get_template_context(c)
1112 1127
1113 1128 @LoginRequired()
1114 1129 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1115 1130 @view_config(
1116 1131 route_name='repo_files_check_head', request_method='POST',
1117 1132 renderer='json_ext', xhr=True)
1118 1133 def repo_files_check_head(self):
1119 1134 self.load_default_context()
1120 1135
1121 1136 commit_id, f_path = self._get_commit_and_path()
1122 1137 _branch_name, _sha_commit_id, is_head = \
1123 1138 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1124 1139
1125 1140 new_path = self.request.POST.get('path')
1126 1141 operation = self.request.POST.get('operation')
1127 1142 path_exist = ''
1128 1143
1129 1144 if new_path and operation in ['create', 'upload']:
1130 1145 new_f_path = os.path.join(f_path.lstrip('/'), new_path)
1131 1146 try:
1132 1147 commit_obj = self.rhodecode_vcs_repo.get_commit(commit_id)
1133 1148 # NOTE(dan): construct whole path without leading /
1134 1149 file_node = commit_obj.get_node(new_f_path)
1135 1150 if file_node is not None:
1136 1151 path_exist = new_f_path
1137 1152 except EmptyRepositoryError:
1138 1153 pass
1139 1154 except Exception:
1140 1155 pass
1141 1156
1142 1157 return {
1143 1158 'branch': _branch_name,
1144 1159 'sha': _sha_commit_id,
1145 1160 'is_head': is_head,
1146 1161 'path_exists': path_exist
1147 1162 }
1148 1163
1149 1164 @LoginRequired()
1150 1165 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1151 1166 @view_config(
1152 1167 route_name='repo_files_remove_file', request_method='GET',
1153 1168 renderer='rhodecode:templates/files/files_delete.mako')
1154 1169 def repo_files_remove_file(self):
1155 1170 _ = self.request.translate
1156 1171 c = self.load_default_context()
1157 1172 commit_id, f_path = self._get_commit_and_path()
1158 1173
1159 1174 self._ensure_not_locked()
1160 1175 _branch_name, _sha_commit_id, is_head = \
1161 1176 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1162 1177
1163 1178 self.forbid_non_head(is_head, f_path)
1164 1179 self.check_branch_permission(_branch_name)
1165 1180
1166 1181 c.commit = self._get_commit_or_redirect(commit_id)
1167 1182 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1168 1183
1169 1184 c.default_message = _(
1170 1185 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1171 1186 c.f_path = f_path
1172 1187
1173 1188 return self._get_template_context(c)
1174 1189
1175 1190 @LoginRequired()
1176 1191 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1177 1192 @CSRFRequired()
1178 1193 @view_config(
1179 1194 route_name='repo_files_delete_file', request_method='POST',
1180 1195 renderer=None)
1181 1196 def repo_files_delete_file(self):
1182 1197 _ = self.request.translate
1183 1198
1184 1199 c = self.load_default_context()
1185 1200 commit_id, f_path = self._get_commit_and_path()
1186 1201
1187 1202 self._ensure_not_locked()
1188 1203 _branch_name, _sha_commit_id, is_head = \
1189 1204 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1190 1205
1191 1206 self.forbid_non_head(is_head, f_path)
1192 1207 self.check_branch_permission(_branch_name)
1193 1208
1194 1209 c.commit = self._get_commit_or_redirect(commit_id)
1195 1210 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1196 1211
1197 1212 c.default_message = _(
1198 1213 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1199 1214 c.f_path = f_path
1200 1215 node_path = f_path
1201 1216 author = self._rhodecode_db_user.full_contact
1202 1217 message = self.request.POST.get('message') or c.default_message
1203 1218 try:
1204 1219 nodes = {
1205 1220 node_path: {
1206 1221 'content': ''
1207 1222 }
1208 1223 }
1209 1224 ScmModel().delete_nodes(
1210 1225 user=self._rhodecode_db_user.user_id, repo=self.db_repo,
1211 1226 message=message,
1212 1227 nodes=nodes,
1213 1228 parent_commit=c.commit,
1214 1229 author=author,
1215 1230 )
1216 1231
1217 1232 h.flash(
1218 1233 _('Successfully deleted file `{}`').format(
1219 1234 h.escape(f_path)), category='success')
1220 1235 except Exception:
1221 1236 log.exception('Error during commit operation')
1222 1237 h.flash(_('Error occurred during commit'), category='error')
1223 1238 raise HTTPFound(
1224 1239 h.route_path('repo_commit', repo_name=self.db_repo_name,
1225 1240 commit_id='tip'))
1226 1241
1227 1242 @LoginRequired()
1228 1243 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1229 1244 @view_config(
1230 1245 route_name='repo_files_edit_file', request_method='GET',
1231 1246 renderer='rhodecode:templates/files/files_edit.mako')
1232 1247 def repo_files_edit_file(self):
1233 1248 _ = self.request.translate
1234 1249 c = self.load_default_context()
1235 1250 commit_id, f_path = self._get_commit_and_path()
1236 1251
1237 1252 self._ensure_not_locked()
1238 1253 _branch_name, _sha_commit_id, is_head = \
1239 1254 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1240 1255
1241 1256 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1242 1257 self.check_branch_permission(_branch_name, commit_id=commit_id)
1243 1258
1244 1259 c.commit = self._get_commit_or_redirect(commit_id)
1245 1260 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1246 1261
1247 1262 if c.file.is_binary:
1248 1263 files_url = h.route_path(
1249 1264 'repo_files',
1250 1265 repo_name=self.db_repo_name,
1251 1266 commit_id=c.commit.raw_id, f_path=f_path)
1252 1267 raise HTTPFound(files_url)
1253 1268
1254 1269 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1255 1270 c.f_path = f_path
1256 1271
1257 1272 return self._get_template_context(c)
1258 1273
1259 1274 @LoginRequired()
1260 1275 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1261 1276 @CSRFRequired()
1262 1277 @view_config(
1263 1278 route_name='repo_files_update_file', request_method='POST',
1264 1279 renderer=None)
1265 1280 def repo_files_update_file(self):
1266 1281 _ = self.request.translate
1267 1282 c = self.load_default_context()
1268 1283 commit_id, f_path = self._get_commit_and_path()
1269 1284
1270 1285 self._ensure_not_locked()
1271 1286
1272 1287 c.commit = self._get_commit_or_redirect(commit_id)
1273 1288 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1274 1289
1275 1290 if c.file.is_binary:
1276 1291 raise HTTPFound(h.route_path('repo_files', repo_name=self.db_repo_name,
1277 1292 commit_id=c.commit.raw_id, f_path=f_path))
1278 1293
1279 1294 _branch_name, _sha_commit_id, is_head = \
1280 1295 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1281 1296
1282 1297 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1283 1298 self.check_branch_permission(_branch_name, commit_id=commit_id)
1284 1299
1285 1300 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1286 1301 c.f_path = f_path
1287 1302
1288 1303 old_content = c.file.content
1289 1304 sl = old_content.splitlines(1)
1290 1305 first_line = sl[0] if sl else ''
1291 1306
1292 1307 r_post = self.request.POST
1293 1308 # line endings: 0 - Unix, 1 - Mac, 2 - DOS
1294 1309 line_ending_mode = detect_mode(first_line, 0)
1295 1310 content = convert_line_endings(r_post.get('content', ''), line_ending_mode)
1296 1311
1297 1312 message = r_post.get('message') or c.default_message
1298 1313 org_node_path = c.file.unicode_path
1299 1314 filename = r_post['filename']
1300 1315
1301 1316 root_path = c.file.dir_path
1302 1317 pure_path = self.create_pure_path(root_path, filename)
1303 1318 node_path = safe_unicode(bytes(pure_path))
1304 1319
1305 1320 default_redirect_url = h.route_path('repo_commit', repo_name=self.db_repo_name,
1306 1321 commit_id=commit_id)
1307 1322 if content == old_content and node_path == org_node_path:
1308 1323 h.flash(_('No changes detected on {}').format(h.escape(org_node_path)),
1309 1324 category='warning')
1310 1325 raise HTTPFound(default_redirect_url)
1311 1326
1312 1327 try:
1313 1328 mapping = {
1314 1329 org_node_path: {
1315 1330 'org_filename': org_node_path,
1316 1331 'filename': node_path,
1317 1332 'content': content,
1318 1333 'lexer': '',
1319 1334 'op': 'mod',
1320 1335 'mode': c.file.mode
1321 1336 }
1322 1337 }
1323 1338
1324 1339 commit = ScmModel().update_nodes(
1325 1340 user=self._rhodecode_db_user.user_id,
1326 1341 repo=self.db_repo,
1327 1342 message=message,
1328 1343 nodes=mapping,
1329 1344 parent_commit=c.commit,
1330 1345 )
1331 1346
1332 1347 h.flash(_('Successfully committed changes to file `{}`').format(
1333 1348 h.escape(f_path)), category='success')
1334 1349 default_redirect_url = h.route_path(
1335 1350 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1336 1351
1337 1352 except Exception:
1338 1353 log.exception('Error occurred during commit')
1339 1354 h.flash(_('Error occurred during commit'), category='error')
1340 1355
1341 1356 raise HTTPFound(default_redirect_url)
1342 1357
1343 1358 @LoginRequired()
1344 1359 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1345 1360 @view_config(
1346 1361 route_name='repo_files_add_file', request_method='GET',
1347 1362 renderer='rhodecode:templates/files/files_add.mako')
1348 1363 @view_config(
1349 1364 route_name='repo_files_upload_file', request_method='GET',
1350 1365 renderer='rhodecode:templates/files/files_upload.mako')
1351 1366 def repo_files_add_file(self):
1352 1367 _ = self.request.translate
1353 1368 c = self.load_default_context()
1354 1369 commit_id, f_path = self._get_commit_and_path()
1355 1370
1356 1371 self._ensure_not_locked()
1357 1372
1358 1373 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1359 1374 if c.commit is None:
1360 1375 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1361 1376
1362 1377 if self.rhodecode_vcs_repo.is_empty():
1363 1378 # for empty repository we cannot check for current branch, we rely on
1364 1379 # c.commit.branch instead
1365 1380 _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True
1366 1381 else:
1367 1382 _branch_name, _sha_commit_id, is_head = \
1368 1383 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1369 1384
1370 1385 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1371 1386 self.check_branch_permission(_branch_name, commit_id=commit_id)
1372 1387
1373 1388 c.default_message = (_('Added file via RhodeCode Enterprise'))
1374 1389 c.f_path = f_path.lstrip('/') # ensure not relative path
1375 1390
1376 1391 return self._get_template_context(c)
1377 1392
1378 1393 @LoginRequired()
1379 1394 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1380 1395 @CSRFRequired()
1381 1396 @view_config(
1382 1397 route_name='repo_files_create_file', request_method='POST',
1383 1398 renderer=None)
1384 1399 def repo_files_create_file(self):
1385 1400 _ = self.request.translate
1386 1401 c = self.load_default_context()
1387 1402 commit_id, f_path = self._get_commit_and_path()
1388 1403
1389 1404 self._ensure_not_locked()
1390 1405
1391 1406 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1392 1407 if c.commit is None:
1393 1408 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1394 1409
1395 1410 # calculate redirect URL
1396 1411 if self.rhodecode_vcs_repo.is_empty():
1397 1412 default_redirect_url = h.route_path(
1398 1413 'repo_summary', repo_name=self.db_repo_name)
1399 1414 else:
1400 1415 default_redirect_url = h.route_path(
1401 1416 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1402 1417
1403 1418 if self.rhodecode_vcs_repo.is_empty():
1404 1419 # for empty repository we cannot check for current branch, we rely on
1405 1420 # c.commit.branch instead
1406 1421 _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True
1407 1422 else:
1408 1423 _branch_name, _sha_commit_id, is_head = \
1409 1424 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1410 1425
1411 1426 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1412 1427 self.check_branch_permission(_branch_name, commit_id=commit_id)
1413 1428
1414 1429 c.default_message = (_('Added file via RhodeCode Enterprise'))
1415 1430 c.f_path = f_path
1416 1431
1417 1432 r_post = self.request.POST
1418 1433 message = r_post.get('message') or c.default_message
1419 1434 filename = r_post.get('filename')
1420 1435 unix_mode = 0
1421 1436 content = convert_line_endings(r_post.get('content', ''), unix_mode)
1422 1437
1423 1438 if not filename:
1424 1439 # If there's no commit, redirect to repo summary
1425 1440 if type(c.commit) is EmptyCommit:
1426 1441 redirect_url = h.route_path(
1427 1442 'repo_summary', repo_name=self.db_repo_name)
1428 1443 else:
1429 1444 redirect_url = default_redirect_url
1430 1445 h.flash(_('No filename specified'), category='warning')
1431 1446 raise HTTPFound(redirect_url)
1432 1447
1433 1448 root_path = f_path
1434 1449 pure_path = self.create_pure_path(root_path, filename)
1435 1450 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1436 1451
1437 1452 author = self._rhodecode_db_user.full_contact
1438 1453 nodes = {
1439 1454 node_path: {
1440 1455 'content': content
1441 1456 }
1442 1457 }
1443 1458
1444 1459 try:
1445 1460
1446 1461 commit = ScmModel().create_nodes(
1447 1462 user=self._rhodecode_db_user.user_id,
1448 1463 repo=self.db_repo,
1449 1464 message=message,
1450 1465 nodes=nodes,
1451 1466 parent_commit=c.commit,
1452 1467 author=author,
1453 1468 )
1454 1469
1455 1470 h.flash(_('Successfully committed new file `{}`').format(
1456 1471 h.escape(node_path)), category='success')
1457 1472
1458 1473 default_redirect_url = h.route_path(
1459 1474 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1460 1475
1461 1476 except NonRelativePathError:
1462 1477 log.exception('Non Relative path found')
1463 1478 h.flash(_('The location specified must be a relative path and must not '
1464 1479 'contain .. in the path'), category='warning')
1465 1480 raise HTTPFound(default_redirect_url)
1466 1481 except (NodeError, NodeAlreadyExistsError) as e:
1467 1482 h.flash(_(h.escape(e)), category='error')
1468 1483 except Exception:
1469 1484 log.exception('Error occurred during commit')
1470 1485 h.flash(_('Error occurred during commit'), category='error')
1471 1486
1472 1487 raise HTTPFound(default_redirect_url)
1473 1488
1474 1489 @LoginRequired()
1475 1490 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1476 1491 @CSRFRequired()
1477 1492 @view_config(
1478 1493 route_name='repo_files_upload_file', request_method='POST',
1479 1494 renderer='json_ext')
1480 1495 def repo_files_upload_file(self):
1481 1496 _ = self.request.translate
1482 1497 c = self.load_default_context()
1483 1498 commit_id, f_path = self._get_commit_and_path()
1484 1499
1485 1500 self._ensure_not_locked()
1486 1501
1487 1502 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1488 1503 if c.commit is None:
1489 1504 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1490 1505
1491 1506 # calculate redirect URL
1492 1507 if self.rhodecode_vcs_repo.is_empty():
1493 1508 default_redirect_url = h.route_path(
1494 1509 'repo_summary', repo_name=self.db_repo_name)
1495 1510 else:
1496 1511 default_redirect_url = h.route_path(
1497 1512 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1498 1513
1499 1514 if self.rhodecode_vcs_repo.is_empty():
1500 1515 # for empty repository we cannot check for current branch, we rely on
1501 1516 # c.commit.branch instead
1502 1517 _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True
1503 1518 else:
1504 1519 _branch_name, _sha_commit_id, is_head = \
1505 1520 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1506 1521
1507 1522 error = self.forbid_non_head(is_head, f_path, json_mode=True)
1508 1523 if error:
1509 1524 return {
1510 1525 'error': error,
1511 1526 'redirect_url': default_redirect_url
1512 1527 }
1513 1528 error = self.check_branch_permission(_branch_name, json_mode=True)
1514 1529 if error:
1515 1530 return {
1516 1531 'error': error,
1517 1532 'redirect_url': default_redirect_url
1518 1533 }
1519 1534
1520 1535 c.default_message = (_('Uploaded file via RhodeCode Enterprise'))
1521 1536 c.f_path = f_path
1522 1537
1523 1538 r_post = self.request.POST
1524 1539
1525 1540 message = c.default_message
1526 1541 user_message = r_post.getall('message')
1527 1542 if isinstance(user_message, list) and user_message:
1528 1543 # we take the first from duplicated results if it's not empty
1529 1544 message = user_message[0] if user_message[0] else message
1530 1545
1531 1546 nodes = {}
1532 1547
1533 1548 for file_obj in r_post.getall('files_upload') or []:
1534 1549 content = file_obj.file
1535 1550 filename = file_obj.filename
1536 1551
1537 1552 root_path = f_path
1538 1553 pure_path = self.create_pure_path(root_path, filename)
1539 1554 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1540 1555
1541 1556 nodes[node_path] = {
1542 1557 'content': content
1543 1558 }
1544 1559
1545 1560 if not nodes:
1546 1561 error = 'missing files'
1547 1562 return {
1548 1563 'error': error,
1549 1564 'redirect_url': default_redirect_url
1550 1565 }
1551 1566
1552 1567 author = self._rhodecode_db_user.full_contact
1553 1568
1554 1569 try:
1555 1570 commit = ScmModel().create_nodes(
1556 1571 user=self._rhodecode_db_user.user_id,
1557 1572 repo=self.db_repo,
1558 1573 message=message,
1559 1574 nodes=nodes,
1560 1575 parent_commit=c.commit,
1561 1576 author=author,
1562 1577 )
1563 1578 if len(nodes) == 1:
1564 1579 flash_message = _('Successfully committed {} new files').format(len(nodes))
1565 1580 else:
1566 1581 flash_message = _('Successfully committed 1 new file')
1567 1582
1568 1583 h.flash(flash_message, category='success')
1569 1584
1570 1585 default_redirect_url = h.route_path(
1571 1586 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1572 1587
1573 1588 except NonRelativePathError:
1574 1589 log.exception('Non Relative path found')
1575 1590 error = _('The location specified must be a relative path and must not '
1576 1591 'contain .. in the path')
1577 1592 h.flash(error, category='warning')
1578 1593
1579 1594 return {
1580 1595 'error': error,
1581 1596 'redirect_url': default_redirect_url
1582 1597 }
1583 1598 except (NodeError, NodeAlreadyExistsError) as e:
1584 1599 error = h.escape(e)
1585 1600 h.flash(error, category='error')
1586 1601
1587 1602 return {
1588 1603 'error': error,
1589 1604 'redirect_url': default_redirect_url
1590 1605 }
1591 1606 except Exception:
1592 1607 log.exception('Error occurred during commit')
1593 1608 error = _('Error occurred during commit')
1594 1609 h.flash(error, category='error')
1595 1610 return {
1596 1611 'error': error,
1597 1612 'redirect_url': default_redirect_url
1598 1613 }
1599 1614
1600 1615 return {
1601 1616 'error': None,
1602 1617 'redirect_url': default_redirect_url
1603 1618 }
@@ -1,266 +1,266 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 import logging
22 22 import datetime
23 23 import formencode
24 24 import formencode.htmlfill
25 25
26 26 from pyramid.httpexceptions import HTTPFound
27 27 from pyramid.view import view_config
28 28 from pyramid.renderers import render
29 29 from pyramid.response import Response
30 30
31 31 from rhodecode import events
32 32 from rhodecode.apps._base import RepoAppView, DataGridAppView
33 33 from rhodecode.lib.auth import (
34 34 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
35 35 HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
36 36 import rhodecode.lib.helpers as h
37 37 from rhodecode.lib.celerylib.utils import get_task_id
38 38 from rhodecode.model.db import coalesce, or_, Repository, RepoGroup
39 39 from rhodecode.model.permission import PermissionModel
40 40 from rhodecode.model.repo import RepoModel
41 41 from rhodecode.model.forms import RepoForkForm
42 42 from rhodecode.model.scm import ScmModel, RepoGroupList
43 43 from rhodecode.lib.utils2 import safe_int, safe_unicode
44 44
45 45 log = logging.getLogger(__name__)
46 46
47 47
48 48 class RepoForksView(RepoAppView, DataGridAppView):
49 49
50 50 def load_default_context(self):
51 51 c = self._get_local_tmpl_context(include_app_defaults=True)
52 52 c.rhodecode_repo = self.rhodecode_vcs_repo
53 53
54 54 acl_groups = RepoGroupList(
55 55 RepoGroup.query().all(),
56 56 perm_set=['group.write', 'group.admin'])
57 57 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
58 58 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
59 59
60 60 c.personal_repo_group = c.rhodecode_user.personal_repo_group
61 61
62 62 return c
63 63
64 64 @LoginRequired()
65 65 @HasRepoPermissionAnyDecorator(
66 66 'repository.read', 'repository.write', 'repository.admin')
67 67 @view_config(
68 68 route_name='repo_forks_show_all', request_method='GET',
69 69 renderer='rhodecode:templates/forks/forks.mako')
70 70 def repo_forks_show_all(self):
71 71 c = self.load_default_context()
72 72 return self._get_template_context(c)
73 73
74 74 @LoginRequired()
75 75 @HasRepoPermissionAnyDecorator(
76 76 'repository.read', 'repository.write', 'repository.admin')
77 77 @view_config(
78 78 route_name='repo_forks_data', request_method='GET',
79 79 renderer='json_ext', xhr=True)
80 80 def repo_forks_data(self):
81 81 _ = self.request.translate
82 82 self.load_default_context()
83 83 column_map = {
84 84 'fork_name': 'repo_name',
85 85 'fork_date': 'created_on',
86 86 'last_activity': 'updated_on'
87 87 }
88 88 draw, start, limit = self._extract_chunk(self.request)
89 89 search_q, order_by, order_dir = self._extract_ordering(
90 90 self.request, column_map=column_map)
91 91
92 92 acl_check = HasRepoPermissionAny(
93 93 'repository.read', 'repository.write', 'repository.admin')
94 94 repo_id = self.db_repo.repo_id
95 95 allowed_ids = [-1]
96 96 for f in Repository.query().filter(Repository.fork_id == repo_id):
97 97 if acl_check(f.repo_name, 'get forks check'):
98 98 allowed_ids.append(f.repo_id)
99 99
100 100 forks_data_total_count = Repository.query()\
101 101 .filter(Repository.fork_id == repo_id)\
102 102 .filter(Repository.repo_id.in_(allowed_ids))\
103 103 .count()
104 104
105 105 # json generate
106 106 base_q = Repository.query()\
107 107 .filter(Repository.fork_id == repo_id)\
108 108 .filter(Repository.repo_id.in_(allowed_ids))\
109 109
110 110 if search_q:
111 111 like_expression = u'%{}%'.format(safe_unicode(search_q))
112 112 base_q = base_q.filter(or_(
113 113 Repository.repo_name.ilike(like_expression),
114 114 Repository.description.ilike(like_expression),
115 115 ))
116 116
117 117 forks_data_total_filtered_count = base_q.count()
118 118
119 119 sort_col = getattr(Repository, order_by, None)
120 120 if sort_col:
121 121 if order_dir == 'asc':
122 122 # handle null values properly to order by NULL last
123 123 if order_by in ['last_activity']:
124 124 sort_col = coalesce(sort_col, datetime.date.max)
125 125 sort_col = sort_col.asc()
126 126 else:
127 127 # handle null values properly to order by NULL last
128 128 if order_by in ['last_activity']:
129 129 sort_col = coalesce(sort_col, datetime.date.min)
130 130 sort_col = sort_col.desc()
131 131
132 132 base_q = base_q.order_by(sort_col)
133 133 base_q = base_q.offset(start).limit(limit)
134 134
135 135 fork_list = base_q.all()
136 136
137 137 def fork_actions(fork):
138 138 url_link = h.route_path(
139 139 'repo_compare',
140 140 repo_name=fork.repo_name,
141 source_ref_type=self.db_repo.landing_rev[0],
142 source_ref=self.db_repo.landing_rev[1],
143 target_ref_type=self.db_repo.landing_rev[0],
144 target_ref=self.db_repo.landing_rev[1],
141 source_ref_type=self.db_repo.landing_ref_type,
142 source_ref=self.db_repo.landing_ref_name,
143 target_ref_type=self.db_repo.landing_ref_type,
144 target_ref=self.db_repo.landing_ref_name,
145 145 _query=dict(merge=1, target_repo=f.repo_name))
146 146 return h.link_to(_('Compare fork'), url_link, class_='btn-link')
147 147
148 148 def fork_name(fork):
149 149 return h.link_to(fork.repo_name,
150 150 h.route_path('repo_summary', repo_name=fork.repo_name))
151 151
152 152 forks_data = []
153 153 for fork in fork_list:
154 154 forks_data.append({
155 155 "username": h.gravatar_with_user(self.request, fork.user.username),
156 156 "fork_name": fork_name(fork),
157 157 "description": fork.description_safe,
158 158 "fork_date": h.age_component(fork.created_on, time_is_local=True),
159 159 "last_activity": h.format_date(fork.updated_on),
160 160 "action": fork_actions(fork),
161 161 })
162 162
163 163 data = ({
164 164 'draw': draw,
165 165 'data': forks_data,
166 166 'recordsTotal': forks_data_total_count,
167 167 'recordsFiltered': forks_data_total_filtered_count,
168 168 })
169 169
170 170 return data
171 171
172 172 @LoginRequired()
173 173 @NotAnonymous()
174 174 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
175 175 @HasRepoPermissionAnyDecorator(
176 176 'repository.read', 'repository.write', 'repository.admin')
177 177 @view_config(
178 178 route_name='repo_fork_new', request_method='GET',
179 179 renderer='rhodecode:templates/forks/forks.mako')
180 180 def repo_fork_new(self):
181 181 c = self.load_default_context()
182 182
183 183 defaults = RepoModel()._get_defaults(self.db_repo_name)
184 184 # alter the description to indicate a fork
185 185 defaults['description'] = (
186 186 'fork of repository: %s \n%s' % (
187 187 defaults['repo_name'], defaults['description']))
188 188 # add suffix to fork
189 189 defaults['repo_name'] = '%s-fork' % defaults['repo_name']
190 190
191 191 data = render('rhodecode:templates/forks/fork.mako',
192 192 self._get_template_context(c), self.request)
193 193 html = formencode.htmlfill.render(
194 194 data,
195 195 defaults=defaults,
196 196 encoding="UTF-8",
197 197 force_defaults=False
198 198 )
199 199 return Response(html)
200 200
201 201 @LoginRequired()
202 202 @NotAnonymous()
203 203 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
204 204 @HasRepoPermissionAnyDecorator(
205 205 'repository.read', 'repository.write', 'repository.admin')
206 206 @CSRFRequired()
207 207 @view_config(
208 208 route_name='repo_fork_create', request_method='POST',
209 209 renderer='rhodecode:templates/forks/fork.mako')
210 210 def repo_fork_create(self):
211 211 _ = self.request.translate
212 212 c = self.load_default_context()
213 213
214 214 _form = RepoForkForm(self.request.translate,
215 215 old_data={'repo_type': self.db_repo.repo_type},
216 216 repo_groups=c.repo_groups_choices)()
217 217 post_data = dict(self.request.POST)
218 218
219 219 # forbid injecting other repo by forging a request
220 220 post_data['fork_parent_id'] = self.db_repo.repo_id
221 221 post_data['landing_rev'] = self.db_repo._landing_revision
222 222
223 223 form_result = {}
224 224 task_id = None
225 225 try:
226 226 form_result = _form.to_python(post_data)
227 227 copy_permissions = form_result.get('copy_permissions')
228 228 # create fork is done sometimes async on celery, db transaction
229 229 # management is handled there.
230 230 task = RepoModel().create_fork(
231 231 form_result, c.rhodecode_user.user_id)
232 232
233 233 task_id = get_task_id(task)
234 234 except formencode.Invalid as errors:
235 235 c.rhodecode_db_repo = self.db_repo
236 236
237 237 data = render('rhodecode:templates/forks/fork.mako',
238 238 self._get_template_context(c), self.request)
239 239 html = formencode.htmlfill.render(
240 240 data,
241 241 defaults=errors.value,
242 242 errors=errors.error_dict or {},
243 243 prefix_error=False,
244 244 encoding="UTF-8",
245 245 force_defaults=False
246 246 )
247 247 return Response(html)
248 248 except Exception:
249 249 log.exception(
250 250 u'Exception while trying to fork the repository %s', self.db_repo_name)
251 251 msg = _('An error occurred during repository forking %s') % (self.db_repo_name, )
252 252 h.flash(msg, category='error')
253 253 raise HTTPFound(h.route_path('home'))
254 254
255 255 repo_name = form_result.get('repo_name_full', self.db_repo_name)
256 256
257 257 affected_user_ids = [self._rhodecode_user.user_id]
258 258 if copy_permissions:
259 259 # permission flush is done in repo creating
260 260 pass
261 261
262 262 PermissionModel().trigger_permission_flush(affected_user_ids)
263 263
264 264 raise HTTPFound(
265 265 h.route_path('repo_creating', repo_name=repo_name,
266 266 _query=dict(task_id=task_id)))
This diff has been collapsed as it changes many lines, (3299 lines changed) Show them Hide them
@@ -1,11099 +1,11328 b''
1 1 # Translations template for rhodecode-enterprise-ce.
2 2 # Copyright (C) 2020 RhodeCode GmbH
3 3 # This file is distributed under the same license as the rhodecode-enterprise-ce project.
4 4 # FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
5 5 #
6 6 #, fuzzy
7 7 msgid ""
8 8 msgstr ""
9 "Project-Id-Version: rhodecode-enterprise-ce 4.18.0\n"
9 "Project-Id-Version: rhodecode-enterprise-ce 4.19.0\n"
10 10 "Report-Msgid-Bugs-To: marcin@rhodecode.com\n"
11 "POT-Creation-Date: 2020-01-08 13:56+0000\n"
11 "POT-Creation-Date: 2020-05-22 09:45+0000\n"
12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 14 "Language-Team: LANGUAGE <LL@li.org>\n"
15 15 "MIME-Version: 1.0\n"
16 16 "Content-Type: text/plain; charset=utf-8\n"
17 17 "Content-Transfer-Encoding: 8bit\n"
18 18 "Generated-By: Babel 1.3\n"
19 19
20 20 #: rhodecode/apps/admin/views/defaults.py:90
21 21 msgid "Default settings updated successfully"
22 22 msgstr ""
23 23
24 24 #: rhodecode/apps/admin/views/defaults.py:108
25 25 msgid "Error occurred during update of default values"
26 26 msgstr ""
27 27
28 28 #: rhodecode/apps/admin/views/exception_tracker.py:156
29 29 msgid "Removed {} Exceptions"
30 30 msgstr ""
31 31
32 32 #: rhodecode/apps/admin/views/exception_tracker.py:173
33 33 msgid "Removed Exception {}"
34 34 msgstr ""
35 35
36 36 #: rhodecode/apps/admin/views/permissions.py:121
37 37 msgid "Application permissions updated successfully"
38 38 msgstr ""
39 39
40 40 #: rhodecode/apps/admin/views/permissions.py:142
41 41 #: rhodecode/apps/admin/views/permissions.py:218
42 42 #: rhodecode/apps/admin/views/permissions.py:320
43 43 msgid "Error occurred during update of permissions"
44 44 msgstr ""
45 45
46 46 #: rhodecode/apps/admin/views/permissions.py:198
47 47 msgid "Object permissions updated successfully"
48 48 msgstr ""
49 49
50 50 #: rhodecode/apps/admin/views/permissions.py:300
51 51 msgid "Global permissions updated successfully"
52 52 msgstr ""
53 53
54 54 #: rhodecode/apps/admin/views/permissions.py:485
55 55 #: rhodecode/templates/admin/gists/gist_show.mako:50
56 56 #: rhodecode/templates/admin/integrations/list.mako:172
57 57 #: rhodecode/templates/admin/my_account/my_account_profile.mako:7
58 58 #: rhodecode/templates/base/issue_tracker_settings.mako:137
59 59 #: rhodecode/templates/data_table/_dt_elements.mako:173
60 #: rhodecode/templates/data_table/_dt_elements.mako:249
61 #: rhodecode/templates/data_table/_dt_elements.mako:262
62 #: rhodecode/templates/data_table/_dt_elements.mako:263
63 #: rhodecode/templates/data_table/_dt_elements.mako:276
60 #: rhodecode/templates/data_table/_dt_elements.mako:251
61 #: rhodecode/templates/data_table/_dt_elements.mako:266
62 #: rhodecode/templates/data_table/_dt_elements.mako:267
63 #: rhodecode/templates/data_table/_dt_elements.mako:282
64 64 #: rhodecode/templates/debug_style/buttons.html:128
65 #: rhodecode/templates/files/files_add.mako:57
65 #: rhodecode/templates/files/files_add.mako:56
66 66 #: rhodecode/templates/files/files_edit.mako:58
67 67 #: rhodecode/templates/files/files_source.mako:29
68 68 #: rhodecode/templates/files/files_source.mako:42
69 69 #: rhodecode/templates/pullrequests/pullrequest_show.mako:74
70 70 #: rhodecode/templates/pullrequests/pullrequest_show.mako:302
71 71 #: rhodecode/templates/user_group/profile.mako:8
72 72 #: rhodecode/templates/users/user_profile.mako:8
73 73 msgid "Edit"
74 74 msgstr ""
75 75
76 76 #: rhodecode/apps/admin/views/permissions.py:513
77 77 msgid "Updated SSH keys file: {}"
78 78 msgstr ""
79 79
80 80 #: rhodecode/apps/admin/views/permissions.py:516
81 81 msgid "SSH key support is disabled in .ini file"
82 82 msgstr ""
83 83
84 84 #: rhodecode/apps/admin/views/repo_groups.py:328
85 85 #, python-format
86 86 msgid "Created repository group %s"
87 87 msgstr ""
88 88
89 89 #: rhodecode/apps/admin/views/repo_groups.py:346
90 90 #, python-format
91 91 msgid "Error occurred during creation of repository group %s"
92 92 msgstr ""
93 93
94 94 #: rhodecode/apps/admin/views/sessions.py:92
95 95 msgid "Cleaned up old sessions"
96 96 msgstr ""
97 97
98 98 #: rhodecode/apps/admin/views/sessions.py:97
99 99 msgid "Failed to cleanup up old sessions"
100 100 msgstr ""
101 101
102 102 #: rhodecode/apps/admin/views/settings.py:162
103 103 #: rhodecode/apps/admin/views/settings.py:317
104 104 #: rhodecode/apps/admin/views/settings.py:392
105 105 #: rhodecode/apps/admin/views/settings.py:726
106 106 #: rhodecode/apps/repository/views/repo_settings_vcs.py:124
107 107 msgid "Some form inputs contain invalid data."
108 108 msgstr ""
109 109
110 110 #: rhodecode/apps/admin/views/settings.py:189
111 111 #: rhodecode/apps/admin/views/settings.py:353
112 112 msgid "Error occurred during updating application settings"
113 113 msgstr ""
114 114
115 115 #: rhodecode/apps/admin/views/settings.py:193
116 116 #: rhodecode/apps/repository/views/repo_settings_vcs.py:143
117 117 msgid "Updated VCS settings"
118 118 msgstr ""
119 119
120 120 #: rhodecode/apps/admin/views/settings.py:267
121 121 #, python-format
122 122 msgid "Repositories successfully rescanned added: %s ; removed: %s"
123 123 msgstr ""
124 124
125 125 #: rhodecode/apps/admin/views/settings.py:349
126 126 msgid "Updated application settings"
127 127 msgstr ""
128 128
129 129 #: rhodecode/apps/admin/views/settings.py:431
130 130 msgid "Updated visualisation settings"
131 131 msgstr ""
132 132
133 133 #: rhodecode/apps/admin/views/settings.py:434
134 134 msgid "Error occurred during updating visualisation settings"
135 135 msgstr ""
136 136
137 137 #: rhodecode/apps/admin/views/settings.py:496
138 138 #: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:127
139 139 msgid "Invalid issue tracker pattern: {}"
140 140 msgstr ""
141 141
142 142 #: rhodecode/apps/admin/views/settings.py:513
143 143 #: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:136
144 144 msgid "Updated issue tracker entries"
145 145 msgstr ""
146 146
147 147 #: rhodecode/apps/admin/views/settings.py:533
148 148 #: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:91
149 149 msgid "Removed issue tracker entry."
150 150 msgstr ""
151 151
152 152 #: rhodecode/apps/admin/views/settings.py:571
153 153 msgid "Please enter email address"
154 154 msgstr ""
155 155
156 156 #: rhodecode/apps/admin/views/settings.py:588
157 157 msgid "Send email task created"
158 158 msgstr ""
159 159
160 160 #: rhodecode/apps/admin/views/settings.py:638
161 161 msgid "Added new hook"
162 162 msgstr ""
163 163
164 164 #: rhodecode/apps/admin/views/settings.py:653
165 165 msgid "Updated hooks"
166 166 msgstr ""
167 167
168 168 #: rhodecode/apps/admin/views/settings.py:657
169 169 msgid "Error occurred during hook creation"
170 170 msgstr ""
171 171
172 172 #: rhodecode/apps/admin/views/settings.py:750
173 173 msgid "Error occurred during updating labs settings"
174 174 msgstr ""
175 175
176 176 #: rhodecode/apps/admin/views/settings.py:755
177 177 msgid "Updated Labs settings"
178 178 msgstr ""
179 179
180 180 #: rhodecode/apps/admin/views/svn_config.py:46
181 msgid "Apache configuration for Subversion generated."
181 msgid "Apache configuration for Subversion generated at `{}`."
182 182 msgstr ""
183 183
184 184 #: rhodecode/apps/admin/views/svn_config.py:54
185 185 msgid "Failed to generate the Apache configuration for Subversion."
186 186 msgstr ""
187 187
188 188 #: rhodecode/apps/admin/views/system_info.py:79
189 189 msgid "Note: please make sure this server can access `${url}` for the update link to work"
190 190 msgstr ""
191 191
192 192 #: rhodecode/apps/admin/views/system_info.py:90
193 193 msgid "Update info"
194 194 msgstr ""
195 195
196 196 #: rhodecode/apps/admin/views/system_info.py:92
197 197 msgid "Check for updates"
198 198 msgstr ""
199 199
200 200 #: rhodecode/apps/admin/views/system_info.py:97
201 201 msgid "RhodeCode Version"
202 202 msgstr ""
203 203
204 204 #: rhodecode/apps/admin/views/system_info.py:98
205 205 msgid "Latest version"
206 206 msgstr ""
207 207
208 208 #: rhodecode/apps/admin/views/system_info.py:99
209 209 msgid "RhodeCode Base URL"
210 210 msgstr ""
211 211
212 212 #: rhodecode/apps/admin/views/system_info.py:100
213 213 msgid "RhodeCode Server IP"
214 214 msgstr ""
215 215
216 216 #: rhodecode/apps/admin/views/system_info.py:101
217 217 msgid "RhodeCode Server ID"
218 218 msgstr ""
219 219
220 220 #: rhodecode/apps/admin/views/system_info.py:102
221 221 msgid "RhodeCode Configuration"
222 222 msgstr ""
223 223
224 224 #: rhodecode/apps/admin/views/system_info.py:103
225 225 msgid "RhodeCode Certificate"
226 226 msgstr ""
227 227
228 228 #: rhodecode/apps/admin/views/system_info.py:104
229 229 msgid "Workers"
230 230 msgstr ""
231 231
232 232 #: rhodecode/apps/admin/views/system_info.py:105
233 233 msgid "Worker Type"
234 234 msgstr ""
235 235
236 236 #: rhodecode/apps/admin/views/system_info.py:109
237 237 msgid "Database"
238 238 msgstr ""
239 239
240 240 #: rhodecode/apps/admin/views/system_info.py:110
241 241 msgid "Database version"
242 242 msgstr ""
243 243
244 244 #: rhodecode/apps/admin/views/system_info.py:114
245 245 msgid "Platform"
246 246 msgstr ""
247 247
248 248 #: rhodecode/apps/admin/views/system_info.py:115
249 249 msgid "Platform UUID"
250 250 msgstr ""
251 251
252 252 #: rhodecode/apps/admin/views/system_info.py:116
253 253 msgid "Lang"
254 254 msgstr ""
255 255
256 256 #: rhodecode/apps/admin/views/system_info.py:117
257 257 msgid "Python version"
258 258 msgstr ""
259 259
260 260 #: rhodecode/apps/admin/views/system_info.py:118
261 261 msgid "Python path"
262 262 msgstr ""
263 263
264 264 #: rhodecode/apps/admin/views/system_info.py:122
265 265 msgid "CPU"
266 266 msgstr ""
267 267
268 268 #: rhodecode/apps/admin/views/system_info.py:123
269 269 msgid "Load"
270 270 msgstr ""
271 271
272 272 #: rhodecode/apps/admin/views/system_info.py:124
273 273 msgid "Memory"
274 274 msgstr ""
275 275
276 276 #: rhodecode/apps/admin/views/system_info.py:125
277 277 msgid "Uptime"
278 278 msgstr ""
279 279
280 280 #: rhodecode/apps/admin/views/system_info.py:129
281 281 msgid "Ulimit"
282 282 msgstr ""
283 283
284 284 #: rhodecode/apps/admin/views/system_info.py:132
285 285 msgid "Storage location"
286 286 msgstr ""
287 287
288 288 #: rhodecode/apps/admin/views/system_info.py:133
289 289 msgid "Storage info"
290 290 msgstr ""
291 291
292 292 #: rhodecode/apps/admin/views/system_info.py:134
293 293 msgid "Storage inodes"
294 294 msgstr ""
295 295
296 296 #: rhodecode/apps/admin/views/system_info.py:136
297 297 msgid "Gist storage location"
298 298 msgstr ""
299 299
300 300 #: rhodecode/apps/admin/views/system_info.py:137
301 301 msgid "Gist storage info"
302 302 msgstr ""
303 303
304 304 #: rhodecode/apps/admin/views/system_info.py:139
305 305 msgid "Archive cache storage location"
306 306 msgstr ""
307 307
308 308 #: rhodecode/apps/admin/views/system_info.py:140
309 309 msgid "Archive cache info"
310 310 msgstr ""
311 311
312 312 #: rhodecode/apps/admin/views/system_info.py:142
313 313 msgid "Temp storage location"
314 314 msgstr ""
315 315
316 316 #: rhodecode/apps/admin/views/system_info.py:143
317 317 msgid "Temp storage info"
318 318 msgstr ""
319 319
320 320 #: rhodecode/apps/admin/views/system_info.py:145
321 321 msgid "Search info"
322 322 msgstr ""
323 323
324 324 #: rhodecode/apps/admin/views/system_info.py:146
325 325 msgid "Search location"
326 326 msgstr ""
327 327
328 328 #: rhodecode/apps/admin/views/system_info.py:150
329 329 msgid "VCS Backends"
330 330 msgstr ""
331 331
332 332 #: rhodecode/apps/admin/views/system_info.py:151
333 333 #: rhodecode/templates/admin/settings/settings_system.mako:32
334 334 msgid "VCS Server"
335 335 msgstr ""
336 336
337 337 #: rhodecode/apps/admin/views/system_info.py:152
338 338 msgid "GIT"
339 339 msgstr ""
340 340
341 341 #: rhodecode/apps/admin/views/system_info.py:153
342 342 msgid "HG"
343 343 msgstr ""
344 344
345 345 #: rhodecode/apps/admin/views/system_info.py:154
346 346 msgid "SVN"
347 347 msgstr ""
348 348
349 349 #: rhodecode/apps/admin/views/user_groups.py:238
350 350 #, python-format
351 351 msgid "Created user group %(user_group_link)s"
352 352 msgstr ""
353 353
354 354 #: rhodecode/apps/admin/views/user_groups.py:260
355 355 #, python-format
356 356 msgid "Error occurred during creation of user group %s"
357 357 msgstr ""
358 358
359 #: rhodecode/apps/admin/views/users.py:221
359 #: rhodecode/apps/admin/views/users.py:222
360 360 #, python-format
361 361 msgid "Created user %(user_link)s"
362 362 msgstr ""
363 363
364 #: rhodecode/apps/admin/views/users.py:242
364 #: rhodecode/apps/admin/views/users.py:243
365 365 #, python-format
366 366 msgid "Error occurred during creation of user %s"
367 367 msgstr ""
368 368
369 #: rhodecode/apps/admin/views/users.py:344
369 #: rhodecode/apps/admin/views/users.py:345
370 370 msgid "User updated successfully"
371 371 msgstr ""
372 372
373 #: rhodecode/apps/admin/views/users.py:362
373 #: rhodecode/apps/admin/views/users.py:363
374 374 #, python-format
375 375 msgid "Error occurred during update of user %s"
376 376 msgstr ""
377 377
378 #: rhodecode/apps/admin/views/users.py:391
379 #, python-format
380 msgid "Detached %s repositories"
381 msgstr ""
382
383 378 #: rhodecode/apps/admin/views/users.py:394
384 379 #, python-format
380 msgid "Detached %s repositories"
381 msgstr ""
382
383 #: rhodecode/apps/admin/views/users.py:397
384 #, python-format
385 385 msgid "Deleted %s repositories"
386 386 msgstr ""
387 387
388 #: rhodecode/apps/admin/views/users.py:400
389 #, python-format
390 msgid "Detached %s repository groups"
391 msgstr ""
392
393 388 #: rhodecode/apps/admin/views/users.py:403
394 389 #, python-format
390 msgid "Detached %s repository groups"
391 msgstr ""
392
393 #: rhodecode/apps/admin/views/users.py:406
394 #, python-format
395 395 msgid "Deleted %s repository groups"
396 396 msgstr ""
397 397
398 #: rhodecode/apps/admin/views/users.py:409
399 #, python-format
400 msgid "Detached %s user groups"
401 msgstr ""
402
403 398 #: rhodecode/apps/admin/views/users.py:412
404 399 #, python-format
400 msgid "Detached %s user groups"
401 msgstr ""
402
403 #: rhodecode/apps/admin/views/users.py:415
404 #, python-format
405 405 msgid "Deleted %s user groups"
406 406 msgstr ""
407 407
408 #: rhodecode/apps/admin/views/users.py:418
409 #, python-format
410 msgid "Detached %s artifacts"
411 msgstr ""
412
413 408 #: rhodecode/apps/admin/views/users.py:421
414 409 #, python-format
410 msgid "Detached %s pull requests"
411 msgstr ""
412
413 #: rhodecode/apps/admin/views/users.py:424
414 #, python-format
415 msgid "Deleted %s pull requests"
416 msgstr ""
417
418 #: rhodecode/apps/admin/views/users.py:430
419 #, python-format
420 msgid "Detached %s artifacts"
421 msgstr ""
422
423 #: rhodecode/apps/admin/views/users.py:433
424 #, python-format
415 425 msgid "Deleted %s artifacts"
416 426 msgstr ""
417 427
418 #: rhodecode/apps/admin/views/users.py:454
428 #: rhodecode/apps/admin/views/users.py:482
419 429 msgid "Successfully deleted user `{}`"
420 430 msgstr ""
421 431
422 #: rhodecode/apps/admin/views/users.py:460
432 #: rhodecode/apps/admin/views/users.py:489
423 433 msgid "An error occurred during deletion of user"
424 434 msgstr ""
425 435
426 #: rhodecode/apps/admin/views/users.py:525
436 #: rhodecode/apps/admin/views/users.py:558
427 437 msgid ""
428 438 "The user participates as reviewer in {} pull request and cannot be deleted. \n"
429 439 "You can set the user to \"{}\" instead of deleting it."
430 440 msgstr ""
431 441
432 #: rhodecode/apps/admin/views/users.py:531
442 #: rhodecode/apps/admin/views/users.py:564
433 443 msgid ""
434 444 "The user participates as reviewer in {} pull requests and cannot be deleted. \n"
435 445 "You can set the user to \"{}\" instead of deleting it."
436 446 msgstr ""
437 447
438 #: rhodecode/apps/admin/views/users.py:620
448 #: rhodecode/apps/admin/views/users.py:653
439 449 msgid "User global permissions updated successfully"
440 450 msgstr ""
441 451
442 #: rhodecode/apps/admin/views/users.py:638
452 #: rhodecode/apps/admin/views/users.py:671
443 453 #: rhodecode/apps/user_group/views/__init__.py:479
444 454 msgid "An error occurred during permissions saving"
445 455 msgstr ""
446 456
447 #: rhodecode/apps/admin/views/users.py:661
457 #: rhodecode/apps/admin/views/users.py:694
448 458 msgid "Force password change enabled for user"
449 459 msgstr ""
450 460
451 #: rhodecode/apps/admin/views/users.py:669
452 #: rhodecode/apps/admin/views/users.py:699
461 #: rhodecode/apps/admin/views/users.py:702
462 #: rhodecode/apps/admin/views/users.py:732
453 463 msgid "An error occurred during password reset for user"
454 464 msgstr ""
455 465
456 #: rhodecode/apps/admin/views/users.py:690
466 #: rhodecode/apps/admin/views/users.py:723
457 467 msgid "Force password change disabled for user"
458 468 msgstr ""
459 469
460 #: rhodecode/apps/admin/views/users.py:737
470 #: rhodecode/apps/admin/views/users.py:796
461 471 #, python-format
462 472 msgid "Linked repository group `%s` as personal"
463 473 msgstr ""
464 474
465 #: rhodecode/apps/admin/views/users.py:743
475 #: rhodecode/apps/admin/views/users.py:802
466 476 #, python-format
467 477 msgid "Created repository group `%s`"
468 478 msgstr ""
469 479
470 #: rhodecode/apps/admin/views/users.py:747
480 #: rhodecode/apps/admin/views/users.py:806
471 481 #, python-format
472 482 msgid "Repository group `%s` is already taken"
473 483 msgstr ""
474 484
475 #: rhodecode/apps/admin/views/users.py:752
485 #: rhodecode/apps/admin/views/users.py:811
476 486 msgid "An error occurred during repository group creation for user"
477 487 msgstr ""
478 488
479 #: rhodecode/apps/admin/views/users.py:775
480 #: rhodecode/apps/my_account/views/my_account.py:160
481 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:16
482 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:16
489 #: rhodecode/apps/admin/views/users.py:834
490 #: rhodecode/apps/my_account/views/my_account.py:161
491 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:22
492 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:27
483 493 msgid "Role"
484 494 msgstr ""
485 495
486 #: rhodecode/apps/admin/views/users.py:814
487 #: rhodecode/apps/my_account/views/my_account.py:195
496 #: rhodecode/apps/admin/views/users.py:892
497 #: rhodecode/apps/my_account/views/my_account.py:217
488 498 msgid "Auth token successfully created"
489 499 msgstr ""
490 500
491 #: rhodecode/apps/admin/views/users.py:843
492 #: rhodecode/apps/my_account/views/my_account.py:219
501 #: rhodecode/apps/admin/views/users.py:921
502 #: rhodecode/apps/my_account/views/my_account.py:241
493 503 msgid "Auth token successfully deleted"
494 504 msgstr ""
495 505
496 #: rhodecode/apps/admin/views/users.py:916
497 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:114
506 #: rhodecode/apps/admin/views/users.py:997
507 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:117
498 508 msgid "Ssh Key successfully created"
499 509 msgstr ""
500 510
501 #: rhodecode/apps/admin/views/users.py:922
502 #: rhodecode/apps/admin/views/users.py:926
503 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:120
504 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:124
511 #: rhodecode/apps/admin/views/users.py:1003
512 #: rhodecode/apps/admin/views/users.py:1007
513 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:123
514 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:127
505 515 msgid "An error occurred during ssh key saving: {}"
506 516 msgstr ""
507 517
508 #: rhodecode/apps/admin/views/users.py:960
509 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:154
518 #: rhodecode/apps/admin/views/users.py:1041
519 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:157
510 520 msgid "Ssh key successfully deleted"
511 521 msgstr ""
512 522
513 #: rhodecode/apps/admin/views/users.py:1006
523 #: rhodecode/apps/admin/views/users.py:1087
514 524 #, python-format
515 525 msgid "Added new email address `%s` for user account"
516 526 msgstr ""
517 527
518 #: rhodecode/apps/admin/views/users.py:1012
528 #: rhodecode/apps/admin/views/users.py:1093
519 529 msgid "Email `{}` is already registered for another user."
520 530 msgstr ""
521 531
522 #: rhodecode/apps/admin/views/users.py:1016
532 #: rhodecode/apps/admin/views/users.py:1097
523 533 msgid "An error occurred during email saving"
524 534 msgstr ""
525 535
526 #: rhodecode/apps/admin/views/users.py:1043
536 #: rhodecode/apps/admin/views/users.py:1124
527 537 msgid "Removed email address from user account"
528 538 msgstr ""
529 539
530 #: rhodecode/apps/admin/views/users.py:1089
540 #: rhodecode/apps/admin/views/users.py:1170
531 541 #, python-format
532 542 msgid "An error occurred during ip saving:%s"
533 543 msgstr ""
534 544
535 #: rhodecode/apps/admin/views/users.py:1111
545 #: rhodecode/apps/admin/views/users.py:1192
536 546 msgid "An error occurred during ip saving"
537 547 msgstr ""
538 548
539 #: rhodecode/apps/admin/views/users.py:1115
549 #: rhodecode/apps/admin/views/users.py:1196
540 550 #, python-format
541 551 msgid "Added ips %s to user whitelist"
542 552 msgstr ""
543 553
544 #: rhodecode/apps/admin/views/users.py:1145
554 #: rhodecode/apps/admin/views/users.py:1226
545 555 msgid "Removed ip address from user whitelist"
546 556 msgstr ""
547 557
548 #: rhodecode/apps/admin/views/users.py:1210
558 #: rhodecode/apps/admin/views/users.py:1291
549 559 msgid "Groups successfully changed"
550 560 msgstr ""
551 561
552 #: rhodecode/apps/admin/views/users.py:1330
562 #: rhodecode/apps/admin/views/users.py:1411
553 563 msgid "Deleted {} cache keys"
554 564 msgstr ""
555 565
556 566 #: rhodecode/apps/gist/views.py:57 rhodecode/model/auth_token.py:51
557 567 msgid "forever"
558 568 msgstr ""
559 569
560 570 #: rhodecode/apps/gist/views.py:58
561 571 msgid "5 minutes"
562 572 msgstr ""
563 573
564 574 #: rhodecode/apps/gist/views.py:59
565 575 msgid "1 hour"
566 576 msgstr ""
567 577
568 578 #: rhodecode/apps/gist/views.py:60
569 579 msgid "1 day"
570 580 msgstr ""
571 581
572 582 #: rhodecode/apps/gist/views.py:61
573 583 msgid "1 month"
574 584 msgstr ""
575 585
576 #: rhodecode/apps/gist/views.py:64 rhodecode/public/js/scripts.js:50068
586 #: rhodecode/apps/gist/views.py:64 rhodecode/public/js/scripts.js:46848
577 587 #: rhodecode/public/js/scripts.min.js:1
578 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:26
579 #: rhodecode/public/js/src/rhodecode.js:621
588 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:35
589 #: rhodecode/public/js/src/rhodecode.js:625
580 590 msgid "Lifetime"
581 591 msgstr ""
582 592
583 593 #: rhodecode/apps/gist/views.py:66
584 594 msgid "Requires registered account"
585 595 msgstr ""
586 596
587 597 #: rhodecode/apps/gist/views.py:67
588 598 msgid "Can be accessed by anonymous users"
589 599 msgstr ""
590 600
591 601 #: rhodecode/apps/gist/views.py:218
592 602 msgid "Error occurred during gist creation"
593 603 msgstr ""
594 604
595 605 #: rhodecode/apps/gist/views.py:242
596 606 #, python-format
597 607 msgid "Deleted gist %s"
598 608 msgstr ""
599 609
600 610 #: rhodecode/apps/gist/views.py:330
601 #: rhodecode/templates/admin/gists/gist_show.mako:73
602 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:36
603 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:36
604 #: rhodecode/templates/data_table/_dt_elements.mako:333
611 #: rhodecode/templates/admin/gists/gist_show.mako:76
612 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:44
613 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:49
614 #: rhodecode/templates/data_table/_dt_elements.mako:341
605 615 msgid "never"
606 616 msgstr ""
607 617
608 618 #: rhodecode/apps/gist/views.py:336
609 619 #, python-format
610 620 msgid "%(expiry)s - current value"
611 621 msgstr ""
612 622
613 623 #: rhodecode/apps/gist/views.py:381
614 624 msgid "Successfully updated gist content"
615 625 msgstr ""
616 626
617 627 #: rhodecode/apps/gist/views.py:386
618 628 msgid "Successfully updated gist data"
619 629 msgstr ""
620 630
621 631 #: rhodecode/apps/gist/views.py:389
622 632 msgid "Error occurred during update of gist {}: {}"
623 633 msgstr ""
624 634
625 635 #: rhodecode/apps/gist/views.py:393
626 636 #, python-format
627 637 msgid "Error occurred during update of gist %s"
628 638 msgstr ""
629 639
630 #: rhodecode/apps/home/views.py:397
631 #: rhodecode/apps/repository/views/repo_pull_requests.py:879
632 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:199
640 #: rhodecode/apps/home/views.py:452
641 #: rhodecode/apps/repository/views/repo_pull_requests.py:914
642 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:209
633 643 #: rhodecode/templates/admin/repos/repo_add.mako:15
634 644 #: rhodecode/templates/admin/repos/repo_add.mako:19
635 645 #: rhodecode/templates/admin/users/user_edit_advanced.mako:12
636 646 #: rhodecode/templates/base/base.mako:107
637 647 #: rhodecode/templates/base/base.mako:126
638 #: rhodecode/templates/base/base.mako:1111
648 #: rhodecode/templates/base/base.mako:1172
639 649 msgid "Repositories"
640 650 msgstr ""
641 651
642 #: rhodecode/apps/home/views.py:424
652 #: rhodecode/apps/home/views.py:479
643 653 #: rhodecode/templates/admin/integrations/form.mako:17
644 654 #: rhodecode/templates/admin/integrations/list.mako:10
645 655 #: rhodecode/templates/admin/permissions/permissions_objects.mako:31
646 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:198
656 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:208
647 657 msgid "Repository Groups"
648 658 msgstr ""
649 659
650 660 #: rhodecode/apps/journal/views.py:133 rhodecode/apps/journal/views.py:179
651 661 msgid "public journal"
652 662 msgstr ""
653 663
654 664 #: rhodecode/apps/journal/views.py:137 rhodecode/apps/journal/views.py:183
655 665 msgid "journal"
656 666 msgstr ""
657 667
658 668 #: rhodecode/apps/login/views.py:304 rhodecode/apps/login/views.py:403
659 669 msgid "Bad captcha"
660 670 msgstr ""
661 671
662 672 #: rhodecode/apps/login/views.py:330
663 673 msgid "You have successfully registered with RhodeCode. You can log-in now."
664 674 msgstr ""
665 675
666 676 #: rhodecode/apps/login/views.py:334
667 677 msgid "Please use the {identity} button to log-in"
668 678 msgstr ""
669 679
670 680 #: rhodecode/apps/login/views.py:372
671 681 msgid "If such email exists, a password reset link was sent to it."
672 682 msgstr ""
673 683
674 684 #: rhodecode/apps/login/views.py:385
675 685 msgid "Password reset has been disabled."
676 686 msgstr ""
677 687
678 688 #: rhodecode/apps/login/views.py:474
679 689 msgid "Given reset token is invalid"
680 690 msgstr ""
681 691
682 692 #: rhodecode/apps/login/views.py:482
683 693 msgid "Your password reset was successful, a new password has been sent to your email"
684 694 msgstr ""
685 695
686 #: rhodecode/apps/my_account/views/my_account.py:135
696 #: rhodecode/apps/my_account/views/my_account.py:136
687 697 msgid "Error occurred during update of user password"
688 698 msgstr ""
689 699
690 #: rhodecode/apps/my_account/views/my_account.py:142
700 #: rhodecode/apps/my_account/views/my_account.py:143
691 701 msgid "Successfully updated password"
692 702 msgstr ""
693 703
694 #: rhodecode/apps/my_account/views/my_account.py:283
704 #: rhodecode/apps/my_account/views/my_account.py:305
695 705 msgid "Error occurred during adding email"
696 706 msgstr ""
697 707
698 #: rhodecode/apps/my_account/views/my_account.py:286
699 msgid "Successfully added email"
700 msgstr ""
701
702 708 #: rhodecode/apps/my_account/views/my_account.py:308
709 msgid "Successfully added email"
710 msgstr ""
711
712 #: rhodecode/apps/my_account/views/my_account.py:330
703 713 msgid "Email successfully deleted"
704 714 msgstr ""
705 715
706 #: rhodecode/apps/my_account/views/my_account.py:518
716 #: rhodecode/apps/my_account/views/my_account.py:540
707 717 msgid "Position {} is defined twice. Please correct this error."
708 718 msgstr ""
709 719
710 #: rhodecode/apps/my_account/views/my_account.py:531
720 #: rhodecode/apps/my_account/views/my_account.py:553
711 721 msgid "Update Bookmarks"
712 722 msgstr ""
713 723
714 #: rhodecode/apps/my_account/views/my_account.py:533
724 #: rhodecode/apps/my_account/views/my_account.py:555
715 725 msgid "Failed to update bookmarks. Make sure an unique position is used."
716 726 msgstr ""
717 727
718 #: rhodecode/apps/my_account/views/my_account.py:685
728 #: rhodecode/apps/my_account/views/my_account.py:707
719 729 msgid "Your account was updated successfully"
720 730 msgstr ""
721 731
722 #: rhodecode/apps/my_account/views/my_account.py:692
732 #: rhodecode/apps/my_account/views/my_account.py:714
723 733 msgid "Error occurred during update of user"
724 734 msgstr ""
725 735
726 736 #: rhodecode/apps/repo_group/views/repo_group_advanced.py:57
727 #: rhodecode/apps/repository/views/repo_settings_advanced.py:77
737 #: rhodecode/apps/repository/views/repo_settings_advanced.py:85
728 738 msgid "updated commit cache"
729 739 msgstr ""
730 740
731 741 #: rhodecode/apps/repo_group/views/repo_group_advanced.py:105
732 742 #, python-format
733 743 msgid "Removed repository group `%s`"
734 744 msgstr ""
735 745
736 746 #: rhodecode/apps/repo_group/views/repo_group_advanced.py:109
737 747 #, python-format
738 748 msgid "Error occurred during deletion of repository group %s"
739 749 msgstr ""
740 750
741 #: rhodecode/apps/repo_group/views/repo_group_permissions.py:74
751 #: rhodecode/apps/repo_group/views/repo_group_permissions.py:75
742 752 #: rhodecode/apps/user_group/views/__init__.py:346
743 753 msgid "Cannot change permission for yourself as admin"
744 754 msgstr ""
745 755
746 #: rhodecode/apps/repo_group/views/repo_group_permissions.py:98
756 #: rhodecode/apps/repo_group/views/repo_group_permissions.py:99
747 757 msgid "Repository Group permissions updated"
748 758 msgstr ""
749 759
750 760 #: rhodecode/apps/repo_group/views/repo_group_settings.py:174
751 761 msgid "Repository Group `{}` updated successfully"
752 762 msgstr ""
753 763
754 764 #: rhodecode/apps/repo_group/views/repo_group_settings.py:179
755 765 #, python-format
756 766 msgid "Error occurred during update of repository group %s"
757 767 msgstr ""
758 768
759 769 #: rhodecode/apps/repository/views/repo_caches.py:80
760 770 msgid "Cache invalidation successful"
761 771 msgstr ""
762 772
763 773 #: rhodecode/apps/repository/views/repo_caches.py:84
764 774 msgid "An error occurred during cache invalidation"
765 775 msgstr ""
766 776
767 777 #: rhodecode/apps/repository/views/repo_changelog.py:66
768 778 #: rhodecode/apps/repository/views/repo_compare.py:64
769 #: rhodecode/apps/repository/views/repo_pull_requests.py:728
779 #: rhodecode/apps/repository/views/repo_pull_requests.py:763
770 780 msgid "There are no commits yet"
771 781 msgstr ""
772 782
773 783 #: rhodecode/apps/repository/views/repo_changelog.py:71
774 784 #: rhodecode/apps/repository/views/repo_files.py:185
775 785 #: rhodecode/apps/repository/views/repo_files.py:205
776 786 msgid "No such commit exists for this repository"
777 787 msgstr ""
778 788
779 789 #: rhodecode/apps/repository/views/repo_checks.py:103
780 790 #, python-format
781 791 msgid "Created repository %s from %s"
782 792 msgstr ""
783 793
784 794 #: rhodecode/apps/repository/views/repo_checks.py:112
785 795 #, python-format
786 796 msgid "Forked repository %s as %s"
787 797 msgstr ""
788 798
789 799 #: rhodecode/apps/repository/views/repo_checks.py:115
790 800 #, python-format
791 801 msgid "Created repository %s"
792 802 msgstr ""
793 803
794 804 #: rhodecode/apps/repository/views/repo_commits.py:111
795 805 msgid "No such commit exists. Org exception: `{}`"
796 806 msgstr ""
797 807
798 808 #: rhodecode/apps/repository/views/repo_commits.py:330
799 #: rhodecode/apps/repository/views/repo_pull_requests.py:1362
809 #: rhodecode/apps/repository/views/repo_pull_requests.py:1399
800 810 #, python-format
801 811 msgid "Status change %(transition_icon)s %(status)s"
802 812 msgstr ""
803 813
804 814 #: rhodecode/apps/repository/views/repo_commits.py:375
805 815 msgid "Changing the status of a commit associated with a closed pull request is not allowed"
806 816 msgstr ""
807 817
808 818 #: rhodecode/apps/repository/views/repo_compare.py:102
809 819 msgid "Select commit"
810 820 msgstr ""
811 821
812 822 #: rhodecode/apps/repository/views/repo_compare.py:173
813 823 msgid "Could not find the source repo: `{}`"
814 824 msgstr ""
815 825
816 826 #: rhodecode/apps/repository/views/repo_compare.py:181
817 827 msgid "Could not find the target repo: `{}`"
818 828 msgstr ""
819 829
820 830 #: rhodecode/apps/repository/views/repo_compare.py:192
821 831 msgid "The comparison of two different kinds of remote repos is not available"
822 832 msgstr ""
823 833
824 834 #: rhodecode/apps/repository/views/repo_compare.py:225
825 835 msgid "Could not compare repos with different large file settings"
826 836 msgstr ""
827 837
828 838 #: rhodecode/apps/repository/views/repo_compare.py:271
829 839 #, python-format
830 840 msgid "Repositories unrelated. Cannot compare commit %(commit1)s from repository %(repo1)s with commit %(commit2)s from repository %(repo2)s."
831 841 msgstr ""
832 842
833 843 #: rhodecode/apps/repository/views/repo_feed.py:68
834 844 #, python-format
835 845 msgid "Changes on %s repository"
836 846 msgstr ""
837 847
838 848 #: rhodecode/apps/repository/views/repo_feed.py:69
839 849 #, python-format
840 850 msgid "%s %s feed"
841 851 msgstr ""
842 852
843 853 #: rhodecode/apps/repository/views/repo_files.py:96
844 854 #, python-format
845 855 msgid "This repository has been locked by %s on %s"
846 856 msgstr ""
847 857
848 858 #: rhodecode/apps/repository/views/repo_files.py:109
849 859 msgid "Cannot modify file. Given commit `{}` is not head of a branch."
850 860 msgstr ""
851 861
852 862 #: rhodecode/apps/repository/views/repo_files.py:127
853 863 msgid "Branch `{}` changes forbidden by rule {}."
854 864 msgstr ""
855 865
856 866 #: rhodecode/apps/repository/views/repo_files.py:175
857 867 msgid "Click here to add a new file."
858 868 msgstr ""
859 869
860 870 #: rhodecode/apps/repository/views/repo_files.py:180
861 871 #, python-format
862 872 msgid "There are no files yet. %s"
863 873 msgstr ""
864 874
865 875 #: rhodecode/apps/repository/views/repo_files.py:341
866 876 msgid "Downloads disabled"
867 877 msgstr ""
868 878
869 879 #: rhodecode/apps/repository/views/repo_files.py:347
870 880 msgid "Unknown archive type for: `{}`"
871 881 msgstr ""
872 882
873 883 #: rhodecode/apps/repository/views/repo_files.py:353
874 884 msgid "Unknown commit_id {}"
875 885 msgstr ""
876 886
877 887 #: rhodecode/apps/repository/views/repo_files.py:356
878 888 msgid "Empty repository"
879 889 msgstr ""
880 890
881 891 #: rhodecode/apps/repository/views/repo_files.py:361
882 892 msgid "No node at path {} for this repository"
883 893 msgstr ""
884 894
885 895 #: rhodecode/apps/repository/views/repo_files.py:410
886 896 msgid "Unknown archive type"
887 897 msgstr ""
888 898
889 #: rhodecode/apps/repository/views/repo_files.py:989
899 #: rhodecode/apps/repository/views/repo_files.py:990
890 900 msgid "Changesets"
891 901 msgstr ""
892 902
893 #: rhodecode/apps/repository/views/repo_files.py:1010
903 #: rhodecode/apps/repository/views/repo_files.py:1011
894 904 #: rhodecode/apps/repository/views/repo_summary.py:264
895 #: rhodecode/model/pull_request.py:1572 rhodecode/model/scm.py:995
905 #: rhodecode/model/pull_request.py:1740 rhodecode/model/scm.py:995
896 906 #: rhodecode/templates/base/vcs_settings.mako:235
897 907 #: rhodecode/templates/summary/components.mako:10
898 908 msgid "Branches"
899 909 msgstr ""
900 910
901 #: rhodecode/apps/repository/views/repo_files.py:1014
911 #: rhodecode/apps/repository/views/repo_files.py:1015
902 912 #: rhodecode/model/scm.py:1012 rhodecode/templates/base/vcs_settings.mako:260
903 913 #: rhodecode/templates/summary/components.mako:34
904 914 msgid "Tags"
905 915 msgstr ""
906 916
907 #: rhodecode/apps/repository/views/repo_files.py:1118
908 #: rhodecode/apps/repository/views/repo_files.py:1146
917 #: rhodecode/apps/repository/views/repo_files.py:1169
918 #: rhodecode/apps/repository/views/repo_files.py:1197
909 919 msgid "Deleted file {} via RhodeCode Enterprise"
910 920 msgstr ""
911 921
912 #: rhodecode/apps/repository/views/repo_files.py:1167
922 #: rhodecode/apps/repository/views/repo_files.py:1218
913 923 msgid "Successfully deleted file `{}`"
914 924 msgstr ""
915 925
916 #: rhodecode/apps/repository/views/repo_files.py:1171
917 #: rhodecode/apps/repository/views/repo_files.py:1288
918 #: rhodecode/apps/repository/views/repo_files.py:1419
919 #: rhodecode/apps/repository/views/repo_files.py:1542
926 #: rhodecode/apps/repository/views/repo_files.py:1222
927 #: rhodecode/apps/repository/views/repo_files.py:1339
928 #: rhodecode/apps/repository/views/repo_files.py:1470
929 #: rhodecode/apps/repository/views/repo_files.py:1593
920 930 msgid "Error occurred during commit"
921 931 msgstr ""
922 932
923 #: rhodecode/apps/repository/views/repo_files.py:1203
924 #: rhodecode/apps/repository/views/repo_files.py:1234
933 #: rhodecode/apps/repository/views/repo_files.py:1254
934 #: rhodecode/apps/repository/views/repo_files.py:1285
925 935 msgid "Edited file {} via RhodeCode Enterprise"
926 936 msgstr ""
927 937
928 #: rhodecode/apps/repository/views/repo_files.py:1257
938 #: rhodecode/apps/repository/views/repo_files.py:1308
929 939 msgid "No changes detected on {}"
930 940 msgstr ""
931 941
932 #: rhodecode/apps/repository/views/repo_files.py:1281
942 #: rhodecode/apps/repository/views/repo_files.py:1332
933 943 msgid "Successfully committed changes to file `{}`"
934 944 msgstr ""
935 945
936 #: rhodecode/apps/repository/views/repo_files.py:1322
937 #: rhodecode/apps/repository/views/repo_files.py:1363
946 #: rhodecode/apps/repository/views/repo_files.py:1373
947 #: rhodecode/apps/repository/views/repo_files.py:1414
938 948 msgid "Added file via RhodeCode Enterprise"
939 949 msgstr ""
940 950
941 #: rhodecode/apps/repository/views/repo_files.py:1379
951 #: rhodecode/apps/repository/views/repo_files.py:1430
942 952 msgid "No filename specified"
943 953 msgstr ""
944 954
945 #: rhodecode/apps/repository/views/repo_files.py:1404
955 #: rhodecode/apps/repository/views/repo_files.py:1455
946 956 msgid "Successfully committed new file `{}`"
947 957 msgstr ""
948 958
949 #: rhodecode/apps/repository/views/repo_files.py:1412
950 #: rhodecode/apps/repository/views/repo_files.py:1524
959 #: rhodecode/apps/repository/views/repo_files.py:1463
960 #: rhodecode/apps/repository/views/repo_files.py:1575
951 961 msgid "The location specified must be a relative path and must not contain .. in the path"
952 962 msgstr ""
953 963
954 #: rhodecode/apps/repository/views/repo_files.py:1469
964 #: rhodecode/apps/repository/views/repo_files.py:1520
955 965 msgid "Uploaded file via RhodeCode Enterprise"
956 966 msgstr ""
957 967
958 #: rhodecode/apps/repository/views/repo_files.py:1513
968 #: rhodecode/apps/repository/views/repo_files.py:1564
959 969 msgid "Successfully committed {} new files"
960 970 msgstr ""
961 971
962 #: rhodecode/apps/repository/views/repo_files.py:1515
972 #: rhodecode/apps/repository/views/repo_files.py:1566
963 973 msgid "Successfully committed 1 new file"
964 974 msgstr ""
965 975
966 976 #: rhodecode/apps/repository/views/repo_forks.py:146
967 977 msgid "Compare fork"
968 978 msgstr ""
969 979
970 980 #: rhodecode/apps/repository/views/repo_forks.py:251
971 981 #, python-format
972 982 msgid "An error occurred during repository forking %s"
973 983 msgstr ""
974 984
975 #: rhodecode/apps/repository/views/repo_permissions.py:55
985 #: rhodecode/apps/repository/views/repo_permissions.py:57
976 986 msgid "Explicitly add user or user group with write+ permission to modify their branch permissions."
977 987 msgstr ""
978 988
979 #: rhodecode/apps/repository/views/repo_permissions.py:90
989 #: rhodecode/apps/repository/views/repo_permissions.py:92
980 990 msgid "Repository access permissions updated"
981 991 msgstr ""
982 992
983 #: rhodecode/apps/repository/views/repo_permissions.py:112
993 #: rhodecode/apps/repository/views/repo_permissions.py:126
984 994 msgid "Repository `{}` private mode set successfully"
985 995 msgstr ""
986 996
987 #: rhodecode/apps/repository/views/repo_permissions.py:116
997 #: rhodecode/apps/repository/views/repo_permissions.py:134
988 998 #: rhodecode/apps/repository/views/repo_settings.py:176
989 999 msgid "Error occurred during update of repository {}"
990 1000 msgstr ""
991 1001
992 #: rhodecode/apps/repository/views/repo_pull_requests.py:758
1002 #: rhodecode/apps/repository/views/repo_pull_requests.py:287
1003 msgid "Pull Request state was force changed to `{}`"
1004 msgstr ""
1005
1006 #: rhodecode/apps/repository/views/repo_pull_requests.py:793
993 1007 msgid "Commit does not exist"
994 1008 msgstr ""
995 1009
996 #: rhodecode/apps/repository/views/repo_pull_requests.py:910
1010 #: rhodecode/apps/repository/views/repo_pull_requests.py:945
997 1011 msgid "Error creating pull request: {}"
998 1012 msgstr ""
999 1013
1000 #: rhodecode/apps/repository/views/repo_pull_requests.py:929
1014 #: rhodecode/apps/repository/views/repo_pull_requests.py:965
1001 1015 msgid "source_repo or target repo not found"
1002 1016 msgstr ""
1003 1017
1004 #: rhodecode/apps/repository/views/repo_pull_requests.py:940
1018 #: rhodecode/apps/repository/views/repo_pull_requests.py:976
1005 1019 msgid "Not Enough permissions to source repo `{}`."
1006 1020 msgstr ""
1007 1021
1008 #: rhodecode/apps/repository/views/repo_pull_requests.py:955
1022 #: rhodecode/apps/repository/views/repo_pull_requests.py:991
1009 1023 msgid "Not Enough permissions to target repo `{}`."
1010 1024 msgstr ""
1011 1025
1012 #: rhodecode/apps/repository/views/repo_pull_requests.py:1018
1026 #: rhodecode/apps/repository/views/repo_pull_requests.py:1055
1013 1027 msgid "Successfully opened new pull request"
1014 1028 msgstr ""
1015 1029
1016 #: rhodecode/apps/repository/views/repo_pull_requests.py:1021
1030 #: rhodecode/apps/repository/views/repo_pull_requests.py:1058
1017 1031 msgid "Error occurred during creation of this pull request."
1018 1032 msgstr ""
1019 1033
1020 #: rhodecode/apps/repository/views/repo_pull_requests.py:1053
1021 #: rhodecode/apps/repository/views/repo_pull_requests.py:1108
1034 #: rhodecode/apps/repository/views/repo_pull_requests.py:1090
1035 #: rhodecode/apps/repository/views/repo_pull_requests.py:1145
1022 1036 msgid "Cannot update closed pull requests."
1023 1037 msgstr ""
1024 1038
1025 #: rhodecode/apps/repository/views/repo_pull_requests.py:1075
1039 #: rhodecode/apps/repository/views/repo_pull_requests.py:1112
1026 1040 msgid "Cannot update pull requests commits in state other than `{}`. Current state is: `{}`"
1027 1041 msgstr ""
1028 1042
1029 #: rhodecode/apps/repository/views/repo_pull_requests.py:1114
1043 #: rhodecode/apps/repository/views/repo_pull_requests.py:1151
1030 1044 msgid "Pull request title & description updated."
1031 1045 msgstr ""
1032 1046
1033 #: rhodecode/apps/repository/views/repo_pull_requests.py:1136
1047 #: rhodecode/apps/repository/views/repo_pull_requests.py:1173
1034 1048 msgid "Pull request updated to \"{source_commit_id}\" with {count_added} added, {count_removed} removed commits. Source of changes: {change_source}"
1035 1049 msgstr ""
1036 1050
1037 #: rhodecode/apps/repository/views/repo_pull_requests.py:1150
1051 #: rhodecode/apps/repository/views/repo_pull_requests.py:1187
1038 1052 msgid "Reload page"
1039 1053 msgstr ""
1040 1054
1041 #: rhodecode/apps/repository/views/repo_pull_requests.py:1185
1055 #: rhodecode/apps/repository/views/repo_pull_requests.py:1222
1042 1056 msgid "Cannot merge pull requests in state other than `{}`. Current state is: `{}`"
1043 1057 msgstr ""
1044 1058
1045 #: rhodecode/apps/repository/views/repo_pull_requests.py:1231
1059 #: rhodecode/apps/repository/views/repo_pull_requests.py:1268
1046 1060 msgid "Pull request was successfully merged and closed."
1047 1061 msgstr ""
1048 1062
1049 #: rhodecode/apps/repository/views/repo_pull_requests.py:1255
1063 #: rhodecode/apps/repository/views/repo_pull_requests.py:1292
1050 1064 msgid "Pull request reviewers updated."
1051 1065 msgstr ""
1052 1066
1053 #: rhodecode/apps/repository/views/repo_pull_requests.py:1288
1067 #: rhodecode/apps/repository/views/repo_pull_requests.py:1325
1054 1068 msgid "Successfully deleted pull request"
1055 1069 msgstr ""
1056 1070
1057 1071 #: rhodecode/apps/repository/views/repo_settings.py:172
1058 1072 msgid "Repository `{}` updated successfully"
1059 1073 msgstr ""
1060 1074
1061 1075 #: rhodecode/apps/repository/views/repo_settings.py:209
1062 1076 msgid "Unlocked"
1063 1077 msgstr ""
1064 1078
1065 1079 #: rhodecode/apps/repository/views/repo_settings.py:214
1066 1080 msgid "Locked"
1067 1081 msgstr ""
1068 1082
1069 1083 #: rhodecode/apps/repository/views/repo_settings.py:216
1070 1084 #, python-format
1071 1085 msgid "Repository has been %s"
1072 1086 msgstr ""
1073 1087
1074 1088 #: rhodecode/apps/repository/views/repo_settings.py:220
1075 #: rhodecode/apps/repository/views/repo_settings_advanced.py:297
1089 #: rhodecode/apps/repository/views/repo_settings_advanced.py:305
1076 1090 msgid "An error occurred during unlocking"
1077 1091 msgstr ""
1078 1092
1079 1093 #: rhodecode/apps/repository/views/repo_settings.py:264
1080 1094 msgid "An error occurred during deletion of repository stats"
1081 1095 msgstr ""
1082 1096
1083 #: rhodecode/apps/repository/views/repo_settings_advanced.py:106
1097 #: rhodecode/apps/repository/views/repo_settings_advanced.py:114
1084 1098 #, python-format
1085 1099 msgid "Archived repository `%s`"
1086 1100 msgstr ""
1087 1101
1088 #: rhodecode/apps/repository/views/repo_settings_advanced.py:111
1102 #: rhodecode/apps/repository/views/repo_settings_advanced.py:119
1089 1103 #, python-format
1090 1104 msgid "An error occurred during archiving of `%s`"
1091 1105 msgstr ""
1092 1106
1093 #: rhodecode/apps/repository/views/repo_settings_advanced.py:149
1107 #: rhodecode/apps/repository/views/repo_settings_advanced.py:157
1094 1108 #, python-format
1095 1109 msgid "Detached %s forks"
1096 1110 msgstr ""
1097 1111
1098 #: rhodecode/apps/repository/views/repo_settings_advanced.py:151
1112 #: rhodecode/apps/repository/views/repo_settings_advanced.py:159
1099 1113 #, python-format
1100 1114 msgid "Deleted %s forks"
1101 1115 msgstr ""
1102 1116
1103 #: rhodecode/apps/repository/views/repo_settings_advanced.py:160
1104 #, python-format
1105 msgid "Deleted repository `%s`"
1106 msgstr ""
1107
1108 #: rhodecode/apps/repository/views/repo_settings_advanced.py:167
1109 msgid "detach or delete"
1110 msgstr ""
1111
1112 1117 #: rhodecode/apps/repository/views/repo_settings_advanced.py:168
1118 #, python-format
1119 msgid "Deleted repository `%s`"
1120 msgstr ""
1121
1122 #: rhodecode/apps/repository/views/repo_settings_advanced.py:175
1123 msgid "detach or delete"
1124 msgstr ""
1125
1126 #: rhodecode/apps/repository/views/repo_settings_advanced.py:176
1113 1127 msgid "Cannot delete `{repo}` it still contains attached forks. Try using {delete_or_detach} option."
1114 1128 msgstr ""
1115 1129
1116 #: rhodecode/apps/repository/views/repo_settings_advanced.py:183
1130 #: rhodecode/apps/repository/views/repo_settings_advanced.py:191
1117 1131 msgid "Cannot delete `{repo}` it still contains {num} attached pull requests. Consider archiving the repository instead."
1118 1132 msgstr ""
1119 1133
1120 #: rhodecode/apps/repository/views/repo_settings_advanced.py:192
1134 #: rhodecode/apps/repository/views/repo_settings_advanced.py:200
1121 1135 #, python-format
1122 1136 msgid "An error occurred during deletion of `%s`"
1123 1137 msgstr ""
1124 1138
1125 #: rhodecode/apps/repository/views/repo_settings_advanced.py:217
1139 #: rhodecode/apps/repository/views/repo_settings_advanced.py:225
1126 1140 msgid "Updated repository visibility in public journal"
1127 1141 msgstr ""
1128 1142
1129 #: rhodecode/apps/repository/views/repo_settings_advanced.py:221
1143 #: rhodecode/apps/repository/views/repo_settings_advanced.py:229
1130 1144 msgid "An error occurred during setting this repository in public journal"
1131 1145 msgstr ""
1132 1146
1133 #: rhodecode/apps/repository/views/repo_settings_advanced.py:257
1147 #: rhodecode/apps/repository/views/repo_settings_advanced.py:265
1134 1148 msgid "Nothing"
1135 1149 msgstr ""
1136 1150
1137 #: rhodecode/apps/repository/views/repo_settings_advanced.py:260
1151 #: rhodecode/apps/repository/views/repo_settings_advanced.py:268
1138 1152 #, python-format
1139 1153 msgid "Marked repo %s as fork of %s"
1140 1154 msgstr ""
1141 1155
1142 #: rhodecode/apps/repository/views/repo_settings_advanced.py:267
1156 #: rhodecode/apps/repository/views/repo_settings_advanced.py:275
1143 1157 msgid "An error occurred during this operation"
1144 1158 msgstr ""
1145 1159
1146 #: rhodecode/apps/repository/views/repo_settings_advanced.py:291
1160 #: rhodecode/apps/repository/views/repo_settings_advanced.py:299
1147 1161 msgid "Locked repository"
1148 1162 msgstr ""
1149 1163
1150 #: rhodecode/apps/repository/views/repo_settings_advanced.py:294
1164 #: rhodecode/apps/repository/views/repo_settings_advanced.py:302
1151 1165 msgid "Unlocked repository"
1152 1166 msgstr ""
1153 1167
1154 #: rhodecode/apps/repository/views/repo_settings_advanced.py:314
1168 #: rhodecode/apps/repository/views/repo_settings_advanced.py:322
1155 1169 msgid "installed updated hooks into this repository"
1156 1170 msgstr ""
1157 1171
1158 1172 #: rhodecode/apps/repository/views/repo_settings_fields.py:86
1159 1173 msgid "An error occurred during creation of field"
1160 1174 msgstr ""
1161 1175
1162 1176 #: rhodecode/apps/repository/views/repo_settings_fields.py:108
1163 1177 msgid "An error occurred during removal of field"
1164 1178 msgstr ""
1165 1179
1166 1180 #: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:86
1167 1181 msgid "Error occurred during deleting issue tracker entry"
1168 1182 msgstr ""
1169 1183
1170 1184 #: rhodecode/apps/repository/views/repo_settings_remote.py:64
1171 1185 msgid "Pulled from remote location"
1172 1186 msgstr ""
1173 1187
1174 1188 #: rhodecode/apps/repository/views/repo_settings_remote.py:67
1175 1189 msgid "An error occurred during pull from remote location"
1176 1190 msgstr ""
1177 1191
1178 1192 #: rhodecode/apps/repository/views/repo_settings_vcs.py:147
1179 1193 msgid "Error occurred during updating repository VCS settings"
1180 1194 msgstr ""
1181 1195
1182 1196 #: rhodecode/apps/repository/views/repo_summary.py:240
1183 1197 #: rhodecode/templates/admin/permissions/permissions.mako:42
1184 1198 #: rhodecode/templates/summary/components.mako:8
1185 1199 msgid "Branch"
1186 1200 msgstr ""
1187 1201
1188 1202 #: rhodecode/apps/repository/views/repo_summary.py:241
1189 1203 #: rhodecode/templates/summary/components.mako:32
1190 1204 msgid "Tag"
1191 1205 msgstr ""
1192 1206
1193 1207 #: rhodecode/apps/repository/views/repo_summary.py:242
1194 1208 #: rhodecode/templates/summary/components.mako:44
1195 1209 msgid "Bookmark"
1196 1210 msgstr ""
1197 1211
1198 1212 #: rhodecode/apps/repository/views/repo_summary.py:265
1199 1213 msgid "Closed branches"
1200 1214 msgstr ""
1201 1215
1202 1216 #: rhodecode/apps/ssh_support/events.py:29
1203 1217 msgid "RhodeCode SSH Key files changed."
1204 1218 msgstr ""
1205 1219
1206 1220 #: rhodecode/apps/svn_support/events.py:30
1207 1221 msgid "Configuration for Apache mad_dav_svn changed."
1208 1222 msgstr ""
1209 1223
1210 1224 #: rhodecode/apps/user_group/views/__init__.py:188
1211 1225 #, python-format
1212 1226 msgid "Updated user group %s"
1213 1227 msgstr ""
1214 1228
1215 1229 #: rhodecode/apps/user_group/views/__init__.py:224
1216 1230 #, python-format
1217 1231 msgid "Error occurred during update of user group %s"
1218 1232 msgstr ""
1219 1233
1220 1234 #: rhodecode/apps/user_group/views/__init__.py:250
1221 1235 msgid "Successfully deleted user group"
1222 1236 msgstr ""
1223 1237
1224 1238 #: rhodecode/apps/user_group/views/__init__.py:255
1225 1239 msgid "An error occurred during deletion of user group"
1226 1240 msgstr ""
1227 1241
1228 1242 #: rhodecode/apps/user_group/views/__init__.py:359
1229 1243 msgid "Target group cannot be the same"
1230 1244 msgstr ""
1231 1245
1232 1246 #: rhodecode/apps/user_group/views/__init__.py:374
1233 1247 msgid "User Group permissions updated"
1234 1248 msgstr ""
1235 1249
1236 1250 #: rhodecode/apps/user_group/views/__init__.py:459
1237 1251 msgid "User Group global permissions updated successfully"
1238 1252 msgstr ""
1239 1253
1240 1254 #: rhodecode/apps/user_group/views/__init__.py:541
1241 1255 msgid "User Group synchronization updated successfully"
1242 1256 msgstr ""
1243 1257
1244 1258 #: rhodecode/apps/user_group/views/__init__.py:545
1245 1259 msgid "An error occurred during synchronization update"
1246 1260 msgstr ""
1247 1261
1248 1262 #: rhodecode/authentication/routes.py:61
1249 1263 #: rhodecode/templates/admin/auth/plugin_settings.mako:14
1250 1264 msgid "Authentication Plugins"
1251 1265 msgstr ""
1252 1266
1253 1267 #: rhodecode/authentication/schema.py:36
1254 1268 msgid "Enable or disable this authentication plugin."
1255 1269 msgstr ""
1256 1270
1257 1271 #: rhodecode/authentication/schema.py:38 rhodecode/integrations/schema.py:32
1258 #: rhodecode/model/permission.py:111 rhodecode/model/permission.py:115
1259 #: rhodecode/model/permission.py:119 rhodecode/model/permission.py:123
1260 #: rhodecode/model/permission.py:127 rhodecode/model/permission.py:131
1272 #: rhodecode/model/permission.py:110 rhodecode/model/permission.py:114
1273 #: rhodecode/model/permission.py:118 rhodecode/model/permission.py:122
1274 #: rhodecode/model/permission.py:126 rhodecode/model/permission.py:130
1261 1275 #: rhodecode/model/validation_schema/schemas/integration_schema.py:195
1262 1276 #: rhodecode/templates/admin/auth/auth_settings.mako:64
1263 1277 #: rhodecode/templates/admin/integrations/list.mako:71
1264 1278 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:23
1265 1279 msgid "Enabled"
1266 1280 msgstr ""
1267 1281
1268 1282 #: rhodecode/authentication/schema.py:44
1269 1283 msgid ""
1270 1284 "Amount of seconds to cache the authentication and permissions check response call for this plugin. \n"
1271 1285 "Useful for expensive calls like LDAP to improve the performance of the system (0 means disabled)."
1272 1286 msgstr ""
1273 1287
1274 1288 #: rhodecode/authentication/schema.py:49
1275 1289 msgid "Auth Cache TTL"
1276 1290 msgstr ""
1277 1291
1278 1292 #: rhodecode/authentication/views.py:92
1279 1293 msgid "Errors exist when saving plugin settings. Please check the form inputs."
1280 1294 msgstr ""
1281 1295
1282 #: rhodecode/authentication/views.py:104 rhodecode/authentication/views.py:163
1296 #: rhodecode/authentication/views.py:105 rhodecode/authentication/views.py:164
1283 1297 msgid "Auth settings updated successfully."
1284 1298 msgstr ""
1285 1299
1286 #: rhodecode/authentication/views.py:166
1300 #: rhodecode/authentication/views.py:167
1287 1301 msgid "Errors exist when saving plugin setting. Please check the form inputs."
1288 1302 msgstr ""
1289 1303
1290 #: rhodecode/authentication/views.py:174
1304 #: rhodecode/authentication/views.py:175
1291 1305 msgid "Error occurred during update of auth settings."
1292 1306 msgstr ""
1293 1307
1294 1308 #: rhodecode/authentication/plugins/auth_crowd.py:60
1295 1309 msgid "The FQDN or IP of the Atlassian CROWD Server"
1296 1310 msgstr ""
1297 1311
1298 1312 #: rhodecode/authentication/plugins/auth_crowd.py:62
1299 1313 msgid "Host"
1300 1314 msgstr ""
1301 1315
1302 1316 #: rhodecode/authentication/plugins/auth_crowd.py:67
1303 1317 msgid "The Port in use by the Atlassian CROWD Server"
1304 1318 msgstr ""
1305 1319
1306 1320 #: rhodecode/authentication/plugins/auth_crowd.py:69
1307 #: rhodecode/authentication/plugins/auth_ldap.py:254
1321 #: rhodecode/authentication/plugins/auth_ldap.py:270
1308 1322 msgid "Port"
1309 1323 msgstr ""
1310 1324
1311 1325 #: rhodecode/authentication/plugins/auth_crowd.py:75
1312 1326 msgid "The Application Name to authenticate to CROWD"
1313 1327 msgstr ""
1314 1328
1315 1329 #: rhodecode/authentication/plugins/auth_crowd.py:77
1316 1330 msgid "Application Name"
1317 1331 msgstr ""
1318 1332
1319 1333 #: rhodecode/authentication/plugins/auth_crowd.py:82
1320 1334 msgid "The password to authenticate to CROWD"
1321 1335 msgstr ""
1322 1336
1323 1337 #: rhodecode/authentication/plugins/auth_crowd.py:84
1324 1338 msgid "Application Password"
1325 1339 msgstr ""
1326 1340
1327 1341 #: rhodecode/authentication/plugins/auth_crowd.py:89
1328 1342 msgid "A comma separated list of group names that identify users as RhodeCode Administrators"
1329 1343 msgstr ""
1330 1344
1331 1345 #: rhodecode/authentication/plugins/auth_crowd.py:93
1332 1346 msgid "Admin Groups"
1333 1347 msgstr ""
1334 1348
1335 1349 #: rhodecode/authentication/plugins/auth_crowd.py:217
1336 1350 msgid "CROWD"
1337 1351 msgstr ""
1338 1352
1339 1353 #: rhodecode/authentication/plugins/auth_headers.py:54
1340 1354 msgid "Header to extract the user from"
1341 1355 msgstr ""
1342 1356
1343 1357 #: rhodecode/authentication/plugins/auth_headers.py:56
1344 1358 msgid "Header"
1345 1359 msgstr ""
1346 1360
1347 1361 #: rhodecode/authentication/plugins/auth_headers.py:61
1348 1362 msgid "Header to extract the user from when main one fails"
1349 1363 msgstr ""
1350 1364
1351 1365 #: rhodecode/authentication/plugins/auth_headers.py:63
1352 1366 msgid "Fallback header"
1353 1367 msgstr ""
1354 1368
1355 1369 #: rhodecode/authentication/plugins/auth_headers.py:68
1356 1370 msgid "Perform cleaning of user, if passed user has @ in username then first part before @ is taken. If there's \\ in the username only the part after \\ is taken"
1357 1371 msgstr ""
1358 1372
1359 1373 #: rhodecode/authentication/plugins/auth_headers.py:73
1360 1374 msgid "Clean username"
1361 1375 msgstr ""
1362 1376
1363 1377 #: rhodecode/authentication/plugins/auth_headers.py:99
1364 1378 msgid "Headers"
1365 1379 msgstr ""
1366 1380
1367 1381 #: rhodecode/authentication/plugins/auth_jasig_cas.py:62
1368 1382 msgid "The url of the Jasig CAS REST service"
1369 1383 msgstr ""
1370 1384
1371 1385 #: rhodecode/authentication/plugins/auth_jasig_cas.py:64
1372 1386 msgid "URL"
1373 1387 msgstr ""
1374 1388
1375 1389 #: rhodecode/authentication/plugins/auth_jasig_cas.py:93
1376 1390 msgid "Jasig-CAS"
1377 1391 msgstr ""
1378 1392
1379 #: rhodecode/authentication/plugins/auth_ldap.py:242
1393 #: rhodecode/authentication/plugins/auth_ldap.py:258
1380 1394 msgid ""
1381 1395 "Host[s] of the LDAP Server \n"
1382 1396 "(e.g., 192.168.2.154, or ldap-server.domain.com.\n"
1383 1397 " Multiple servers can be specified using commas"
1384 1398 msgstr ""
1385 1399
1386 #: rhodecode/authentication/plugins/auth_ldap.py:246
1400 #: rhodecode/authentication/plugins/auth_ldap.py:262
1387 1401 msgid "LDAP Host"
1388 1402 msgstr ""
1389 1403
1390 #: rhodecode/authentication/plugins/auth_ldap.py:251
1391 msgid "Custom port that the LDAP server is listening on. Default value is: 389, use 689 for LDAPS(SSL)"
1392 msgstr ""
1393
1394 #: rhodecode/authentication/plugins/auth_ldap.py:261
1404 #: rhodecode/authentication/plugins/auth_ldap.py:267
1405 msgid "Custom port that the LDAP server is listening on. Default value is: 389, use 636 for LDAPS (SSL)"
1406 msgstr ""
1407
1408 #: rhodecode/authentication/plugins/auth_ldap.py:277
1395 1409 msgid "Timeout for LDAP connection"
1396 1410 msgstr ""
1397 1411
1398 #: rhodecode/authentication/plugins/auth_ldap.py:263
1412 #: rhodecode/authentication/plugins/auth_ldap.py:279
1399 1413 msgid "Connection timeout"
1400 1414 msgstr ""
1401 1415
1402 #: rhodecode/authentication/plugins/auth_ldap.py:270
1416 #: rhodecode/authentication/plugins/auth_ldap.py:286
1403 1417 msgid ""
1404 1418 "Optional user DN/account to connect to LDAP if authentication is required. \n"
1405 1419 "e.g., cn=admin,dc=mydomain,dc=com, or uid=root,cn=users,dc=mydomain,dc=com, or admin@mydomain.com"
1406 1420 msgstr ""
1407 1421
1408 #: rhodecode/authentication/plugins/auth_ldap.py:275
1409 msgid "Account"
1410 msgstr ""
1411
1412 #: rhodecode/authentication/plugins/auth_ldap.py:280
1422 #: rhodecode/authentication/plugins/auth_ldap.py:291
1423 msgid "Bind account"
1424 msgstr ""
1425
1426 #: rhodecode/authentication/plugins/auth_ldap.py:296
1413 1427 msgid "Password to authenticate for given user DN."
1414 1428 msgstr ""
1415 1429
1416 #: rhodecode/authentication/plugins/auth_ldap.py:283
1417 #: rhodecode/integrations/types/webhook.py:89 rhodecode/templates/login.mako:51
1418 #: rhodecode/templates/register.mako:62
1419 #: rhodecode/templates/admin/my_account/my_account.mako:31
1420 #: rhodecode/templates/admin/users/user_add.mako:44
1421 #: rhodecode/templates/debug_style/login.html:45
1422 msgid "Password"
1423 msgstr ""
1424
1425 #: rhodecode/authentication/plugins/auth_ldap.py:288
1430 #: rhodecode/authentication/plugins/auth_ldap.py:299
1431 msgid "Bind account password"
1432 msgstr ""
1433
1434 #: rhodecode/authentication/plugins/auth_ldap.py:304
1426 1435 msgid "TLS Type"
1427 1436 msgstr ""
1428 1437
1429 #: rhodecode/authentication/plugins/auth_ldap.py:289
1438 #: rhodecode/authentication/plugins/auth_ldap.py:305
1430 1439 msgid "Connection Security"
1431 1440 msgstr ""
1432 1441
1433 #: rhodecode/authentication/plugins/auth_ldap.py:295
1442 #: rhodecode/authentication/plugins/auth_ldap.py:311
1434 1443 msgid ""
1435 1444 "Require Cert over TLS?. Self-signed and custom certificates can be used when\n"
1436 1445 " `RhodeCode Certificate` found in admin > settings > system info page is extended."
1437 1446 msgstr ""
1438 1447
1439 #: rhodecode/authentication/plugins/auth_ldap.py:298
1448 #: rhodecode/authentication/plugins/auth_ldap.py:314
1440 1449 msgid "Certificate Checks"
1441 1450 msgstr ""
1442 1451
1443 #: rhodecode/authentication/plugins/auth_ldap.py:304
1444 msgid ""
1445 "This specifies the PEM-format file path containing certificates for use in TLS connection.\n"
1446 "If not specified `TLS Cert dir` will be used"
1447 msgstr ""
1448
1449 #: rhodecode/authentication/plugins/auth_ldap.py:307
1450 msgid "TLS Cert file"
1451 msgstr ""
1452
1453 #: rhodecode/authentication/plugins/auth_ldap.py:313
1454 msgid "This specifies the path of a directory that contains individual CA certificates in separate files."
1455 msgstr ""
1456
1457 #: rhodecode/authentication/plugins/auth_ldap.py:315
1458 msgid "TLS Cert dir"
1459 msgstr ""
1460
1461 1452 #: rhodecode/authentication/plugins/auth_ldap.py:320
1462 1453 msgid ""
1463 "Base DN to search. Dynamic bind is supported. Add `$login` marker in it to be replaced with current user credentials \n"
1454 "This specifies the PEM-format file path containing certificates for use in TLS connection.\n"
1455 "If not specified `TLS Cert dir` will be used"
1456 msgstr ""
1457
1458 #: rhodecode/authentication/plugins/auth_ldap.py:323
1459 msgid "TLS Cert file"
1460 msgstr ""
1461
1462 #: rhodecode/authentication/plugins/auth_ldap.py:329
1463 msgid "This specifies the path of a directory that contains individual CA certificates in separate files."
1464 msgstr ""
1465
1466 #: rhodecode/authentication/plugins/auth_ldap.py:331
1467 msgid "TLS Cert dir"
1468 msgstr ""
1469
1470 #: rhodecode/authentication/plugins/auth_ldap.py:336
1471 msgid ""
1472 "Base DN to search. Dynamic bind is supported. Add `$login` marker in it to be replaced with current user username \n"
1464 1473 "(e.g., dc=mydomain,dc=com, or ou=Users,dc=mydomain,dc=com)"
1465 1474 msgstr ""
1466 1475
1467 #: rhodecode/authentication/plugins/auth_ldap.py:325
1476 #: rhodecode/authentication/plugins/auth_ldap.py:341
1468 1477 msgid "Base DN"
1469 1478 msgstr ""
1470 1479
1471 #: rhodecode/authentication/plugins/auth_ldap.py:330
1480 #: rhodecode/authentication/plugins/auth_ldap.py:346
1472 1481 msgid ""
1473 1482 "Filter to narrow results \n"
1474 1483 "(e.g., (&(objectCategory=Person)(objectClass=user)), or \n"
1475 1484 "(memberof=cn=rc-login,ou=groups,ou=company,dc=mydomain,dc=com)))"
1476 1485 msgstr ""
1477 1486
1478 #: rhodecode/authentication/plugins/auth_ldap.py:335
1487 #: rhodecode/authentication/plugins/auth_ldap.py:351
1479 1488 msgid "LDAP Search Filter"
1480 1489 msgstr ""
1481 1490
1482 #: rhodecode/authentication/plugins/auth_ldap.py:341
1491 #: rhodecode/authentication/plugins/auth_ldap.py:357
1483 1492 msgid "How deep to search LDAP. If unsure set to SUBTREE"
1484 1493 msgstr ""
1485 1494
1486 #: rhodecode/authentication/plugins/auth_ldap.py:342
1495 #: rhodecode/authentication/plugins/auth_ldap.py:358
1487 1496 msgid "LDAP Search Scope"
1488 1497 msgstr ""
1489 1498
1490 #: rhodecode/authentication/plugins/auth_ldap.py:348
1499 #: rhodecode/authentication/plugins/auth_ldap.py:364
1491 1500 msgid "LDAP Attribute to map to user name (e.g., uid, or sAMAccountName)"
1492 1501 msgstr ""
1493 1502
1494 #: rhodecode/authentication/plugins/auth_ldap.py:350
1503 #: rhodecode/authentication/plugins/auth_ldap.py:366
1495 1504 msgid "Login Attribute"
1496 1505 msgstr ""
1497 1506
1498 #: rhodecode/authentication/plugins/auth_ldap.py:351
1507 #: rhodecode/authentication/plugins/auth_ldap.py:367
1499 1508 msgid "The LDAP Login attribute of the CN must be specified"
1500 1509 msgstr ""
1501 1510
1502 #: rhodecode/authentication/plugins/auth_ldap.py:356
1511 #: rhodecode/authentication/plugins/auth_ldap.py:372
1503 1512 msgid ""
1504 1513 "LDAP Attribute to map to email address (e.g., mail).\n"
1505 1514 "Emails are a crucial part of RhodeCode. \n"
1506 1515 "If possible add a valid email attribute to ldap users."
1507 1516 msgstr ""
1508 1517
1509 #: rhodecode/authentication/plugins/auth_ldap.py:361
1518 #: rhodecode/authentication/plugins/auth_ldap.py:377
1510 1519 msgid "Email Attribute"
1511 1520 msgstr ""
1512 1521
1513 #: rhodecode/authentication/plugins/auth_ldap.py:366
1522 #: rhodecode/authentication/plugins/auth_ldap.py:382
1514 1523 msgid "LDAP Attribute to map to first name (e.g., givenName)"
1515 1524 msgstr ""
1516 1525
1517 #: rhodecode/authentication/plugins/auth_ldap.py:369
1526 #: rhodecode/authentication/plugins/auth_ldap.py:385
1518 1527 msgid "First Name Attribute"
1519 1528 msgstr ""
1520 1529
1521 #: rhodecode/authentication/plugins/auth_ldap.py:374
1530 #: rhodecode/authentication/plugins/auth_ldap.py:390
1522 1531 msgid "LDAP Attribute to map to last name (e.g., sn)"
1523 1532 msgstr ""
1524 1533
1525 #: rhodecode/authentication/plugins/auth_ldap.py:377
1534 #: rhodecode/authentication/plugins/auth_ldap.py:393
1526 1535 msgid "Last Name Attribute"
1527 1536 msgstr ""
1528 1537
1529 #: rhodecode/authentication/plugins/auth_ldap.py:409
1538 #: rhodecode/authentication/plugins/auth_ldap.py:425
1530 1539 msgid "LDAP"
1531 1540 msgstr ""
1532 1541
1533 1542 #: rhodecode/authentication/plugins/auth_pam.py:60
1534 1543 msgid "PAM service name to use for authentication."
1535 1544 msgstr ""
1536 1545
1537 1546 #: rhodecode/authentication/plugins/auth_pam.py:62
1538 1547 msgid "PAM service name"
1539 1548 msgstr ""
1540 1549
1541 1550 #: rhodecode/authentication/plugins/auth_pam.py:67
1542 1551 msgid "Regular expression for extracting user name/email etc. from Unix userinfo."
1543 1552 msgstr ""
1544 1553
1545 1554 #: rhodecode/authentication/plugins/auth_pam.py:70
1546 1555 msgid "Gecos Regex"
1547 1556 msgstr ""
1548 1557
1549 1558 #: rhodecode/authentication/plugins/auth_pam.py:99
1550 1559 msgid "PAM"
1551 1560 msgstr ""
1552 1561
1553 1562 #: rhodecode/authentication/plugins/auth_rhodecode.py:79
1554 1563 msgid "RhodeCode Internal"
1555 1564 msgstr ""
1556 1565
1557 1566 #: rhodecode/authentication/plugins/auth_rhodecode.py:200
1558 1567 msgid "Allowed user types for authentication using this plugin."
1559 1568 msgstr ""
1560 1569
1561 1570 #: rhodecode/authentication/plugins/auth_rhodecode.py:201
1562 1571 msgid "User restriction"
1563 1572 msgstr ""
1564 1573
1565 1574 #: rhodecode/authentication/plugins/auth_rhodecode.py:209
1566 1575 msgid "Allowed protocols for authentication using this plugin. VCS means GIT/HG/SVN. HTTP is web based login."
1567 1576 msgstr ""
1568 1577
1569 1578 #: rhodecode/authentication/plugins/auth_rhodecode.py:211
1570 1579 #: rhodecode/authentication/plugins/auth_token.py:173
1571 1580 msgid "Scope restriction"
1572 1581 msgstr ""
1573 1582
1574 1583 #: rhodecode/authentication/plugins/auth_token.py:77
1575 1584 msgid "Rhodecode Token"
1576 1585 msgstr ""
1577 1586
1578 1587 #: rhodecode/authentication/plugins/auth_token.py:172
1579 1588 msgid "Choose operation scope restriction when authenticating."
1580 1589 msgstr ""
1581 1590
1582 1591 #: rhodecode/events/pullrequest.py:79
1583 1592 msgid "pullrequest created"
1584 1593 msgstr ""
1585 1594
1586 #: rhodecode/events/pullrequest.py:88
1595 #: rhodecode/events/pullrequest.py:80
1596 msgid "Event triggered after pull request was created"
1597 msgstr ""
1598
1599 #: rhodecode/events/pullrequest.py:89
1587 1600 msgid "pullrequest closed"
1588 1601 msgstr ""
1589 1602
1590 #: rhodecode/events/pullrequest.py:97
1603 #: rhodecode/events/pullrequest.py:90
1604 msgid "Event triggered after pull request was closed"
1605 msgstr ""
1606
1607 #: rhodecode/events/pullrequest.py:99
1591 1608 msgid "pullrequest commits updated"
1592 1609 msgstr ""
1593 1610
1594 #: rhodecode/events/pullrequest.py:106
1611 #: rhodecode/events/pullrequest.py:100
1612 msgid "Event triggered after pull requests was updated"
1613 msgstr ""
1614
1615 #: rhodecode/events/pullrequest.py:109
1595 1616 msgid "pullrequest review changed"
1596 1617 msgstr ""
1597 1618
1598 #: rhodecode/events/pullrequest.py:119
1619 #: rhodecode/events/pullrequest.py:110
1620 msgid "Event triggered after a review status of a pull requests has changed to other."
1621 msgstr ""
1622
1623 #: rhodecode/events/pullrequest.py:124
1599 1624 msgid "pullrequest merged"
1600 1625 msgstr ""
1601 1626
1602 #: rhodecode/events/pullrequest.py:128
1627 #: rhodecode/events/pullrequest.py:125
1628 msgid "Event triggered after a successful merge operation was executed on a pull request"
1629 msgstr ""
1630
1631 #: rhodecode/events/pullrequest.py:135
1603 1632 msgid "pullrequest commented"
1604 1633 msgstr ""
1605 1634
1606 #: rhodecode/events/repo.py:190
1635 #: rhodecode/events/pullrequest.py:136
1636 msgid "Event triggered after a comment was made on a code in the pull request"
1637 msgstr ""
1638
1639 #: rhodecode/events/repo.py:191
1640 msgid "repository commit comment"
1641 msgstr ""
1642
1643 #: rhodecode/events/repo.py:192
1644 msgid "Event triggered after a comment was made on commit inside a repository"
1645 msgstr ""
1646
1647 #: rhodecode/events/repo.py:224
1607 1648 msgid "repository pre create"
1608 1649 msgstr ""
1609 1650
1610 #: rhodecode/events/repo.py:199
1651 #: rhodecode/events/repo.py:225
1652 msgid "Event triggered before repository is created"
1653 msgstr ""
1654
1655 #: rhodecode/events/repo.py:234
1611 1656 msgid "repository created"
1612 1657 msgstr ""
1613 1658
1614 #: rhodecode/events/repo.py:208
1659 #: rhodecode/events/repo.py:235
1660 msgid "Event triggered after repository was created"
1661 msgstr ""
1662
1663 #: rhodecode/events/repo.py:244
1615 1664 msgid "repository pre delete"
1616 1665 msgstr ""
1617 1666
1618 #: rhodecode/events/repo.py:217
1667 #: rhodecode/events/repo.py:245
1668 msgid "Event triggered before a repository is deleted"
1669 msgstr ""
1670
1671 #: rhodecode/events/repo.py:254
1619 1672 msgid "repository deleted"
1620 1673 msgstr ""
1621 1674
1622 #: rhodecode/events/repo.py:257
1675 #: rhodecode/events/repo.py:255
1676 msgid "Event triggered after repository was deleted"
1677 msgstr ""
1678
1679 #: rhodecode/events/repo.py:295
1623 1680 msgid "repository pre pull"
1624 1681 msgstr ""
1625 1682
1626 #: rhodecode/events/repo.py:266
1683 #: rhodecode/events/repo.py:296
1684 msgid "Event triggered before repository code is pulled"
1685 msgstr ""
1686
1687 #: rhodecode/events/repo.py:305
1627 1688 msgid "repository pull"
1628 1689 msgstr ""
1629 1690
1630 #: rhodecode/events/repo.py:275
1691 #: rhodecode/events/repo.py:306
1692 msgid "Event triggered after repository code was pulled"
1693 msgstr ""
1694
1695 #: rhodecode/events/repo.py:315
1631 1696 msgid "repository pre push"
1632 1697 msgstr ""
1633 1698
1634 #: rhodecode/events/repo.py:286
1699 #: rhodecode/events/repo.py:316
1700 msgid "Event triggered before the code is pushed to a repository"
1701 msgstr ""
1702
1703 #: rhodecode/events/repo.py:328
1635 1704 msgid "repository push"
1636 1705 msgstr ""
1637 1706
1707 #: rhodecode/events/repo.py:329
1708 msgid "Event triggered after the code was pushed to a repository"
1709 msgstr ""
1710
1638 1711 #: rhodecode/events/repo_group.py:62
1639 1712 msgid "repository group created"
1640 1713 msgstr ""
1641 1714
1642 #: rhodecode/events/repo_group.py:71
1715 #: rhodecode/events/repo_group.py:63
1716 msgid "Event triggered after a repository group was created"
1717 msgstr ""
1718
1719 #: rhodecode/events/repo_group.py:72
1643 1720 msgid "repository group deleted"
1644 1721 msgstr ""
1645 1722
1646 #: rhodecode/events/repo_group.py:80
1723 #: rhodecode/events/repo_group.py:73
1724 msgid "Event triggered after a repository group was deleted"
1725 msgstr ""
1726
1727 #: rhodecode/events/repo_group.py:82
1647 1728 msgid "repository group update"
1648 1729 msgstr ""
1649 1730
1731 #: rhodecode/events/repo_group.py:83
1732 msgid "Event triggered after a repository group was updated"
1733 msgstr ""
1734
1650 1735 #: rhodecode/events/user.py:37
1651 1736 msgid "user registered"
1652 1737 msgstr ""
1653 1738
1654 1739 #: rhodecode/events/user.py:52
1655 1740 msgid "user pre create"
1656 1741 msgstr ""
1657 1742
1658 1743 #: rhodecode/events/user.py:66
1659 1744 msgid "user post create"
1660 1745 msgstr ""
1661 1746
1662 1747 #: rhodecode/events/user.py:80
1663 1748 msgid "user pre update"
1664 1749 msgstr ""
1665 1750
1666 1751 #: rhodecode/events/user.py:100
1667 1752 msgid "user permissions change"
1668 1753 msgstr ""
1669 1754
1670 1755 #: rhodecode/forms/__init__.py:35
1671 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:88
1672 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:72
1756 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:97
1757 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:73
1673 1758 #: rhodecode/templates/admin/permissions/permissions_application.mako:60
1674 1759 #: rhodecode/templates/admin/permissions/permissions_ips.mako:64
1675 1760 #: rhodecode/templates/admin/permissions/permissions_objects.mako:60
1676 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:207
1677 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:72
1761 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:217
1762 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:78
1678 1763 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:66
1679 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:80
1680 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:192
1681 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:244
1764 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:201
1765 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:251
1682 1766 #: rhodecode/templates/admin/repos/repo_edit_vcs.mako:44
1683 1767 #: rhodecode/templates/admin/settings/settings_global.mako:141
1684 1768 #: rhodecode/templates/admin/settings/settings_issuetracker.mako:16
1685 1769 #: rhodecode/templates/admin/settings/settings_labs.mako:49
1686 1770 #: rhodecode/templates/admin/settings/settings_vcs.mako:14
1687 1771 #: rhodecode/templates/admin/settings/settings_visual.mako:215
1688 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:193
1689 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:88
1690 #: rhodecode/templates/admin/users/user_edit_emails.mako:63
1691 #: rhodecode/templates/admin/users/user_edit_ips.mako:71
1692 #: rhodecode/templates/admin/users/user_edit_profile.mako:146
1693 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:67
1772 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:207
1773 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:101
1774 #: rhodecode/templates/admin/users/user_edit_emails.mako:66
1775 #: rhodecode/templates/admin/users/user_edit_ips.mako:76
1776 #: rhodecode/templates/admin/users/user_edit_profile.mako:155
1777 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:72
1694 1778 #: rhodecode/templates/base/default_perms_box.mako:89
1695 1779 msgid "Reset"
1696 1780 msgstr ""
1697 1781
1698 #: rhodecode/forms/__init__.py:36
1699 #: rhodecode/templates/admin/gists/gist_show.mako:57
1782 #: rhodecode/forms/__init__.py:36 rhodecode/public/js/scripts.js:37802
1783 #: rhodecode/public/js/scripts.min.js:1
1784 #: rhodecode/public/js/src/rhodecode/utils/ajax.js:158
1785 #: rhodecode/templates/admin/gists/gist_show.mako:59
1700 1786 #: rhodecode/templates/admin/integrations/list.mako:179
1701 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:50
1702 #: rhodecode/templates/admin/my_account/my_account_emails.mako:32
1703 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:33
1787 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:59
1788 #: rhodecode/templates/admin/my_account/my_account_emails.mako:33
1789 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:34
1704 1790 #: rhodecode/templates/admin/notifications/notifications_data.mako:22
1705 1791 #: rhodecode/templates/admin/notifications/notifications_show.mako:37
1706 1792 #: rhodecode/templates/admin/permissions/permissions_ips.mako:29
1707 1793 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:25
1708 1794 #: rhodecode/templates/admin/settings/settings_hooks.mako:46
1709 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:50
1710 #: rhodecode/templates/admin/users/user_edit_emails.mako:31
1711 #: rhodecode/templates/admin/users/user_edit_ips.mako:35
1712 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:30
1795 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:63
1796 #: rhodecode/templates/admin/users/user_edit_emails.mako:34
1797 #: rhodecode/templates/admin/users/user_edit_ips.mako:40
1798 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:35
1713 1799 #: rhodecode/templates/base/issue_tracker_settings.mako:146
1714 1800 #: rhodecode/templates/base/vcs_settings.mako:244
1715 1801 #: rhodecode/templates/base/vcs_settings.mako:269
1716 1802 #: rhodecode/templates/changeset/changeset_file_comment.mako:140
1717 1803 #: rhodecode/templates/changeset/changeset_file_comment.mako:142
1718 1804 #: rhodecode/templates/changeset/changeset_file_comment.mako:145
1719 #: rhodecode/templates/data_table/_dt_elements.mako:179
1720 #: rhodecode/templates/data_table/_dt_elements.mako:253
1721 #: rhodecode/templates/data_table/_dt_elements.mako:268
1722 #: rhodecode/templates/data_table/_dt_elements.mako:280
1723 #: rhodecode/templates/data_table/_dt_elements.mako:426
1805 #: rhodecode/templates/data_table/_dt_elements.mako:436
1724 1806 #: rhodecode/templates/debug_style/buttons.html:132
1725 1807 #: rhodecode/templates/files/files_source.mako:30
1726 1808 #: rhodecode/templates/files/files_source.mako:37
1727 1809 #: rhodecode/templates/files/files_source.mako:43
1728 1810 msgid "Delete"
1729 1811 msgstr ""
1730 1812
1731 1813 #: rhodecode/integrations/schema.py:30
1732 1814 #: rhodecode/model/validation_schema/schemas/integration_schema.py:193
1733 1815 msgid "Enable or disable this integration."
1734 1816 msgstr ""
1735 1817
1736 1818 #: rhodecode/integrations/schema.py:37
1737 1819 #: rhodecode/model/validation_schema/schemas/integration_schema.py:174
1738 1820 msgid "Short name for this integration."
1739 1821 msgstr ""
1740 1822
1741 1823 #: rhodecode/integrations/schema.py:39
1742 1824 #: rhodecode/model/validation_schema/schemas/integration_schema.py:176
1743 1825 msgid "Integration name"
1744 1826 msgstr ""
1745 1827
1746 1828 #: rhodecode/integrations/schema.py:51
1747 1829 msgid "Limit integrations to to work only on the direct children repositories of this repository group (no subgroups)"
1748 1830 msgstr ""
1749 1831
1750 1832 #: rhodecode/integrations/schema.py:55
1751 1833 msgid "Limit to childen repos only"
1752 1834 msgstr ""
1753 1835
1754 1836 #: rhodecode/integrations/schema.py:63
1755 1837 msgid "Limit integrations to to work only on root level repositories"
1756 1838 msgstr ""
1757 1839
1758 1840 #: rhodecode/integrations/schema.py:66
1759 1841 msgid "Root repositories only"
1760 1842 msgstr ""
1761 1843
1762 1844 #: rhodecode/integrations/views.py:147
1763 1845 msgid "{repo_name} repository"
1764 1846 msgstr ""
1765 1847
1766 1848 #: rhodecode/integrations/views.py:150
1767 1849 msgid "{repo_group_name} repo group"
1768 1850 msgstr ""
1769 1851
1770 1852 #: rhodecode/integrations/views.py:153
1771 1853 #: rhodecode/templates/admin/permissions/permissions.mako:36
1772 1854 msgid "Global"
1773 1855 msgstr ""
1774 1856
1775 1857 #: rhodecode/integrations/views.py:157
1776 1858 msgid "{name} integration"
1777 1859 msgstr ""
1778 1860
1779 1861 #: rhodecode/integrations/views.py:172
1780 1862 msgid "Integration {integration_name} deleted successfully."
1781 1863 msgstr ""
1782 1864
1783 1865 #: rhodecode/integrations/views.py:305
1784 1866 msgid "Errors exist when saving integration settings. Please check the form inputs."
1785 1867 msgstr ""
1786 1868
1787 1869 #: rhodecode/integrations/views.py:330
1788 1870 msgid "Integration {integration_name} updated successfully."
1789 1871 msgstr ""
1790 1872
1791 #: rhodecode/integrations/types/email.py:156
1873 #: rhodecode/integrations/types/email.py:157
1792 1874 msgid "Recipients"
1793 1875 msgstr ""
1794 1876
1795 #: rhodecode/integrations/types/email.py:157
1877 #: rhodecode/integrations/types/email.py:158
1796 1878 msgid "Email addresses to send push events to"
1797 1879 msgstr ""
1798 1880
1799 #: rhodecode/integrations/types/email.py:162
1800 1881 #: rhodecode/integrations/types/email.py:163
1882 #: rhodecode/integrations/types/email.py:164
1801 1883 msgid "Email address"
1802 1884 msgstr ""
1803 1885
1804 #: rhodecode/integrations/types/email.py:174
1886 #: rhodecode/integrations/types/email.py:175
1805 1887 #: rhodecode/templates/register.mako:95
1806 #: rhodecode/templates/admin/my_account/my_account_profile.mako:67
1888 #: rhodecode/templates/admin/my_account/my_account_profile.mako:78
1807 1889 #: rhodecode/templates/admin/users/user_add.mako:86
1808 #: rhodecode/templates/admin/users/user_edit_profile.mako:62
1890 #: rhodecode/templates/admin/users/user_edit_profile.mako:65
1809 1891 #: rhodecode/templates/admin/users/users.mako:76
1810 1892 #: rhodecode/templates/email_templates/user_registration.mako:50
1811 1893 #: rhodecode/templates/users/user_profile.mako:69
1812 1894 msgid "Email"
1813 1895 msgstr ""
1814 1896
1815 #: rhodecode/integrations/types/email.py:175
1897 #: rhodecode/integrations/types/email.py:176
1816 1898 msgid "Send repo push summaries to a list of recipients via email"
1817 1899 msgstr ""
1818 1900
1819 #: rhodecode/integrations/types/hipchat.py:62
1820 msgid "Yellow"
1821 msgstr ""
1822
1823 1901 #: rhodecode/integrations/types/hipchat.py:63
1824 msgid "Red"
1902 msgid "Yellow"
1825 1903 msgstr ""
1826 1904
1827 1905 #: rhodecode/integrations/types/hipchat.py:64
1828 msgid "Green"
1906 msgid "Red"
1829 1907 msgstr ""
1830 1908
1831 1909 #: rhodecode/integrations/types/hipchat.py:65
1832 msgid "Purple"
1910 msgid "Green"
1833 1911 msgstr ""
1834 1912
1835 1913 #: rhodecode/integrations/types/hipchat.py:66
1914 msgid "Purple"
1915 msgstr ""
1916
1917 #: rhodecode/integrations/types/hipchat.py:67
1836 1918 msgid "Gray"
1837 1919 msgstr ""
1838 1920
1839 #: rhodecode/integrations/types/hipchat.py:71
1840 msgid "Hipchat server URL"
1841 msgstr ""
1842
1843 1921 #: rhodecode/integrations/types/hipchat.py:72
1922 msgid "Hipchat server URL"
1923 msgstr ""
1924
1925 #: rhodecode/integrations/types/hipchat.py:73
1844 1926 msgid "Hipchat integration url."
1845 1927 msgstr ""
1846 1928
1847 #: rhodecode/integrations/types/hipchat.py:82
1848 msgid "Notify"
1849 msgstr ""
1850
1851 1929 #: rhodecode/integrations/types/hipchat.py:83
1930 msgid "Notify"
1931 msgstr ""
1932
1933 #: rhodecode/integrations/types/hipchat.py:84
1852 1934 msgid "Make a notification to the users in room."
1853 1935 msgstr ""
1854 1936
1855 #: rhodecode/integrations/types/hipchat.py:89
1856 msgid "Color"
1857 msgstr ""
1858
1859 1937 #: rhodecode/integrations/types/hipchat.py:90
1938 msgid "Color"
1939 msgstr ""
1940
1941 #: rhodecode/integrations/types/hipchat.py:91
1860 1942 msgid "Background color of message."
1861 1943 msgstr ""
1862 1944
1863 #: rhodecode/integrations/types/hipchat.py:101
1864 msgid "Hipchat"
1865 msgstr ""
1866
1867 1945 #: rhodecode/integrations/types/hipchat.py:102
1946 msgid "Hipchat"
1947 msgstr ""
1948
1949 #: rhodecode/integrations/types/hipchat.py:103
1868 1950 msgid "Send events such as repo pushes and pull requests to your hipchat channel."
1869 1951 msgstr ""
1870 1952
1871 #: rhodecode/integrations/types/slack.py:71
1872 msgid "Slack service URL"
1873 msgstr ""
1874
1875 1953 #: rhodecode/integrations/types/slack.py:72
1954 msgid "Slack service URL"
1955 msgstr ""
1956
1957 #: rhodecode/integrations/types/slack.py:73
1876 1958 msgid "This can be setup at the <a href=\"https://my.slack.com/services/new/incoming-webhook/\">slack app manager</a>"
1877 1959 msgstr ""
1878 1960
1879 #: rhodecode/integrations/types/slack.py:85
1880 #: rhodecode/integrations/types/webhook.py:79 rhodecode/templates/login.mako:44
1961 #: rhodecode/integrations/types/slack.py:86
1962 #: rhodecode/integrations/types/webhook.py:81 rhodecode/templates/login.mako:44
1881 1963 #: rhodecode/templates/register.mako:48
1882 1964 #: rhodecode/templates/admin/admin_log_base.mako:7
1883 #: rhodecode/templates/admin/my_account/my_account_profile.mako:27
1884 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:23
1965 #: rhodecode/templates/admin/my_account/my_account_profile.mako:38
1966 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:29
1885 1967 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:45
1886 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:70
1968 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:74
1887 1969 #: rhodecode/templates/admin/users/user_add.mako:35
1888 #: rhodecode/templates/admin/users/user_edit_profile.mako:36
1970 #: rhodecode/templates/admin/users/user_edit_profile.mako:39
1889 1971 #: rhodecode/templates/admin/users/users.mako:74
1890 1972 #: rhodecode/templates/debug_style/login.html:36
1891 1973 #: rhodecode/templates/email_templates/user_registration.mako:42
1892 1974 #: rhodecode/templates/user_group/profile.mako:61
1893 1975 #: rhodecode/templates/users/user_profile.mako:29
1894 1976 msgid "Username"
1895 1977 msgstr ""
1896 1978
1897 #: rhodecode/integrations/types/slack.py:86
1979 #: rhodecode/integrations/types/slack.py:87
1898 1980 msgid "Username to show notifications coming from."
1899 1981 msgstr ""
1900 1982
1901 #: rhodecode/integrations/types/slack.py:95
1902 msgid "Channel"
1903 msgstr ""
1904
1905 1983 #: rhodecode/integrations/types/slack.py:96
1984 msgid "Channel"
1985 msgstr ""
1986
1987 #: rhodecode/integrations/types/slack.py:97
1906 1988 msgid "Channel to send notifications to."
1907 1989 msgstr ""
1908 1990
1909 #: rhodecode/integrations/types/slack.py:105
1910 msgid "Emoji"
1911 msgstr ""
1912
1913 1991 #: rhodecode/integrations/types/slack.py:106
1992 msgid "Emoji"
1993 msgstr ""
1994
1995 #: rhodecode/integrations/types/slack.py:107
1914 1996 msgid "Emoji to use eg. :studio_microphone:"
1915 1997 msgstr ""
1916 1998
1917 #: rhodecode/integrations/types/slack.py:117
1918 msgid "Slack"
1919 msgstr ""
1920
1921 1999 #: rhodecode/integrations/types/slack.py:118
2000 msgid "Slack"
2001 msgstr ""
2002
2003 #: rhodecode/integrations/types/slack.py:119
1922 2004 msgid "Send events such as repo pushes and pull requests to your slack channel."
1923 2005 msgstr ""
1924 2006
1925 #: rhodecode/integrations/types/webhook.py:48
2007 #: rhodecode/integrations/types/webhook.py:49
1926 2008 msgid "Webhook URL"
1927 2009 msgstr ""
1928 2010
1929 #: rhodecode/integrations/types/webhook.py:50
2011 #: rhodecode/integrations/types/webhook.py:51
1930 2012 msgid "URL to which Webhook should submit data. If used some of the variables would trigger multiple calls, like ${branch} or ${commit_id}. Webhook will be called as many times as unique objects in data in such cases."
1931 2013 msgstr ""
1932 2014
1933 #: rhodecode/integrations/types/webhook.py:68
2015 #: rhodecode/integrations/types/webhook.py:70
1934 2016 msgid "Secret Token"
1935 2017 msgstr ""
1936 2018
1937 #: rhodecode/integrations/types/webhook.py:69
2019 #: rhodecode/integrations/types/webhook.py:71
1938 2020 msgid "Optional string used to validate received payloads. It will be sent together with event data in JSON"
1939 2021 msgstr ""
1940 2022
1941 #: rhodecode/integrations/types/webhook.py:80
2023 #: rhodecode/integrations/types/webhook.py:82
1942 2024 msgid "Optional username to authenticate the call."
1943 2025 msgstr ""
1944 2026
1945 #: rhodecode/integrations/types/webhook.py:90
2027 #: rhodecode/integrations/types/webhook.py:91 rhodecode/templates/login.mako:51
2028 #: rhodecode/templates/register.mako:62
2029 #: rhodecode/templates/admin/my_account/my_account.mako:31
2030 #: rhodecode/templates/admin/users/user_add.mako:44
2031 #: rhodecode/templates/debug_style/login.html:45
2032 msgid "Password"
2033 msgstr ""
2034
2035 #: rhodecode/integrations/types/webhook.py:92
1946 2036 msgid "Optional password to authenticate the call."
1947 2037 msgstr ""
1948 2038
1949 #: rhodecode/integrations/types/webhook.py:100
2039 #: rhodecode/integrations/types/webhook.py:102
1950 2040 msgid "Custom Header Key"
1951 2041 msgstr ""
1952 2042
1953 #: rhodecode/integrations/types/webhook.py:101
2043 #: rhodecode/integrations/types/webhook.py:103
1954 2044 msgid "Custom Header name to be set when calling endpoint."
1955 2045 msgstr ""
1956 2046
1957 #: rhodecode/integrations/types/webhook.py:110
2047 #: rhodecode/integrations/types/webhook.py:112
1958 2048 msgid "Custom Header Value"
1959 2049 msgstr ""
1960 2050
1961 #: rhodecode/integrations/types/webhook.py:111
2051 #: rhodecode/integrations/types/webhook.py:113
1962 2052 msgid "Custom Header value to be set when calling endpoint."
1963 2053 msgstr ""
1964 2054
1965 #: rhodecode/integrations/types/webhook.py:120
2055 #: rhodecode/integrations/types/webhook.py:122
1966 2056 msgid "Call Method"
1967 2057 msgstr ""
1968 2058
1969 #: rhodecode/integrations/types/webhook.py:121
2059 #: rhodecode/integrations/types/webhook.py:123
1970 2060 msgid "Select a HTTP method to use when calling the Webhook."
1971 2061 msgstr ""
1972 2062
1973 #: rhodecode/integrations/types/webhook.py:133
2063 #: rhodecode/integrations/types/webhook.py:135
1974 2064 msgid "Webhook"
1975 2065 msgstr ""
1976 2066
1977 #: rhodecode/integrations/types/webhook.py:134
2067 #: rhodecode/integrations/types/webhook.py:136
1978 2068 msgid "send JSON data to a url endpoint"
1979 2069 msgstr ""
1980 2070
1981 2071 #: rhodecode/lib/action_parser.py:93
1982 2072 msgid "[deleted] repository"
1983 2073 msgstr ""
1984 2074
1985 2075 #: rhodecode/lib/action_parser.py:96 rhodecode/lib/action_parser.py:114
1986 2076 msgid "[created] repository"
1987 2077 msgstr ""
1988 2078
1989 2079 #: rhodecode/lib/action_parser.py:99
1990 2080 msgid "[created] repository as fork"
1991 2081 msgstr ""
1992 2082
1993 2083 #: rhodecode/lib/action_parser.py:102 rhodecode/lib/action_parser.py:117
1994 2084 msgid "[forked] repository"
1995 2085 msgstr ""
1996 2086
1997 2087 #: rhodecode/lib/action_parser.py:105 rhodecode/lib/action_parser.py:120
1998 2088 msgid "[updated] repository"
1999 2089 msgstr ""
2000 2090
2001 2091 #: rhodecode/lib/action_parser.py:108
2002 2092 msgid "[downloaded] archive from repository"
2003 2093 msgstr ""
2004 2094
2005 2095 #: rhodecode/lib/action_parser.py:111
2006 2096 msgid "[delete] repository"
2007 2097 msgstr ""
2008 2098
2009 2099 #: rhodecode/lib/action_parser.py:123
2010 2100 msgid "[created] user"
2011 2101 msgstr ""
2012 2102
2013 2103 #: rhodecode/lib/action_parser.py:126
2014 2104 msgid "[updated] user"
2015 2105 msgstr ""
2016 2106
2017 2107 #: rhodecode/lib/action_parser.py:129
2018 2108 msgid "[created] user group"
2019 2109 msgstr ""
2020 2110
2021 2111 #: rhodecode/lib/action_parser.py:132
2022 2112 msgid "[updated] user group"
2023 2113 msgstr ""
2024 2114
2025 2115 #: rhodecode/lib/action_parser.py:135
2026 2116 msgid "[commented] on commit in repository"
2027 2117 msgstr ""
2028 2118
2029 2119 #: rhodecode/lib/action_parser.py:138
2030 2120 msgid "[commented] on pull request for"
2031 2121 msgstr ""
2032 2122
2033 2123 #: rhodecode/lib/action_parser.py:141
2034 2124 msgid "[closed] pull request for"
2035 2125 msgstr ""
2036 2126
2037 2127 #: rhodecode/lib/action_parser.py:144
2038 2128 msgid "[merged] pull request for"
2039 2129 msgstr ""
2040 2130
2041 2131 #: rhodecode/lib/action_parser.py:147
2042 2132 msgid "[pushed] into"
2043 2133 msgstr ""
2044 2134
2045 2135 #: rhodecode/lib/action_parser.py:150
2046 2136 msgid "[committed via RhodeCode] into repository"
2047 2137 msgstr ""
2048 2138
2049 2139 #: rhodecode/lib/action_parser.py:153
2050 2140 msgid "[pulled from remote] into repository"
2051 2141 msgstr ""
2052 2142
2053 2143 #: rhodecode/lib/action_parser.py:156
2054 2144 msgid "[pulled] from"
2055 2145 msgstr ""
2056 2146
2057 2147 #: rhodecode/lib/action_parser.py:159
2058 2148 msgid "[started following] repository"
2059 2149 msgstr ""
2060 2150
2061 2151 #: rhodecode/lib/action_parser.py:162
2062 2152 msgid "[stopped following] repository"
2063 2153 msgstr ""
2064 2154
2065 2155 #: rhodecode/lib/action_parser.py:172
2066 2156 #, python-format
2067 2157 msgid "fork name %s"
2068 2158 msgstr ""
2069 2159
2070 2160 #: rhodecode/lib/action_parser.py:191
2071 2161 #, python-format
2072 2162 msgid "Pull request #%s"
2073 2163 msgstr ""
2074 2164
2075 2165 #: rhodecode/lib/action_parser.py:226
2076 2166 #, python-format
2077 2167 msgid "Show all combined commits %s->%s"
2078 2168 msgstr ""
2079 2169
2080 2170 #: rhodecode/lib/action_parser.py:231
2081 2171 msgid "compare view"
2082 2172 msgstr ""
2083 2173
2084 2174 #: rhodecode/lib/action_parser.py:238
2085 2175 #, python-format
2086 2176 msgid " and %(num)s more commits"
2087 2177 msgstr ""
2088 2178
2089 2179 #: rhodecode/lib/action_parser.py:293
2090 2180 #, python-format
2091 2181 msgid "Deleted branch: %s"
2092 2182 msgstr ""
2093 2183
2094 2184 #: rhodecode/lib/action_parser.py:296
2095 2185 #, python-format
2096 2186 msgid "Created tag: %s"
2097 2187 msgstr ""
2098 2188
2099 2189 #: rhodecode/lib/action_parser.py:309
2100 2190 msgid "Commit not found"
2101 2191 msgstr ""
2102 2192
2103 #: rhodecode/lib/auth.py:1672
2193 #: rhodecode/lib/auth.py:1760
2104 2194 msgid "IP {} not allowed"
2105 2195 msgstr ""
2106 2196
2107 #: rhodecode/lib/auth.py:1764
2197 #: rhodecode/lib/auth.py:1852
2108 2198 msgid "You need to be a registered user to perform this action"
2109 2199 msgstr ""
2110 2200
2111 #: rhodecode/lib/auth.py:1808
2201 #: rhodecode/lib/auth.py:1896
2112 2202 msgid "You need to be signed in to view this page"
2113 2203 msgstr ""
2114 2204
2115 #: rhodecode/lib/diffs.py:902
2205 #: rhodecode/lib/diffs.py:903
2116 2206 msgid "Click to select line"
2117 2207 msgstr ""
2118 2208
2119 #: rhodecode/lib/helpers.py:1706
2209 #: rhodecode/lib/helpers.py:1721
2120 2210 msgid ""
2121 2211 "Example filter terms:\n"
2122 2212 " repository:vcs\n"
2123 2213 " username:marcin\n"
2124 2214 " username:(NOT marcin)\n"
2125 2215 " action:*push*\n"
2126 2216 " ip:127.0.0.1\n"
2127 2217 " date:20120101\n"
2128 2218 " date:[20120101100000 TO 20120102]\n"
2129 2219 "\n"
2130 2220 "Actions: {actions}\n"
2131 2221 "\n"
2132 2222 "Generate wildcards using '*' character:\n"
2133 2223 " \"repository:vcs*\" - search everything starting with 'vcs'\n"
2134 2224 " \"repository:*vcs*\" - search for repository containing 'vcs'\n"
2135 2225 "\n"
2136 2226 "Optional AND / OR operators in queries\n"
2137 2227 " \"repository:vcs OR repository:test\"\n"
2138 2228 " \"username:test AND repository:test*\"\n"
2139 2229 msgstr ""
2140 2230
2141 #: rhodecode/lib/helpers.py:1730
2231 #: rhodecode/lib/helpers.py:1745
2142 2232 #, python-format
2143 2233 msgid "%s repository is not mapped to db perhaps it was created or renamed from the filesystem please run the application again in order to rescan repositories"
2144 2234 msgstr ""
2145 2235
2146 2236 #: rhodecode/lib/utils2.py:542
2147 2237 msgid "in ${ago}"
2148 2238 msgstr ""
2149 2239
2150 2240 #: rhodecode/lib/utils2.py:548
2151 2241 msgid "${ago} ago"
2152 2242 msgstr ""
2153 2243
2154 2244 #: rhodecode/lib/utils2.py:557
2155 2245 msgid "${val}, ${detail}"
2156 2246 msgstr ""
2157 2247
2158 2248 #: rhodecode/lib/utils2.py:559
2159 2249 msgid "${val}, ${detail} ago"
2160 2250 msgstr ""
2161 2251
2162 2252 #: rhodecode/lib/utils2.py:561
2163 2253 msgid "in ${val}, ${detail}"
2164 2254 msgstr ""
2165 2255
2166 2256 #: rhodecode/lib/utils2.py:563
2167 2257 msgid "${val} and ${detail}"
2168 2258 msgstr ""
2169 2259
2170 2260 #: rhodecode/lib/utils2.py:565
2171 2261 msgid "${val} and ${detail} ago"
2172 2262 msgstr ""
2173 2263
2174 2264 #: rhodecode/lib/utils2.py:567
2175 2265 msgid "in ${val} and ${detail}"
2176 2266 msgstr ""
2177 2267
2178 #: rhodecode/lib/utils2.py:571 rhodecode/public/js/scripts.js:25634
2268 #: rhodecode/lib/utils2.py:571 rhodecode/public/js/scripts.js:22115
2179 2269 #: rhodecode/public/js/scripts.min.js:1
2180 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:99
2270 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:111
2181 2271 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:174
2182 2272 msgid "just now"
2183 2273 msgstr ""
2184 2274
2185 2275 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:568
2186 2276 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:581
2187 2277 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:598
2188 2278 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:681
2189 2279 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:656
2190 2280 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:658
2191 2281 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:681
2192 2282 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:682
2193 2283 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:699
2194 2284 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:716
2195 2285 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:732
2196 2286 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:735
2197 2287 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:737
2198 2288 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:737
2199 2289 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:764
2200 2290 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:774
2201 2291 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:815
2202 2292 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:815
2203 2293 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:816
2204 2294 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:816
2205 2295 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:822
2206 2296 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:944
2207 2297 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:969
2208 2298 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2587
2209 2299 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2653
2210 2300 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2739
2211 2301 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2772
2212 2302 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2772
2213 2303 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2987
2304 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3073
2214 2305 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2275
2215 2306 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2267
2216 2307 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2266
2217 2308 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2270
2218 2309 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2270
2219 2310 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2321
2220 2311 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2322
2221 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2522 rhodecode/model/db.py:3061
2312 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2522 rhodecode/model/db.py:3079
2222 2313 msgid "Repository no access"
2223 2314 msgstr ""
2224 2315
2225 2316 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:569
2226 2317 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:582
2227 2318 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:599
2228 2319 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:682
2229 2320 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:657
2230 2321 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:659
2231 2322 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:682
2232 2323 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:683
2233 2324 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:700
2234 2325 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:717
2235 2326 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:733
2236 2327 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:736
2237 2328 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:738
2238 2329 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:738
2239 2330 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:765
2240 2331 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:775
2241 2332 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:816
2242 2333 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:816
2243 2334 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:817
2244 2335 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:817
2245 2336 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:823
2246 2337 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:945
2247 2338 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:970
2248 2339 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2588
2249 2340 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2654
2250 2341 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2740
2251 2342 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2773
2252 2343 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2773
2253 2344 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2988
2345 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3074
2254 2346 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2276
2255 2347 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2268
2256 2348 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2267
2257 2349 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2271
2258 2350 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2271
2259 2351 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2322
2260 2352 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2323
2261 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2523 rhodecode/model/db.py:3062
2353 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2523 rhodecode/model/db.py:3080
2262 2354 msgid "Repository read access"
2263 2355 msgstr ""
2264 2356
2265 2357 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:570
2266 2358 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:583
2267 2359 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:600
2268 2360 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:683
2269 2361 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:658
2270 2362 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:660
2271 2363 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:683
2272 2364 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:684
2273 2365 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:701
2274 2366 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:718
2275 2367 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:734
2276 2368 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:737
2277 2369 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:739
2278 2370 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:739
2279 2371 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:766
2280 2372 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:776
2281 2373 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:817
2282 2374 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:817
2283 2375 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:818
2284 2376 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:818
2285 2377 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824
2286 2378 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946
2287 2379 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971
2288 2380 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2589
2289 2381 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2655
2290 2382 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2741
2291 2383 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2774
2292 2384 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2774
2293 2385 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2989
2386 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3075
2294 2387 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2277
2295 2388 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2269
2296 2389 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2268
2297 2390 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2272
2298 2391 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2272
2299 2392 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2323
2300 2393 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2324
2301 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2524 rhodecode/model/db.py:3063
2394 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2524 rhodecode/model/db.py:3081
2302 2395 msgid "Repository write access"
2303 2396 msgstr ""
2304 2397
2305 2398 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:571
2306 2399 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:584
2307 2400 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:601
2308 2401 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:684
2309 2402 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:659
2310 2403 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:661
2311 2404 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:684
2312 2405 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:685
2313 2406 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:702
2314 2407 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:719
2315 2408 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:735
2316 2409 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:738
2317 2410 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:740
2318 2411 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:740
2319 2412 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:767
2320 2413 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:777
2321 2414 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:818
2322 2415 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:818
2323 2416 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:819
2324 2417 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:819
2325 2418 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:825
2326 2419 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:947
2327 2420 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:972
2328 2421 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2590
2329 2422 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2656
2330 2423 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2742
2331 2424 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2775
2332 2425 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2775
2333 2426 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2990
2427 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3076
2334 2428 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2278
2335 2429 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2270
2336 2430 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2269
2337 2431 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2273
2338 2432 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2273
2339 2433 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2324
2340 2434 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2325
2341 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2525 rhodecode/model/db.py:3064
2435 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2525 rhodecode/model/db.py:3082
2342 2436 msgid "Repository admin access"
2343 2437 msgstr ""
2344 2438
2345 2439 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:573
2346 2440 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:586
2347 2441 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:603
2348 2442 msgid "Repositories Group no access"
2349 2443 msgstr ""
2350 2444
2351 2445 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:574
2352 2446 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:587
2353 2447 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:604
2354 2448 msgid "Repositories Group read access"
2355 2449 msgstr ""
2356 2450
2357 2451 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:575
2358 2452 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:588
2359 2453 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:605
2360 2454 msgid "Repositories Group write access"
2361 2455 msgstr ""
2362 2456
2363 2457 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:576
2364 2458 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:589
2365 2459 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:606
2366 2460 msgid "Repositories Group admin access"
2367 2461 msgstr ""
2368 2462
2369 2463 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:578
2370 2464 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:591
2371 2465 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:608
2372 2466 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:691
2373 2467 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:654
2374 2468 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:656
2375 2469 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:679
2376 2470 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:680
2377 2471 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:697
2378 2472 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:714
2379 2473 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:730
2380 2474 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:733
2381 2475 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:735
2382 2476 msgid "RhodeCode Administrator"
2383 2477 msgstr ""
2384 2478
2385 2479 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:579
2386 2480 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:592
2387 2481 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:609
2388 2482 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:692
2389 2483 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:677
2390 2484 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:679
2391 2485 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:702
2392 2486 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:703
2393 2487 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:720
2394 2488 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:737
2395 2489 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:753
2396 2490 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:756
2397 2491 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:758
2398 2492 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:758
2399 2493 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:785
2400 2494 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:795
2401 2495 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:836
2402 2496 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:836
2403 2497 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:837
2404 2498 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:837
2405 2499 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:843
2406 2500 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:965
2407 2501 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:990
2408 2502 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2608
2409 2503 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2679
2410 2504 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2765
2411 2505 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2798
2412 2506 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2798
2413 2507 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3013
2508 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3099
2414 2509 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2296
2415 2510 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2288
2416 2511 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2287
2417 2512 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2291
2418 2513 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2291
2419 2514 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2342
2420 2515 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2343
2421 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2543 rhodecode/model/db.py:3087
2516 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2543 rhodecode/model/db.py:3105
2422 2517 msgid "Repository creation disabled"
2423 2518 msgstr ""
2424 2519
2425 2520 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:580
2426 2521 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:593
2427 2522 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:610
2428 2523 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:693
2429 2524 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:678
2430 2525 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:680
2431 2526 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:703
2432 2527 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:704
2433 2528 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:721
2434 2529 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:738
2435 2530 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:754
2436 2531 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:757
2437 2532 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:759
2438 2533 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:759
2439 2534 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:786
2440 2535 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:796
2441 2536 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:837
2442 2537 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:837
2443 2538 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:838
2444 2539 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:838
2445 2540 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844
2446 2541 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966
2447 2542 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991
2448 2543 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2609
2449 2544 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2680
2450 2545 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2766
2451 2546 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2799
2452 2547 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2799
2453 2548 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3014
2549 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3100
2454 2550 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2297
2455 2551 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2289
2456 2552 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2288
2457 2553 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2292
2458 2554 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2292
2459 2555 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2343
2460 2556 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2344
2461 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2544 rhodecode/model/db.py:3088
2557 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2544 rhodecode/model/db.py:3106
2462 2558 msgid "Repository creation enabled"
2463 2559 msgstr ""
2464 2560
2465 2561 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:581
2466 2562 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:594
2467 2563 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:611
2468 2564 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:694
2469 2565 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:680
2470 2566 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:682
2471 2567 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:705
2472 2568 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:706
2473 2569 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:723
2474 2570 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:740
2475 2571 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:758
2476 2572 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:761
2477 2573 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:763
2478 2574 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:763
2479 2575 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:790
2480 2576 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:800
2481 2577 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:841
2482 2578 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:841
2483 2579 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:842
2484 2580 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:842
2485 2581 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:848
2486 2582 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:970
2487 2583 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:995
2488 2584 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2613
2489 2585 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2684
2490 2586 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2770
2491 2587 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2803
2492 2588 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2803
2493 2589 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3018
2590 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3104
2494 2591 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2301
2495 2592 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2293
2496 2593 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2292
2497 2594 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2296
2498 2595 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2296
2499 2596 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2347
2500 2597 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2348
2501 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2548 rhodecode/model/db.py:3092
2598 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2548 rhodecode/model/db.py:3110
2502 2599 msgid "Repository forking disabled"
2503 2600 msgstr ""
2504 2601
2505 2602 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:582
2506 2603 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:595
2507 2604 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:612
2508 2605 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:695
2509 2606 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:681
2510 2607 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:683
2511 2608 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:706
2512 2609 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:707
2513 2610 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:724
2514 2611 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:741
2515 2612 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:759
2516 2613 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:762
2517 2614 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:764
2518 2615 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:764
2519 2616 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:791
2520 2617 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:801
2521 2618 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:842
2522 2619 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:842
2523 2620 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:843
2524 2621 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:843
2525 2622 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849
2526 2623 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971
2527 2624 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996
2528 2625 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2614
2529 2626 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2685
2530 2627 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2771
2531 2628 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2804
2532 2629 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2804
2533 2630 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3019
2631 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3105
2534 2632 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2302
2535 2633 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2294
2536 2634 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2293
2537 2635 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2297
2538 2636 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2297
2539 2637 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2348
2540 2638 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2349
2541 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2549 rhodecode/model/db.py:3093
2639 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2549 rhodecode/model/db.py:3111
2542 2640 msgid "Repository forking enabled"
2543 2641 msgstr ""
2544 2642
2545 2643 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:583
2546 2644 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:596
2547 2645 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:613
2548 2646 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:696
2549 2647 msgid "Register disabled"
2550 2648 msgstr ""
2551 2649
2552 2650 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:584
2553 2651 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:597
2554 2652 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:614
2555 2653 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:697
2556 2654 msgid "Register new user with RhodeCode with manual activation"
2557 2655 msgstr ""
2558 2656
2559 2657 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:587
2560 2658 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:600
2561 2659 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:617
2562 2660 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:700
2563 2661 msgid "Register new user with RhodeCode with auto activation"
2564 2662 msgstr ""
2565 2663
2566 2664 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:843
2567 2665 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:864
2568 2666 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:873
2569 2667 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:956
2570 2668 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:994
2571 2669 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:996
2572 2670 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1019
2573 2671 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1020
2574 2672 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1037
2575 2673 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1054
2576 2674 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1073
2577 2675 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1076
2578 2676 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1087
2579 2677 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1090
2580 2678 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1120
2581 2679 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1134
2582 2680 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1175
2583 2681 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1175
2584 2682 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1184
2585 2683 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1184
2586 2684 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1194
2587 2685 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1316
2588 2686 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1341
2589 2687 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3295
2590 2688 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:3378
2591 2689 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:3491
2592 2690 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:3524
2593 2691 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:3525
2594 2692 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3757
2693 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3843
2595 2694 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2915
2596 2695 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2907
2597 2696 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2907
2598 2697 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2910
2599 2698 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2910
2600 2699 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3011
2601 2700 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3012
2602 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3230 rhodecode/model/db.py:3831
2603 #: rhodecode/public/js/scripts.js:44680 rhodecode/public/js/scripts.min.js:1
2604 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:44
2605 #: rhodecode/public/js/src/rhodecode/pullrequests.js:320
2701 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3230 rhodecode/model/db.py:3859
2702 #: rhodecode/public/js/scripts.js:41391 rhodecode/public/js/scripts.min.js:1
2703 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:56
2704 #: rhodecode/public/js/src/rhodecode/pullrequests.js:350
2606 2705 msgid "Not Reviewed"
2607 2706 msgstr ""
2608 2707
2609 2708 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:844
2610 2709 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:865
2611 2710 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:874
2612 2711 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:957
2613 2712 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:995
2614 2713 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:997
2615 2714 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1020
2616 2715 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1021
2617 2716 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1038
2618 2717 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1055
2619 2718 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1074
2620 2719 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1077
2621 2720 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1088
2622 2721 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1091
2623 2722 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1121
2624 2723 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1135
2625 2724 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1176
2626 2725 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1176
2627 2726 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1185
2628 2727 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1185
2629 2728 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1195
2630 2729 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1317
2631 2730 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1342
2632 2731 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3296
2633 2732 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:3379
2634 2733 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:3492
2635 2734 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:3525
2636 2735 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:3526
2637 2736 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3758
2737 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3844
2638 2738 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2916
2639 2739 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2908
2640 2740 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2908
2641 2741 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2911
2642 2742 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2911
2643 2743 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3012
2644 2744 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3013
2645 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3231 rhodecode/model/db.py:3832
2745 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3231 rhodecode/model/db.py:3860
2646 2746 msgid "Approved"
2647 2747 msgstr ""
2648 2748
2649 2749 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:845
2650 2750 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:866
2651 2751 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:875
2652 2752 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:958
2653 2753 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:996
2654 2754 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:998
2655 2755 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1021
2656 2756 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1022
2657 2757 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1039
2658 2758 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1056
2659 2759 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1075
2660 2760 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1078
2661 2761 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1089
2662 2762 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1092
2663 2763 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1122
2664 2764 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1136
2665 2765 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1177
2666 2766 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1177
2667 2767 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1186
2668 2768 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1186
2669 2769 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1196
2670 2770 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1318
2671 2771 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1343
2672 2772 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3297
2673 2773 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:3380
2674 2774 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:3493
2675 2775 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:3526
2676 2776 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:3527
2677 2777 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3759
2778 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3845
2678 2779 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2917
2679 2780 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2909
2680 2781 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2909
2681 2782 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2912
2682 2783 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2912
2683 2784 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3013
2684 2785 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3014
2685 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3232 rhodecode/model/db.py:3833
2786 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3232 rhodecode/model/db.py:3861
2686 2787 msgid "Rejected"
2687 2788 msgstr ""
2688 2789
2689 2790 #: rhodecode/lib/dbmigrate/schema/db_1_4_0.py:846
2690 2791 #: rhodecode/lib/dbmigrate/schema/db_1_5_0.py:867
2691 2792 #: rhodecode/lib/dbmigrate/schema/db_1_5_2.py:876
2692 2793 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:959
2693 2794 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:997
2694 2795 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:999
2695 2796 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:1022
2696 2797 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:1023
2697 2798 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:1040
2698 2799 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:1057
2699 2800 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:1076
2700 2801 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:1079
2701 2802 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:1090
2702 2803 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:1093
2703 2804 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:1123
2704 2805 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:1137
2705 2806 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:1178
2706 2807 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:1178
2707 2808 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:1187
2708 2809 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:1187
2709 2810 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1197
2710 2811 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1319
2711 2812 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1344
2712 2813 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3298
2713 2814 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:3381
2714 2815 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:3494
2715 2816 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:3527
2716 2817 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:3528
2717 2818 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3760
2819 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3846
2718 2820 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2918
2719 2821 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2910
2720 2822 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2910
2721 2823 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2913
2722 2824 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2913
2723 2825 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3014
2724 2826 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3015
2725 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3233 rhodecode/model/db.py:3834
2827 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3233 rhodecode/model/db.py:3862
2726 2828 msgid "Under Review"
2727 2829 msgstr ""
2728 2830
2729 2831 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:686
2730 2832 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:661
2731 2833 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:663
2732 2834 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:686
2733 2835 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:687
2734 2836 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:704
2735 2837 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:721
2736 2838 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:737
2737 2839 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:740
2738 2840 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:742
2739 2841 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:742
2740 2842 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:769
2741 2843 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:779
2742 2844 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:820
2743 2845 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:820
2744 2846 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:821
2745 2847 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:821
2746 2848 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:827
2747 2849 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:949
2748 2850 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:974
2749 2851 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2592
2750 2852 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2658
2751 2853 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2744
2752 2854 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2777
2753 2855 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2777
2754 2856 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2992
2857 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3078
2755 2858 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2280
2756 2859 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2272
2757 2860 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2271
2758 2861 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2275
2759 2862 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2275
2760 2863 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2326
2761 2864 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2327
2762 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2527 rhodecode/model/db.py:3066
2865 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2527 rhodecode/model/db.py:3084
2763 2866 msgid "Repository group no access"
2764 2867 msgstr ""
2765 2868
2766 2869 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:687
2767 2870 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:662
2768 2871 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:664
2769 2872 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:687
2770 2873 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:688
2771 2874 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:705
2772 2875 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:722
2773 2876 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:738
2774 2877 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:741
2775 2878 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:743
2776 2879 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:743
2777 2880 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:770
2778 2881 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:780
2779 2882 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:821
2780 2883 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:821
2781 2884 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:822
2782 2885 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:822
2783 2886 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828
2784 2887 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950
2785 2888 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975
2786 2889 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2593
2787 2890 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2659
2788 2891 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2745
2789 2892 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2778
2790 2893 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2778
2791 2894 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2993
2895 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3079
2792 2896 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2281
2793 2897 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2273
2794 2898 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2272
2795 2899 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2276
2796 2900 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2276
2797 2901 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2327
2798 2902 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2328
2799 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2528 rhodecode/model/db.py:3067
2903 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2528 rhodecode/model/db.py:3085
2800 2904 msgid "Repository group read access"
2801 2905 msgstr ""
2802 2906
2803 2907 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:688
2804 2908 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:663
2805 2909 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:665
2806 2910 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:688
2807 2911 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:689
2808 2912 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:706
2809 2913 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:723
2810 2914 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:739
2811 2915 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:742
2812 2916 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:744
2813 2917 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:744
2814 2918 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:771
2815 2919 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:781
2816 2920 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:822
2817 2921 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:822
2818 2922 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:823
2819 2923 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:823
2820 2924 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829
2821 2925 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951
2822 2926 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976
2823 2927 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2594
2824 2928 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2660
2825 2929 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2746
2826 2930 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2779
2827 2931 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2779
2828 2932 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2994
2933 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3080
2829 2934 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2282
2830 2935 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2274
2831 2936 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2273
2832 2937 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2277
2833 2938 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2277
2834 2939 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2328
2835 2940 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2329
2836 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2529 rhodecode/model/db.py:3068
2941 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2529 rhodecode/model/db.py:3086
2837 2942 msgid "Repository group write access"
2838 2943 msgstr ""
2839 2944
2840 2945 #: rhodecode/lib/dbmigrate/schema/db_1_6_0.py:689
2841 2946 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:664
2842 2947 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:666
2843 2948 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:689
2844 2949 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:690
2845 2950 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:707
2846 2951 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:724
2847 2952 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:740
2848 2953 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:743
2849 2954 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:745
2850 2955 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:745
2851 2956 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:772
2852 2957 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:782
2853 2958 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:823
2854 2959 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:823
2855 2960 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:824
2856 2961 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:824
2857 2962 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:830
2858 2963 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:952
2859 2964 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:977
2860 2965 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2595
2861 2966 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2661
2862 2967 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2747
2863 2968 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2780
2864 2969 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2780
2865 2970 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2995
2971 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3081
2866 2972 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2283
2867 2973 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2275
2868 2974 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2274
2869 2975 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2278
2870 2976 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2278
2871 2977 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2329
2872 2978 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2330
2873 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2530 rhodecode/model/db.py:3069
2979 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2530 rhodecode/model/db.py:3087
2874 2980 msgid "Repository group admin access"
2875 2981 msgstr ""
2876 2982
2877 2983 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:666
2878 2984 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:668
2879 2985 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:691
2880 2986 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:692
2881 2987 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:709
2882 2988 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:726
2883 2989 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:742
2884 2990 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:745
2885 2991 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:747
2886 2992 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:747
2887 2993 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:774
2888 2994 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:784
2889 2995 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:825
2890 2996 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:825
2891 2997 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:826
2892 2998 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:826
2893 2999 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:832
2894 3000 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:954
2895 3001 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:979
2896 3002 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2597
2897 3003 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2663
2898 3004 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2749
2899 3005 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2782
2900 3006 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2782
2901 3007 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2997
3008 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3083
2902 3009 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2285
2903 3010 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2277
2904 3011 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2276
2905 3012 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2280
2906 3013 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2280
2907 3014 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2331
2908 3015 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2332
2909 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2532 rhodecode/model/db.py:3071
3016 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2532 rhodecode/model/db.py:3089
2910 3017 msgid "User group no access"
2911 3018 msgstr ""
2912 3019
2913 3020 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:667
2914 3021 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:669
2915 3022 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:692
2916 3023 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:693
2917 3024 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:710
2918 3025 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:727
2919 3026 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:743
2920 3027 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:746
2921 3028 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:748
2922 3029 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:748
2923 3030 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:775
2924 3031 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:785
2925 3032 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:826
2926 3033 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:826
2927 3034 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:827
2928 3035 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:827
2929 3036 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833
2930 3037 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955
2931 3038 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980
2932 3039 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2598
2933 3040 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2664
2934 3041 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2750
2935 3042 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2783
2936 3043 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2783
2937 3044 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2998
3045 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3084
2938 3046 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2286
2939 3047 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2278
2940 3048 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2277
2941 3049 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2281
2942 3050 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2281
2943 3051 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2332
2944 3052 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2333
2945 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2533 rhodecode/model/db.py:3072
3053 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2533 rhodecode/model/db.py:3090
2946 3054 msgid "User group read access"
2947 3055 msgstr ""
2948 3056
2949 3057 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:668
2950 3058 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:670
2951 3059 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:693
2952 3060 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:694
2953 3061 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:711
2954 3062 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:728
2955 3063 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:744
2956 3064 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:747
2957 3065 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:749
2958 3066 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:749
2959 3067 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:776
2960 3068 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:786
2961 3069 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:827
2962 3070 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:827
2963 3071 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:828
2964 3072 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:828
2965 3073 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834
2966 3074 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956
2967 3075 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981
2968 3076 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2599
2969 3077 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2665
2970 3078 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2751
2971 3079 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2784
2972 3080 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2784
2973 3081 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2999
3082 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3085
2974 3083 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2287
2975 3084 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2279
2976 3085 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2278
2977 3086 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2282
2978 3087 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2282
2979 3088 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2333
2980 3089 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2334
2981 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2534 rhodecode/model/db.py:3073
3090 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2534 rhodecode/model/db.py:3091
2982 3091 msgid "User group write access"
2983 3092 msgstr ""
2984 3093
2985 3094 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:669
2986 3095 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:671
2987 3096 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:694
2988 3097 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:695
2989 3098 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:712
2990 3099 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:729
2991 3100 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:745
2992 3101 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:748
2993 3102 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:750
2994 3103 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:750
2995 3104 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:777
2996 3105 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:787
2997 3106 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:828
2998 3107 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:828
2999 3108 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:829
3000 3109 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:829
3001 3110 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:835
3002 3111 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:957
3003 3112 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:982
3004 3113 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2600
3005 3114 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2666
3006 3115 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2752
3007 3116 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2785
3008 3117 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2785
3009 3118 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3000
3119 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3086
3010 3120 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2288
3011 3121 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2280
3012 3122 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2279
3013 3123 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2283
3014 3124 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2283
3015 3125 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2334
3016 3126 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2335
3017 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2535 rhodecode/model/db.py:3074
3127 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2535 rhodecode/model/db.py:3092
3018 3128 msgid "User group admin access"
3019 3129 msgstr ""
3020 3130
3021 3131 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:671
3022 3132 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:673
3023 3133 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:696
3024 3134 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:697
3025 3135 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:714
3026 3136 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:731
3027 3137 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:747
3028 3138 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:750
3029 3139 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:752
3030 3140 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:752
3031 3141 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:779
3032 3142 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:789
3033 3143 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:830
3034 3144 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:830
3035 3145 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:831
3036 3146 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:831
3037 3147 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:837
3038 3148 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:959
3039 3149 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:984
3040 3150 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2602
3041 3151 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2673
3042 3152 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2759
3043 3153 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2792
3044 3154 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2792
3045 3155 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3007
3156 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3093
3046 3157 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2290
3047 3158 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2282
3048 3159 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2281
3049 3160 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2285
3050 3161 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2285
3051 3162 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2336
3052 3163 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2337
3053 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2537 rhodecode/model/db.py:3081
3164 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2537 rhodecode/model/db.py:3099
3054 3165 msgid "Repository Group creation disabled"
3055 3166 msgstr ""
3056 3167
3057 3168 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:672
3058 3169 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:674
3059 3170 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:697
3060 3171 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:698
3061 3172 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:715
3062 3173 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:732
3063 3174 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:748
3064 3175 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:751
3065 3176 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:753
3066 3177 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:753
3067 3178 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:780
3068 3179 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:790
3069 3180 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:831
3070 3181 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:831
3071 3182 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:832
3072 3183 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:832
3073 3184 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838
3074 3185 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960
3075 3186 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985
3076 3187 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2603
3077 3188 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2674
3078 3189 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2760
3079 3190 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2793
3080 3191 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2793
3081 3192 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3008
3193 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3094
3082 3194 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2291
3083 3195 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2283
3084 3196 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2282
3085 3197 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2286
3086 3198 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2286
3087 3199 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2337
3088 3200 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2338
3089 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2538 rhodecode/model/db.py:3082
3201 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2538 rhodecode/model/db.py:3100
3090 3202 msgid "Repository Group creation enabled"
3091 3203 msgstr ""
3092 3204
3093 3205 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:674
3094 3206 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:676
3095 3207 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:699
3096 3208 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:700
3097 3209 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:717
3098 3210 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:734
3099 3211 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:750
3100 3212 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:753
3101 3213 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:755
3102 3214 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:755
3103 3215 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:782
3104 3216 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:792
3105 3217 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:833
3106 3218 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:833
3107 3219 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:834
3108 3220 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:834
3109 3221 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:840
3110 3222 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:962
3111 3223 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:987
3112 3224 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2605
3113 3225 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2676
3114 3226 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2762
3115 3227 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2795
3116 3228 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2795
3117 3229 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3010
3230 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3096
3118 3231 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2293
3119 3232 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2285
3120 3233 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2284
3121 3234 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2288
3122 3235 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2288
3123 3236 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2339
3124 3237 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2340
3125 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2540 rhodecode/model/db.py:3084
3238 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2540 rhodecode/model/db.py:3102
3126 3239 msgid "User Group creation disabled"
3127 3240 msgstr ""
3128 3241
3129 3242 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:675
3130 3243 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:677
3131 3244 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:700
3132 3245 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:701
3133 3246 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:718
3134 3247 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:735
3135 3248 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:751
3136 3249 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:754
3137 3250 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:756
3138 3251 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:756
3139 3252 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:783
3140 3253 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:793
3141 3254 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:834
3142 3255 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:834
3143 3256 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:835
3144 3257 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:835
3145 3258 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841
3146 3259 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963
3147 3260 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988
3148 3261 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2606
3149 3262 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2677
3150 3263 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2763
3151 3264 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2796
3152 3265 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2796
3153 3266 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3011
3267 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3097
3154 3268 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2294
3155 3269 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2286
3156 3270 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2285
3157 3271 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2289
3158 3272 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2289
3159 3273 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2340
3160 3274 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2341
3161 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2541 rhodecode/model/db.py:3085
3275 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2541 rhodecode/model/db.py:3103
3162 3276 msgid "User Group creation enabled"
3163 3277 msgstr ""
3164 3278
3165 3279 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:683
3166 3280 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:685
3167 3281 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:708
3168 3282 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:709
3169 3283 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:726
3170 3284 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:743
3171 3285 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:761
3172 3286 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:764
3173 3287 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:766
3174 3288 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:766
3175 3289 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:793
3176 3290 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:803
3177 3291 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:844
3178 3292 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:844
3179 3293 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:845
3180 3294 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:845
3181 3295 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:851
3182 3296 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:973
3183 3297 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:998
3184 3298 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2616
3185 3299 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2687
3186 3300 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2773
3187 3301 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2806
3188 3302 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2806
3189 3303 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3021
3304 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3107
3190 3305 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2304
3191 3306 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2296
3192 3307 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2295
3193 3308 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2299
3194 3309 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2299
3195 3310 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2350
3196 3311 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2351
3197 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2551 rhodecode/model/db.py:3095
3312 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2551 rhodecode/model/db.py:3113
3198 3313 msgid "Registration disabled"
3199 3314 msgstr ""
3200 3315
3201 3316 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:684
3202 3317 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:686
3203 3318 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:709
3204 3319 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:710
3205 3320 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:727
3206 3321 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:744
3207 3322 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:762
3208 3323 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:765
3209 3324 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:767
3210 3325 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:767
3211 3326 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:794
3212 3327 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:804
3213 3328 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:845
3214 3329 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:845
3215 3330 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:846
3216 3331 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:846
3217 3332 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852
3218 3333 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974
3219 3334 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999
3220 3335 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2617
3221 3336 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2688
3222 3337 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2774
3223 3338 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2807
3224 3339 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2807
3225 3340 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3022
3341 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3108
3226 3342 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2305
3227 3343 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2297
3228 3344 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2296
3229 3345 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2300
3230 3346 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2300
3231 3347 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2351
3232 3348 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2352
3233 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2552 rhodecode/model/db.py:3096
3349 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2552 rhodecode/model/db.py:3114
3234 3350 msgid "User Registration with manual account activation"
3235 3351 msgstr ""
3236 3352
3237 3353 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:685
3238 3354 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:687
3239 3355 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:710
3240 3356 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:711
3241 3357 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:728
3242 3358 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:745
3243 3359 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:763
3244 3360 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:766
3245 3361 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:768
3246 3362 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:768
3247 3363 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:795
3248 3364 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:805
3249 3365 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:846
3250 3366 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:846
3251 3367 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:847
3252 3368 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:847
3253 3369 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853
3254 3370 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975
3255 3371 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000
3256 3372 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2618
3257 3373 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2689
3258 3374 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2775
3259 3375 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2808
3260 3376 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2808
3261 3377 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3023
3378 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3109
3262 3379 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2306
3263 3380 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2298
3264 3381 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2297
3265 3382 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2301
3266 3383 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2301
3267 3384 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2352
3268 3385 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2353
3269 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2553 rhodecode/model/db.py:3097
3386 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2553 rhodecode/model/db.py:3115
3270 3387 msgid "User Registration with automatic account activation"
3271 3388 msgstr ""
3272 3389
3273 3390 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:687
3274 3391 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:689
3275 3392 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:712
3276 3393 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:713
3277 3394 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:730
3278 3395 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:747
3279 3396 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:765
3280 3397 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:768
3281 3398 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:770
3282 3399 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:770
3283 3400 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:797
3284 3401 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:807
3285 3402 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:848
3286 3403 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:848
3287 3404 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:849
3288 3405 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:849
3289 3406 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:855
3290 3407 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:977
3291 3408 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1002
3292 3409 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2624
3293 3410 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2695
3294 3411 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2781
3295 3412 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2814
3296 3413 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2814
3297 3414 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3029
3415 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3115
3298 3416 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2308
3299 3417 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2300
3300 3418 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2299
3301 3419 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2303
3302 3420 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2303
3303 3421 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2358
3304 3422 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2359
3305 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2559 rhodecode/model/db.py:3103
3306 #: rhodecode/model/permission.py:106
3423 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2559 rhodecode/model/db.py:3121
3424 #: rhodecode/model/permission.py:105
3307 3425 msgid "Manual activation of external account"
3308 3426 msgstr ""
3309 3427
3310 3428 #: rhodecode/lib/dbmigrate/schema/db_1_7_0.py:688
3311 3429 #: rhodecode/lib/dbmigrate/schema/db_1_8_0.py:690
3312 3430 #: rhodecode/lib/dbmigrate/schema/db_2_0_0.py:713
3313 3431 #: rhodecode/lib/dbmigrate/schema/db_2_0_1.py:714
3314 3432 #: rhodecode/lib/dbmigrate/schema/db_2_0_2.py:731
3315 3433 #: rhodecode/lib/dbmigrate/schema/db_2_1_0.py:748
3316 3434 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:766
3317 3435 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:769
3318 3436 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:771
3319 3437 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:771
3320 3438 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:798
3321 3439 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:808
3322 3440 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:849
3323 3441 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:849
3324 3442 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:850
3325 3443 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:850
3326 3444 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856
3327 3445 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978
3328 3446 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003
3329 3447 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2625
3330 3448 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2696
3331 3449 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2782
3332 3450 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2815
3333 3451 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2815
3334 3452 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3030
3453 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3116
3335 3454 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2309
3336 3455 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2301
3337 3456 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2300
3338 3457 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2304
3339 3458 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2304
3340 3459 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2359
3341 3460 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2360
3342 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2560 rhodecode/model/db.py:3104
3343 #: rhodecode/model/permission.py:107
3461 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2560 rhodecode/model/db.py:3122
3462 #: rhodecode/model/permission.py:106
3344 3463 msgid "Automatic activation of external account"
3345 3464 msgstr ""
3346 3465
3347 3466 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:755
3348 3467 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:758
3349 3468 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:760
3350 3469 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:760
3351 3470 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:787
3352 3471 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:797
3353 3472 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:838
3354 3473 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:838
3355 3474 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:839
3356 3475 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:839
3357 3476 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845
3358 3477 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967
3359 3478 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992
3360 3479 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2610
3361 3480 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2681
3362 3481 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2767
3363 3482 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2800
3364 3483 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2800
3365 3484 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3015
3485 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3101
3366 3486 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2298
3367 3487 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2290
3368 3488 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2289
3369 3489 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2293
3370 3490 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2293
3371 3491 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2344
3372 3492 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2345
3373 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2545 rhodecode/model/db.py:3089
3493 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2545 rhodecode/model/db.py:3107
3374 3494 msgid "Repository creation enabled with write permission to a repository group"
3375 3495 msgstr ""
3376 3496
3377 3497 #: rhodecode/lib/dbmigrate/schema/db_2_2_0.py:756
3378 3498 #: rhodecode/lib/dbmigrate/schema/db_2_2_3.py:759
3379 3499 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_0.py:761
3380 3500 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:761
3381 3501 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:788
3382 3502 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:798
3383 3503 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:839
3384 3504 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:839
3385 3505 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:840
3386 3506 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:840
3387 3507 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:846
3388 3508 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:968
3389 3509 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:993
3390 3510 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2611
3391 3511 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2682
3392 3512 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2768
3393 3513 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2801
3394 3514 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2801
3395 3515 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3016
3516 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3102
3396 3517 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2299
3397 3518 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2291
3398 3519 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2290
3399 3520 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2294
3400 3521 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2294
3401 3522 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2345
3402 3523 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2346
3403 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2546 rhodecode/model/db.py:3090
3524 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2546 rhodecode/model/db.py:3108
3404 3525 msgid "Repository creation disabled with write permission to a repository group"
3405 3526 msgstr ""
3406 3527
3407 3528 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_1.py:735
3408 3529 #: rhodecode/lib/dbmigrate/schema/db_2_3_0_2.py:762
3409 3530 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:772
3410 3531 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:813
3411 3532 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:813
3412 3533 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:814
3413 3534 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:814
3414 3535 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:820
3415 3536 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:942
3416 3537 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:967
3417 3538 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2585
3418 3539 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2651
3419 3540 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2737
3420 3541 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2770
3421 3542 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2770
3422 3543 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2985
3544 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3071
3423 3545 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2273
3424 3546 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2265
3425 3547 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2264
3426 3548 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2268
3427 3549 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2268
3428 3550 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2319
3429 3551 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2320
3430 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2520 rhodecode/model/db.py:3059
3552 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2520 rhodecode/model/db.py:3077
3431 3553 msgid "RhodeCode Super Administrator"
3432 3554 msgstr ""
3433 3555
3434 3556 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:810
3435 3557 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:851
3436 3558 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:851
3437 3559 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:852
3438 3560 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:852
3439 3561 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:858
3440 3562 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:980
3441 3563 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1005
3442 3564 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2627
3443 3565 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2698
3444 3566 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2784
3445 3567 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2817
3446 3568 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2817
3447 3569 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3032
3570 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3118
3448 3571 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2311
3449 3572 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2303
3450 3573 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2302
3451 3574 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2306
3452 3575 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2306
3453 3576 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2361
3454 3577 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2362
3455 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2562 rhodecode/model/db.py:3106
3578 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2562 rhodecode/model/db.py:3124
3456 3579 msgid "Inherit object permissions from default user disabled"
3457 3580 msgstr ""
3458 3581
3459 3582 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_0.py:811
3460 3583 #: rhodecode/lib/dbmigrate/schema/db_3_0_0_1.py:852
3461 3584 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_0.py:852
3462 3585 #: rhodecode/lib/dbmigrate/schema/db_3_1_0_1.py:853
3463 3586 #: rhodecode/lib/dbmigrate/schema/db_3_2_0_0.py:853
3464 3587 #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859
3465 3588 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981
3466 3589 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006
3467 3590 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2628
3468 3591 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2699
3469 3592 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2785
3470 3593 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2818
3471 3594 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2818
3472 3595 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3033
3596 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3119
3473 3597 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2312
3474 3598 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2304
3475 3599 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2303
3476 3600 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2307
3477 3601 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2307
3478 3602 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2362
3479 3603 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2363
3480 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2563 rhodecode/model/db.py:3107
3604 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2563 rhodecode/model/db.py:3125
3481 3605 msgid "Inherit object permissions from default user enabled"
3482 3606 msgstr ""
3483 3607
3484 3608 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1103
3485 3609 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1107
3486 3610 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:1118
3487 3611 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:1120
3488 3612 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:1120
3489 3613 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:1137
3614 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:1189
3490 3615 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:910
3491 3616 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:911
3492 3617 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:910
3493 3618 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:912
3494 3619 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:912
3495 3620 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:955
3496 3621 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:956
3497 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1050 rhodecode/model/db.py:1178
3622 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1050 rhodecode/model/db.py:1195
3498 3623 msgid "all"
3499 3624 msgstr ""
3500 3625
3501 3626 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1104
3502 3627 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1108
3503 3628 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:1119
3504 3629 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:1121
3505 3630 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:1121
3506 3631 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:1138
3632 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:1190
3507 3633 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:911
3508 3634 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:912
3509 3635 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:911
3510 3636 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:913
3511 3637 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:913
3512 3638 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:956
3513 3639 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:957
3514 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1051 rhodecode/model/db.py:1179
3640 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1051 rhodecode/model/db.py:1196
3515 3641 msgid "http/web interface"
3516 3642 msgstr ""
3517 3643
3518 3644 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1105
3519 3645 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1109
3520 3646 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:1120
3521 3647 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:1122
3522 3648 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:1122
3523 3649 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:1139
3650 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:1191
3524 3651 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:912
3525 3652 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:913
3526 3653 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:912
3527 3654 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:914
3528 3655 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:914
3529 3656 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:957
3530 3657 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:958
3531 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1052 rhodecode/model/db.py:1180
3658 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1052 rhodecode/model/db.py:1197
3532 3659 msgid "vcs (git/hg/svn protocol)"
3533 3660 msgstr ""
3534 3661
3535 3662 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1106
3536 3663 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1110
3537 3664 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:1121
3538 3665 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:1123
3539 3666 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:1123
3540 3667 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:1140
3668 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:1192
3541 3669 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:913
3542 3670 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:914
3543 3671 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:913
3544 3672 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:915
3545 3673 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:915
3546 3674 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:958
3547 3675 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:959
3548 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1053 rhodecode/model/db.py:1181
3676 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1053 rhodecode/model/db.py:1198
3549 3677 msgid "api calls"
3550 3678 msgstr ""
3551 3679
3552 3680 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1107
3553 3681 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:1111
3554 3682 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:1122
3555 3683 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:1124
3556 3684 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:1124
3557 3685 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:1141
3686 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:1193
3558 3687 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:914
3559 3688 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:915
3560 3689 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:914
3561 3690 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:916
3562 3691 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:916
3563 3692 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:959
3564 3693 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:960
3565 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1054 rhodecode/model/db.py:1182
3694 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1054 rhodecode/model/db.py:1199
3566 3695 msgid "feed access"
3567 3696 msgstr ""
3568 3697
3569 3698 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2348
3570 3699 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2414
3571 3700 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2488
3572 3701 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2511
3573 3702 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2511
3574 3703 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:2638
3704 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:2729
3575 3705 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2051
3576 3706 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2043
3577 3707 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2042
3578 3708 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_2.py:2046
3579 3709 #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2046
3580 3710 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2090
3581 3711 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2091
3582 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2284 rhodecode/model/db.py:2717
3712 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2284 rhodecode/model/db.py:2735
3583 3713 msgid "No parent"
3584 3714 msgstr ""
3585 3715
3586 3716 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2620
3587 3717 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2691
3588 3718 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2777
3589 3719 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2810
3590 3720 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2810
3591 3721 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3025
3722 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3111
3592 3723 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2354
3593 3724 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2355
3594 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2555 rhodecode/model/db.py:3099
3725 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2555 rhodecode/model/db.py:3117
3595 3726 msgid "Password reset enabled"
3596 3727 msgstr ""
3597 3728
3598 3729 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2621
3599 3730 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2692
3600 3731 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2778
3601 3732 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2811
3602 3733 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2811
3603 3734 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3026
3735 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3112
3604 3736 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2355
3605 3737 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2356
3606 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2556 rhodecode/model/db.py:3100
3738 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2556 rhodecode/model/db.py:3118
3607 3739 msgid "Password reset hidden"
3608 3740 msgstr ""
3609 3741
3610 3742 #: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2622
3611 3743 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2693
3612 3744 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2779
3613 3745 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2812
3614 3746 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2812
3615 3747 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3027
3748 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3113
3616 3749 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2356
3617 3750 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2357
3618 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2557 rhodecode/model/db.py:3101
3751 #: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2557 rhodecode/model/db.py:3119
3619 3752 msgid "Password reset disabled"
3620 3753 msgstr ""
3621 3754
3622 3755 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2668
3623 3756 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2754
3624 3757 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2787
3625 3758 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2787
3626 3759 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3002
3627 #: rhodecode/model/db.py:3076
3760 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3088
3761 #: rhodecode/model/db.py:3094
3628 3762 msgid "Branch no permissions"
3629 3763 msgstr ""
3630 3764
3631 3765 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2669
3632 3766 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2755
3633 3767 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2788
3634 3768 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2788
3635 3769 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3003
3636 #: rhodecode/model/db.py:3077
3770 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3089
3771 #: rhodecode/model/db.py:3095
3637 3772 msgid "Branch access by web merge"
3638 3773 msgstr ""
3639 3774
3640 3775 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2670
3641 3776 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2756
3642 3777 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2789
3643 3778 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2789
3644 3779 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3004
3645 #: rhodecode/model/db.py:3078
3780 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3090
3781 #: rhodecode/model/db.py:3096
3646 3782 msgid "Branch access by push"
3647 3783 msgstr ""
3648 3784
3649 3785 #: rhodecode/lib/dbmigrate/schema/db_4_13_0_0.py:2671
3650 3786 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_0.py:2757
3651 3787 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_1.py:2790
3652 3788 #: rhodecode/lib/dbmigrate/schema/db_4_16_0_2.py:2790
3653 3789 #: rhodecode/lib/dbmigrate/schema/db_4_18_0_1.py:3005
3654 #: rhodecode/model/db.py:3079
3790 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:3091
3791 #: rhodecode/model/db.py:3097
3655 3792 msgid "Branch access by push with force"
3656 3793 msgstr ""
3657 3794
3795 #: rhodecode/lib/dbmigrate/schema/db_4_19_0_0.py:1194
3796 #: rhodecode/model/db.py:1200
3797 msgid "artifacts downloads"
3798 msgstr ""
3799
3658 3800 #: rhodecode/lib/index/whoosh.py:189
3659 3801 msgid "Index Type"
3660 3802 msgstr ""
3661 3803
3662 3804 #: rhodecode/lib/index/whoosh.py:192
3663 3805 msgid "File Index"
3664 3806 msgstr ""
3665 3807
3666 3808 #: rhodecode/lib/index/whoosh.py:193 rhodecode/lib/index/whoosh.py:199
3667 3809 msgid "Indexed documents"
3668 3810 msgstr ""
3669 3811
3670 3812 #: rhodecode/lib/index/whoosh.py:194 rhodecode/lib/index/whoosh.py:200
3671 3813 msgid "Last update"
3672 3814 msgstr ""
3673 3815
3674 3816 #: rhodecode/lib/index/whoosh.py:198
3675 3817 msgid "Commit index"
3676 3818 msgstr ""
3677 3819
3678 3820 #: rhodecode/lib/vcs/backends/base.py:150
3679 3821 msgid "This pull request can be automatically merged."
3680 3822 msgstr ""
3681 3823
3682 3824 #: rhodecode/lib/vcs/backends/base.py:152
3683 3825 msgid "This pull request cannot be merged because of an unhandled exception. {exception}"
3684 3826 msgstr ""
3685 3827
3686 3828 #: rhodecode/lib/vcs/backends/base.py:155
3687 3829 msgid "This pull request cannot be merged because of merge conflicts. {unresolved_files}"
3688 3830 msgstr ""
3689 3831
3690 3832 #: rhodecode/lib/vcs/backends/base.py:157
3691 3833 msgid "This pull request could not be merged because push to target:`{target}@{merge_commit}` failed."
3692 3834 msgstr ""
3693 3835
3694 3836 #: rhodecode/lib/vcs/backends/base.py:160
3695 3837 msgid "This pull request cannot be merged because the target `{target_ref.name}` is not a head."
3696 3838 msgstr ""
3697 3839
3698 3840 #: rhodecode/lib/vcs/backends/base.py:163
3699 3841 msgid "This pull request cannot be merged because the source contains more branches than the target."
3700 3842 msgstr ""
3701 3843
3702 3844 #: rhodecode/lib/vcs/backends/base.py:166
3703 3845 msgid "This pull request cannot be merged because the target `{target_ref.name}` has multiple heads: `{heads}`."
3704 3846 msgstr ""
3705 3847
3706 3848 #: rhodecode/lib/vcs/backends/base.py:169
3707 3849 msgid "This pull request cannot be merged because the target repository is locked by {locked_by}."
3708 3850 msgstr ""
3709 3851
3710 3852 #: rhodecode/lib/vcs/backends/base.py:173
3711 3853 msgid "This pull request cannot be merged because the target reference `{target_ref.name}` is missing."
3712 3854 msgstr ""
3713 3855
3714 3856 #: rhodecode/lib/vcs/backends/base.py:176
3715 3857 msgid "This pull request cannot be merged because the source reference `{source_ref.name}` is missing."
3716 3858 msgstr ""
3717 3859
3718 3860 #: rhodecode/lib/vcs/backends/base.py:179
3719 3861 msgid "This pull request cannot be merged because of conflicts related to sub repositories."
3720 3862 msgstr ""
3721 3863
3722 3864 #: rhodecode/lib/vcs/backends/base.py:184
3723 3865 msgid "This pull request cannot be merged because the target or the source reference is missing."
3724 3866 msgstr ""
3725 3867
3726 3868 #: rhodecode/model/auth_token.py:53
3727 3869 msgid "5 minutes {end_date}"
3728 3870 msgstr ""
3729 3871
3730 3872 #: rhodecode/model/auth_token.py:55
3731 3873 msgid "1 hour {end_date}"
3732 3874 msgstr ""
3733 3875
3734 3876 #: rhodecode/model/auth_token.py:57
3735 3877 msgid "1 day {end_date}"
3736 3878 msgstr ""
3737 3879
3738 3880 #: rhodecode/model/auth_token.py:59
3739 3881 msgid "1 month {end_date}"
3740 3882 msgstr ""
3741 3883
3742 3884 #: rhodecode/model/comment.py:473
3743 3885 msgid "made a comment"
3744 3886 msgstr ""
3745 3887
3746 3888 #: rhodecode/model/comment.py:474
3747 3889 msgid "Show it now"
3748 3890 msgstr ""
3749 3891
3750 #: rhodecode/model/db.py:1183
3751 msgid "artifacts downloads"
3752 msgstr ""
3753
3754 3892 #: rhodecode/model/forms.py:88
3755 3893 msgid "Please enter a login"
3756 3894 msgstr ""
3757 3895
3758 3896 #: rhodecode/model/forms.py:89
3759 3897 #, python-format
3760 3898 msgid "Enter a value %(min)i characters long or more"
3761 3899 msgstr ""
3762 3900
3763 3901 #: rhodecode/model/forms.py:99
3764 3902 msgid "Please enter a password"
3765 3903 msgstr ""
3766 3904
3767 3905 #: rhodecode/model/forms.py:100
3768 3906 #, python-format
3769 3907 msgid "Enter %(min)i characters or more"
3770 3908 msgstr ""
3771 3909
3772 #: rhodecode/model/notification.py:245
3910 #: rhodecode/model/notification.py:246
3773 3911 #, python-format
3774 3912 msgid "%(user)s commented on commit %(date_or_age)s"
3775 3913 msgstr ""
3776 3914
3777 #: rhodecode/model/notification.py:246
3915 #: rhodecode/model/notification.py:247
3778 3916 #, python-format
3779 3917 msgid "%(user)s commented on commit at %(date_or_age)s"
3780 3918 msgstr ""
3781 3919
3782 #: rhodecode/model/notification.py:249
3783 #, python-format
3784 msgid "%(user)s sent message %(date_or_age)s"
3785 msgstr ""
3786
3787 3920 #: rhodecode/model/notification.py:250
3788 3921 #, python-format
3922 msgid "%(user)s sent message %(date_or_age)s"
3923 msgstr ""
3924
3925 #: rhodecode/model/notification.py:251
3926 #, python-format
3789 3927 msgid "%(user)s sent message at %(date_or_age)s"
3790 3928 msgstr ""
3791 3929
3792 #: rhodecode/model/notification.py:253
3793 #, python-format
3794 msgid "%(user)s mentioned you %(date_or_age)s"
3795 msgstr ""
3796
3797 3930 #: rhodecode/model/notification.py:254
3798 3931 #, python-format
3932 msgid "%(user)s mentioned you %(date_or_age)s"
3933 msgstr ""
3934
3935 #: rhodecode/model/notification.py:255
3936 #, python-format
3799 3937 msgid "%(user)s mentioned you at %(date_or_age)s"
3800 3938 msgstr ""
3801 3939
3802 #: rhodecode/model/notification.py:257
3803 #, python-format
3804 msgid "%(user)s registered in RhodeCode %(date_or_age)s"
3805 msgstr ""
3806
3807 3940 #: rhodecode/model/notification.py:258
3808 3941 #, python-format
3942 msgid "%(user)s registered in RhodeCode %(date_or_age)s"
3943 msgstr ""
3944
3945 #: rhodecode/model/notification.py:259
3946 #, python-format
3809 3947 msgid "%(user)s registered in RhodeCode at %(date_or_age)s"
3810 3948 msgstr ""
3811 3949
3812 #: rhodecode/model/notification.py:261
3813 #, python-format
3814 msgid "%(user)s opened new pull request %(date_or_age)s"
3815 msgstr ""
3816
3817 3950 #: rhodecode/model/notification.py:262
3818 3951 #, python-format
3952 msgid "%(user)s opened new pull request %(date_or_age)s"
3953 msgstr ""
3954
3955 #: rhodecode/model/notification.py:263
3956 #, python-format
3819 3957 msgid "%(user)s opened new pull request at %(date_or_age)s"
3820 3958 msgstr ""
3821 3959
3822 #: rhodecode/model/notification.py:265
3823 #, python-format
3824 msgid "%(user)s updated pull request %(date_or_age)s"
3825 msgstr ""
3826
3827 3960 #: rhodecode/model/notification.py:266
3828 3961 #, python-format
3962 msgid "%(user)s updated pull request %(date_or_age)s"
3963 msgstr ""
3964
3965 #: rhodecode/model/notification.py:267
3966 #, python-format
3829 3967 msgid "%(user)s updated pull request at %(date_or_age)s"
3830 3968 msgstr ""
3831 3969
3832 #: rhodecode/model/notification.py:269
3833 #, python-format
3834 msgid "%(user)s commented on pull request %(date_or_age)s"
3835 msgstr ""
3836
3837 3970 #: rhodecode/model/notification.py:270
3838 3971 #, python-format
3972 msgid "%(user)s commented on pull request %(date_or_age)s"
3973 msgstr ""
3974
3975 #: rhodecode/model/notification.py:271
3976 #, python-format
3839 3977 msgid "%(user)s commented on pull request at %(date_or_age)s"
3840 3978 msgstr ""
3841 3979
3980 #: rhodecode/model/permission.py:71 rhodecode/model/permission.py:77
3981 #: rhodecode/model/permission.py:83
3982 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:11
3983 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:207
3984 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:11
3985 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:15
3986 msgid "None"
3987 msgstr ""
3988
3842 3989 #: rhodecode/model/permission.py:72 rhodecode/model/permission.py:78
3843 3990 #: rhodecode/model/permission.py:84
3844 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:11
3845 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:197
3846 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:11
3847 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:11
3848 msgid "None"
3991 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:12
3992 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:12
3993 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:16
3994 msgid "Read"
3849 3995 msgstr ""
3850 3996
3851 3997 #: rhodecode/model/permission.py:73 rhodecode/model/permission.py:79
3852 3998 #: rhodecode/model/permission.py:85
3853 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:12
3854 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:12
3855 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:12
3856 msgid "Read"
3999 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:13
4000 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:13
4001 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:17
4002 #: rhodecode/templates/changeset/changeset_file_comment.mako:272
4003 #: rhodecode/templates/changeset/changeset_file_comment.mako:323
4004 #: rhodecode/templates/data_table/_dt_elements.mako:450
4005 msgid "Write"
3857 4006 msgstr ""
3858 4007
3859 4008 #: rhodecode/model/permission.py:74 rhodecode/model/permission.py:80
3860 4009 #: rhodecode/model/permission.py:86
3861 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:13
3862 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:13
3863 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:13
3864 #: rhodecode/templates/changeset/changeset_file_comment.mako:268
3865 #: rhodecode/templates/changeset/changeset_file_comment.mako:319
3866 #: rhodecode/templates/data_table/_dt_elements.mako:440
3867 msgid "Write"
3868 msgstr ""
3869
3870 #: rhodecode/model/permission.py:75 rhodecode/model/permission.py:81
3871 #: rhodecode/model/permission.py:87
3872 4010 #: rhodecode/templates/admin/auth/plugin_settings.mako:12
3873 4011 #: rhodecode/templates/admin/defaults/defaults.mako:12
3874 4012 #: rhodecode/templates/admin/integrations/base.mako:21
3875 4013 #: rhodecode/templates/admin/integrations/form.mako:15
3876 4014 #: rhodecode/templates/admin/integrations/form.mako:28
3877 4015 #: rhodecode/templates/admin/integrations/global.mako:12
3878 4016 #: rhodecode/templates/admin/integrations/list.mako:8
3879 4017 #: rhodecode/templates/admin/integrations/list.mako:14
3880 4018 #: rhodecode/templates/admin/integrations/new.mako:11
3881 4019 #: rhodecode/templates/admin/permissions/permissions.mako:12
3882 4020 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:12
3883 4021 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:14
3884 4022 #: rhodecode/templates/admin/repos/repo_add.mako:13
3885 4023 #: rhodecode/templates/admin/repos/repo_add.mako:17
3886 4024 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:14
3887 4025 #: rhodecode/templates/admin/settings/settings.mako:12
3888 4026 #: rhodecode/templates/admin/user_groups/user_group_add.mako:11
3889 4027 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:12
3890 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:14
4028 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:18
3891 4029 #: rhodecode/templates/admin/users/user_add.mako:11
3892 4030 #: rhodecode/templates/admin/users/user_edit.mako:12
3893 #: rhodecode/templates/base/base.mako:801
4031 #: rhodecode/templates/base/base.mako:832
3894 4032 msgid "Admin"
3895 4033 msgstr ""
3896 4034
4035 #: rhodecode/model/permission.py:89
4036 msgid "Protected/No Access"
4037 msgstr ""
4038
3897 4039 #: rhodecode/model/permission.py:90
3898 msgid "Protected/No Access"
4040 msgid "Web merge"
3899 4041 msgstr ""
3900 4042
3901 4043 #: rhodecode/model/permission.py:91
3902 msgid "Web merge"
4044 msgid "Push"
3903 4045 msgstr ""
3904 4046
3905 4047 #: rhodecode/model/permission.py:92
3906 msgid "Push"
3907 msgstr ""
3908
3909 #: rhodecode/model/permission.py:93
3910 4048 msgid "Force Push"
3911 4049 msgstr ""
3912 4050
3913 #: rhodecode/model/permission.py:96 rhodecode/model/permission.py:110
3914 #: rhodecode/model/permission.py:114 rhodecode/model/permission.py:118
3915 #: rhodecode/model/permission.py:122 rhodecode/model/permission.py:126
3916 #: rhodecode/model/permission.py:130
4051 #: rhodecode/model/permission.py:95 rhodecode/model/permission.py:109
4052 #: rhodecode/model/permission.py:113 rhodecode/model/permission.py:117
4053 #: rhodecode/model/permission.py:121 rhodecode/model/permission.py:125
4054 #: rhodecode/model/permission.py:129
3917 4055 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:27
3918 4056 msgid "Disabled"
3919 4057 msgstr ""
3920 4058
4059 #: rhodecode/model/permission.py:96
4060 msgid "Allowed with manual account activation"
4061 msgstr ""
4062
3921 4063 #: rhodecode/model/permission.py:97
3922 msgid "Allowed with manual account activation"
3923 msgstr ""
3924
3925 #: rhodecode/model/permission.py:98
3926 4064 msgid "Allowed with automatic account activation"
3927 4065 msgstr ""
3928 4066
4067 #: rhodecode/model/permission.py:100
4068 msgid "Allow password recovery"
4069 msgstr ""
4070
3929 4071 #: rhodecode/model/permission.py:101
3930 msgid "Allow password recovery"
4072 msgid "Hide password recovery link"
3931 4073 msgstr ""
3932 4074
3933 4075 #: rhodecode/model/permission.py:102
3934 msgid "Hide password recovery link"
3935 msgstr ""
3936
3937 #: rhodecode/model/permission.py:103
3938 4076 msgid "Disable password recovery"
3939 4077 msgstr ""
3940 4078
3941 #: rhodecode/model/pull_request.py:90
4079 #: rhodecode/model/pull_request.py:215
3942 4080 msgid "Pull request update successful."
3943 4081 msgstr ""
3944 4082
3945 #: rhodecode/model/pull_request.py:92
4083 #: rhodecode/model/pull_request.py:217
3946 4084 msgid "Pull request update failed because of an unknown error."
3947 4085 msgstr ""
3948 4086
3949 #: rhodecode/model/pull_request.py:94
4087 #: rhodecode/model/pull_request.py:219
3950 4088 msgid "No update needed because the source and target have not changed."
3951 4089 msgstr ""
3952 4090
3953 #: rhodecode/model/pull_request.py:96
4091 #: rhodecode/model/pull_request.py:221
3954 4092 msgid "Pull request cannot be updated because the reference type is not supported for an update. Only Branch, Tag or Bookmark is allowed."
3955 4093 msgstr ""
3956 4094
3957 #: rhodecode/model/pull_request.py:99
4095 #: rhodecode/model/pull_request.py:224
3958 4096 msgid "This pull request cannot be updated because the target reference is missing."
3959 4097 msgstr ""
3960 4098
3961 #: rhodecode/model/pull_request.py:102
4099 #: rhodecode/model/pull_request.py:227
3962 4100 msgid "This pull request cannot be updated because the source reference is missing."
3963 4101 msgstr ""
3964 4102
3965 #: rhodecode/model/pull_request.py:1355
4103 #: rhodecode/model/pull_request.py:1518
3966 4104 msgid "Server-side pull request merging is disabled."
3967 4105 msgstr ""
3968 4106
3969 #: rhodecode/model/pull_request.py:1357
4107 #: rhodecode/model/pull_request.py:1521
3970 4108 msgid "This pull request is closed."
3971 4109 msgstr ""
3972 4110
3973 #: rhodecode/model/pull_request.py:1371
4111 #: rhodecode/model/pull_request.py:1535
3974 4112 msgid "Pull request merging is not supported."
3975 4113 msgstr ""
3976 4114
3977 #: rhodecode/model/pull_request.py:1390
4115 #: rhodecode/model/pull_request.py:1552
3978 4116 msgid "Target repository large files support is disabled."
3979 4117 msgstr ""
3980 4118
3981 #: rhodecode/model/pull_request.py:1393
4119 #: rhodecode/model/pull_request.py:1555
3982 4120 msgid "Source repository large files support is disabled."
3983 4121 msgstr ""
3984 4122
3985 #: rhodecode/model/pull_request.py:1571 rhodecode/model/scm.py:1004
4123 #: rhodecode/model/pull_request.py:1739 rhodecode/model/scm.py:1004
3986 4124 #: rhodecode/templates/admin/my_account/my_account.mako:32
3987 #: rhodecode/templates/base/base.mako:633
4125 #: rhodecode/templates/base/base.mako:629
3988 4126 #: rhodecode/templates/summary/components.mako:46
3989 4127 msgid "Bookmarks"
3990 4128 msgstr ""
3991 4129
3992 #: rhodecode/model/pull_request.py:1576
3993 msgid "Commit IDs"
3994 msgstr ""
3995
3996 #: rhodecode/model/pull_request.py:1579
3997 #: rhodecode/templates/summary/components.mako:22
3998 msgid "Closed Branches"
3999 msgstr ""
4000
4001 4130 #: rhodecode/model/pull_request.py:1744
4131 msgid "Commit IDs"
4132 msgstr ""
4133
4134 #: rhodecode/model/pull_request.py:1747
4135 #: rhodecode/templates/summary/components.mako:22
4136 msgid "Closed Branches"
4137 msgstr ""
4138
4139 #: rhodecode/model/pull_request.py:1929
4002 4140 msgid "WIP marker in title prevents from accidental merge."
4003 4141 msgstr ""
4004 4142
4005 #: rhodecode/model/pull_request.py:1755
4143 #: rhodecode/model/pull_request.py:1939
4006 4144 msgid "User `{}` not allowed to perform merge."
4007 4145 msgstr ""
4008 4146
4009 #: rhodecode/model/pull_request.py:1773
4147 #: rhodecode/model/pull_request.py:1957
4010 4148 msgid "Target branch `{}` changes rejected by rule {}."
4011 4149 msgstr ""
4012 4150
4013 #: rhodecode/model/pull_request.py:1787
4151 #: rhodecode/model/pull_request.py:1971
4014 4152 msgid "Pull request reviewer approval is pending."
4015 4153 msgstr ""
4016 4154
4017 #: rhodecode/model/pull_request.py:1801
4155 #: rhodecode/model/pull_request.py:1985
4018 4156 msgid "Cannot merge, {} TODO still not resolved."
4019 4157 msgstr ""
4020 4158
4021 #: rhodecode/model/pull_request.py:1804
4159 #: rhodecode/model/pull_request.py:1988
4022 4160 msgid "Cannot merge, {} TODOs still not resolved."
4023 4161 msgstr ""
4024 4162
4025 #: rhodecode/model/pull_request.py:1839
4163 #: rhodecode/model/pull_request.py:2043
4026 4164 msgid "Merge strategy: rebase"
4027 4165 msgstr ""
4028 4166
4029 #: rhodecode/model/pull_request.py:1844
4167 #: rhodecode/model/pull_request.py:2048
4030 4168 msgid "Merge strategy: explicit merge commit"
4031 4169 msgstr ""
4032 4170
4033 #: rhodecode/model/pull_request.py:1852
4171 #: rhodecode/model/pull_request.py:2056
4034 4172 msgid "Source branch will be closed after merge."
4035 4173 msgstr ""
4036 4174
4037 #: rhodecode/model/pull_request.py:1854
4175 #: rhodecode/model/pull_request.py:2058
4038 4176 msgid "Source branch will be deleted after merge."
4039 4177 msgstr ""
4040 4178
4041 4179 #: rhodecode/model/validators.py:93 rhodecode/model/validators.py:94
4042 4180 msgid "Value cannot be an empty list"
4043 4181 msgstr ""
4044 4182
4045 4183 #: rhodecode/model/validators.py:140
4046 4184 msgid "Pattern already exists"
4047 4185 msgstr ""
4048 4186
4049 4187 #: rhodecode/model/validators.py:161
4050 4188 #, python-format
4051 4189 msgid "Username \"%(username)s\" already exists"
4052 4190 msgstr ""
4053 4191
4054 4192 #: rhodecode/model/validators.py:163
4055 4193 #, python-format
4056 4194 msgid "Username \"%(username)s\" is forbidden"
4057 4195 msgstr ""
4058 4196
4059 4197 #: rhodecode/model/validators.py:165
4060 4198 #: rhodecode/model/validation_schema/schemas/user_schema.py:71
4061 4199 msgid "Username may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character or underscore"
4062 4200 msgstr ""
4063 4201
4064 4202 #: rhodecode/model/validators.py:196
4065 4203 #, python-format
4066 4204 msgid "Username %(username)s is not valid"
4067 4205 msgstr ""
4068 4206
4069 4207 #: rhodecode/model/validators.py:197
4070 4208 #, python-format
4071 4209 msgid "Username %(username)s is disabled"
4072 4210 msgstr ""
4073 4211
4074 4212 #: rhodecode/model/validators.py:222
4075 4213 msgid "Invalid user group name"
4076 4214 msgstr ""
4077 4215
4078 4216 #: rhodecode/model/validators.py:223
4079 4217 #, python-format
4080 4218 msgid "User group `%(usergroup)s` already exists"
4081 4219 msgstr ""
4082 4220
4083 4221 #: rhodecode/model/validators.py:225
4084 4222 msgid "user group name may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character"
4085 4223 msgstr ""
4086 4224
4087 4225 #: rhodecode/model/validators.py:265
4088 4226 msgid "Cannot assign this group as parent"
4089 4227 msgstr ""
4090 4228
4091 4229 #: rhodecode/model/validators.py:266
4092 4230 #, python-format
4093 4231 msgid "Group \"%(group_name)s\" already exists"
4094 4232 msgstr ""
4095 4233
4096 4234 #: rhodecode/model/validators.py:267
4097 4235 #, python-format
4098 4236 msgid "Repository with name \"%(group_name)s\" already exists"
4099 4237 msgstr ""
4100 4238
4101 4239 #: rhodecode/model/validators.py:269
4102 4240 msgid "no permission to store repository groupin this location"
4103 4241 msgstr ""
4104 4242
4105 4243 #: rhodecode/model/validators.py:271
4106 4244 msgid "no permission to store repository group in root location"
4107 4245 msgstr ""
4108 4246
4109 4247 #: rhodecode/model/validators.py:388
4110 4248 msgid "Invalid characters (non-ascii) in password"
4111 4249 msgstr ""
4112 4250
4113 4251 #: rhodecode/model/validators.py:407
4114 4252 msgid "Passwords do not match"
4115 4253 msgstr ""
4116 4254
4117 4255 #: rhodecode/model/validators.py:427
4118 4256 msgid "invalid password"
4119 4257 msgstr ""
4120 4258
4121 4259 #: rhodecode/model/validators.py:428
4122 4260 msgid "invalid user name"
4123 4261 msgstr ""
4124 4262
4125 4263 #: rhodecode/model/validators.py:429
4126 4264 msgid "Your account is disabled"
4127 4265 msgstr ""
4128 4266
4129 4267 #: rhodecode/model/validators.py:465
4130 4268 #, python-format
4131 4269 msgid "Repository name %(repo)s is disallowed"
4132 4270 msgstr ""
4133 4271
4134 4272 #: rhodecode/model/validators.py:467
4135 4273 #, python-format
4136 4274 msgid "Repository with name %(repo)s already exists"
4137 4275 msgstr ""
4138 4276
4139 4277 #: rhodecode/model/validators.py:469
4140 4278 #, python-format
4141 4279 msgid "Repository group with name \"%(repo)s\" already exists"
4142 4280 msgstr ""
4143 4281
4144 4282 #: rhodecode/model/validators.py:472
4145 4283 #, python-format
4146 4284 msgid "Repository with name %(repo)s exists in group \"%(group)s\""
4147 4285 msgstr ""
4148 4286
4149 4287 #: rhodecode/model/validators.py:474
4150 4288 #, python-format
4151 4289 msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\""
4152 4290 msgstr ""
4153 4291
4154 4292 #: rhodecode/model/validators.py:567
4155 4293 #: rhodecode/model/validation_schema/schemas/repo_schema.py:230
4156 4294 msgid "Repository name cannot end with .git"
4157 4295 msgstr ""
4158 4296
4159 4297 #: rhodecode/model/validators.py:627
4160 4298 #, python-format
4161 4299 msgid "invalid clone url for %(rtype)s repository"
4162 4300 msgstr ""
4163 4301
4164 4302 #: rhodecode/model/validators.py:628
4165 4303 #, python-format
4166 4304 msgid "Invalid clone url, provide a valid clone url starting with one of %(allowed_prefixes)s"
4167 4305 msgstr ""
4168 4306
4169 4307 #: rhodecode/model/validators.py:660
4170 4308 msgid "Fork have to be the same type as parent"
4171 4309 msgstr ""
4172 4310
4173 4311 #: rhodecode/model/validators.py:677
4174 4312 msgid "You do not have the permission to create repositories in this group."
4175 4313 msgstr ""
4176 4314
4177 4315 #: rhodecode/model/validators.py:680
4178 4316 #: rhodecode/model/validation_schema/schemas/repo_schema.py:136
4179 4317 msgid "You do not have the permission to store repositories in the root location."
4180 4318 msgstr ""
4181 4319
4182 4320 #: rhodecode/model/validators.py:740
4183 4321 msgid "This username or user group name is not valid"
4184 4322 msgstr ""
4185 4323
4186 4324 #: rhodecode/model/validators.py:853
4187 4325 msgid "This is not a valid path"
4188 4326 msgstr ""
4189 4327
4190 4328 #: rhodecode/model/validators.py:871
4191 4329 #: rhodecode/model/validation_schema/schemas/user_schema.py:144
4192 4330 #: rhodecode/model/validation_schema/schemas/user_schema.py:148
4193 4331 msgid "This e-mail address is already taken"
4194 4332 msgstr ""
4195 4333
4196 4334 #: rhodecode/model/validators.py:893
4197 4335 #, python-format
4198 4336 msgid "e-mail \"%(email)s\" does not exist."
4199 4337 msgstr ""
4200 4338
4201 4339 #: rhodecode/model/validators.py:914
4202 4340 #, python-format
4203 4341 msgid "Revisions %(revs)s are already part of pull request or have set status"
4204 4342 msgstr ""
4205 4343
4206 4344 #: rhodecode/model/validators.py:947
4207 4345 #: rhodecode/model/validation_schema/validators.py:41
4208 4346 #: rhodecode/model/validation_schema/validators.py:54
4209 4347 msgid "Please enter a valid IPv4 or IpV6 address"
4210 4348 msgstr ""
4211 4349
4212 4350 #: rhodecode/model/validators.py:948
4213 4351 #, python-format
4214 4352 msgid "The network size (bits) must be within the range of 0-32 (not %(bits)r)"
4215 4353 msgstr ""
4216 4354
4217 4355 #: rhodecode/model/validators.py:976
4218 4356 msgid "Key name can only consist of letters, underscore, dash or numbers"
4219 4357 msgstr ""
4220 4358
4221 4359 #: rhodecode/model/validators.py:993
4222 4360 #, python-format
4223 4361 msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name"
4224 4362 msgstr ""
4225 4363
4226 4364 #: rhodecode/model/validators.py:996
4227 4365 #, python-format
4228 4366 msgid "The plugin \"%(plugin_id)s\" is missing an includeme function."
4229 4367 msgstr ""
4230 4368
4231 4369 #: rhodecode/model/validators.py:999
4232 4370 #, python-format
4233 4371 msgid "Can not load plugin \"%(plugin_id)s\""
4234 4372 msgstr ""
4235 4373
4236 4374 #: rhodecode/model/validators.py:1001
4237 4375 #, python-format
4238 4376 msgid "No plugin available with ID \"%(plugin_id)s\""
4239 4377 msgstr ""
4240 4378
4241 4379 #: rhodecode/model/validators.py:1069
4242 4380 msgid "Url must start with http or /"
4243 4381 msgstr ""
4244 4382
4245 4383 #: rhodecode/model/validation_schema/validators.py:62
4246 4384 msgid "Invalid glob pattern"
4247 4385 msgstr ""
4248 4386
4249 4387 #: rhodecode/model/validation_schema/validators.py:71
4250 4388 msgid "Name must start with a letter or number. Got `{}`"
4251 4389 msgstr ""
4252 4390
4253 4391 #: rhodecode/model/validation_schema/validators.py:142
4254 4392 msgid "invalid clone url for {repo_type} repository"
4255 4393 msgstr ""
4256 4394
4257 4395 #: rhodecode/model/validation_schema/validators.py:151
4258 4396 msgid "Please enter a valid json object"
4259 4397 msgstr ""
4260 4398
4261 4399 #: rhodecode/model/validation_schema/schemas/comment_schema.py:42
4262 4400 #: rhodecode/model/validation_schema/schemas/gist_schema.py:89
4263 4401 msgid "Gist with name {} already exists"
4264 4402 msgstr ""
4265 4403
4266 4404 #: rhodecode/model/validation_schema/schemas/comment_schema.py:48
4267 4405 #: rhodecode/model/validation_schema/schemas/gist_schema.py:95
4268 4406 msgid "Filename {} cannot be inside a directory"
4269 4407 msgstr ""
4270 4408
4271 4409 #: rhodecode/model/validation_schema/schemas/gist_schema.py:132
4272 4410 msgid "Duplicated value for filename found: `{}`"
4273 4411 msgstr ""
4274 4412
4275 4413 #: rhodecode/model/validation_schema/schemas/integration_schema.py:36
4276 4414 msgid "Pick a scope:"
4277 4415 msgstr ""
4278 4416
4279 4417 #: rhodecode/model/validation_schema/schemas/integration_schema.py:39
4280 4418 msgid "Global (all repositories)"
4281 4419 msgstr ""
4282 4420
4283 4421 #: rhodecode/model/validation_schema/schemas/integration_schema.py:40
4284 4422 msgid "Top level repositories only"
4285 4423 msgstr ""
4286 4424
4287 4425 #: rhodecode/model/validation_schema/schemas/integration_schema.py:79
4288 4426 msgid "Only repo admins can create integrations"
4289 4427 msgstr ""
4290 4428
4291 4429 #: rhodecode/model/validation_schema/schemas/integration_schema.py:86
4292 4430 msgid "Only repogroup admins can create integrations"
4293 4431 msgstr ""
4294 4432
4295 4433 #: rhodecode/model/validation_schema/schemas/integration_schema.py:91
4296 4434 msgid "Only superadmins can create global integrations"
4297 4435 msgstr ""
4298 4436
4299 4437 #: rhodecode/model/validation_schema/schemas/integration_schema.py:181
4300 4438 msgid "Scope of the integration. Recursive means the integration runs on all repos of that group and children recursively."
4301 4439 msgstr ""
4302 4440
4303 4441 #: rhodecode/model/validation_schema/schemas/integration_schema.py:184
4304 4442 msgid "Integration scope"
4305 4443 msgstr ""
4306 4444
4307 4445 #: rhodecode/model/validation_schema/schemas/integration_schema.py:214
4308 4446 msgid "General integration options"
4309 4447 msgstr ""
4310 4448
4311 4449 #: rhodecode/model/validation_schema/schemas/integration_schema.py:217
4312 4450 msgid "{integration_type} settings"
4313 4451 msgstr ""
4314 4452
4315 4453 #: rhodecode/model/validation_schema/schemas/repo_group_schema.py:52
4316 4454 #: rhodecode/model/validation_schema/schemas/repo_group_schema.py:56
4317 4455 msgid "Parent repository group `{}` does not exist"
4318 4456 msgstr ""
4319 4457
4320 4458 #: rhodecode/model/validation_schema/schemas/repo_group_schema.py:58
4321 4459 msgid "You do not have the permission to store repository groups in the root location."
4322 4460 msgstr ""
4323 4461
4324 4462 #: rhodecode/model/validation_schema/schemas/repo_group_schema.py:118
4325 4463 msgid "Repo group owner with id `{}` does not exists"
4326 4464 msgstr ""
4327 4465
4328 4466 #: rhodecode/model/validation_schema/schemas/repo_group_schema.py:136
4329 4467 #: rhodecode/model/validation_schema/schemas/repo_schema.py:215
4330 4468 msgid "Repository with name `{}` already exists"
4331 4469 msgstr ""
4332 4470
4333 4471 #: rhodecode/model/validation_schema/schemas/repo_group_schema.py:141
4334 4472 #: rhodecode/model/validation_schema/schemas/repo_schema.py:220
4335 4473 msgid "Repository group with name `{}` already exists"
4336 4474 msgstr ""
4337 4475
4338 4476 #: rhodecode/model/validation_schema/schemas/repo_schema.py:60
4339 4477 msgid "Repo owner with id `{}` does not exists"
4340 4478 msgstr ""
4341 4479
4342 4480 #: rhodecode/model/validation_schema/schemas/repo_schema.py:102
4343 4481 msgid "Fork with id `{}` does not exists"
4344 4482 msgstr ""
4345 4483
4346 4484 #: rhodecode/model/validation_schema/schemas/repo_schema.py:105
4347 4485 msgid "Cannot set fork of parameter of this repository to itself"
4348 4486 msgstr ""
4349 4487
4350 4488 #: rhodecode/model/validation_schema/schemas/repo_schema.py:130
4351 4489 #: rhodecode/model/validation_schema/schemas/repo_schema.py:134
4352 4490 msgid "Repository group `{}` does not exist"
4353 4491 msgstr ""
4354 4492
4355 4493 #: rhodecode/model/validation_schema/schemas/user_group_schema.py:32
4356 4494 msgid "Allowed in name are letters, numbers, and `-`, `_`, `.` Name must start with a letter or number. Got `{}`"
4357 4495 msgstr ""
4358 4496
4359 4497 #: rhodecode/model/validation_schema/schemas/user_group_schema.py:48
4360 4498 msgid "User group owner with id `{}` does not exists"
4361 4499 msgstr ""
4362 4500
4363 4501 #: rhodecode/model/validation_schema/schemas/user_schema.py:39
4364 4502 msgid "Password is incorrect"
4365 4503 msgstr ""
4366 4504
4367 4505 #: rhodecode/model/validation_schema/schemas/user_schema.py:62
4368 4506 msgid "New password must be different to old password"
4369 4507 msgstr ""
4370 4508
4371 4509 #: rhodecode/model/validation_schema/schemas/user_schema.py:183
4372 4510 msgid "Additional emails can be specified at <a href=\"{}\">extra emails</a> page."
4373 4511 msgstr ""
4374 4512
4375 #: rhodecode/public/js/scripts.js:19
4376 msgid ": , "
4377 msgstr ""
4378
4379 #: rhodecode/public/js/scripts.js:24109 rhodecode/public/js/scripts.min.js:1
4380 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:39
4513 #: rhodecode/public/js/scripts.js:20588 rhodecode/public/js/scripts.min.js:1
4514 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:51
4381 4515 #: rhodecode/public/js/src/plugins/jquery.autocomplete.js:87
4382 4516 msgid "No results"
4383 4517 msgstr ""
4384 4518
4385 #: rhodecode/public/js/scripts.js:25569 rhodecode/public/js/scripts.min.js:1
4386 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:130
4519 #: rhodecode/public/js/scripts.js:22050 rhodecode/public/js/scripts.min.js:1
4520 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:144
4387 4521 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:109
4388 4522 msgid "{0} year"
4389 4523 msgstr ""
4390 4524
4391 #: rhodecode/public/js/scripts.js:25570 rhodecode/public/js/scripts.min.js:1
4392 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:120
4525 #: rhodecode/public/js/scripts.js:22051 rhodecode/public/js/scripts.min.js:1
4526 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:132
4393 4527 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:110
4394 4528 msgid "{0} month"
4395 4529 msgstr ""
4396 4530
4397 #: rhodecode/public/js/scripts.js:25571 rhodecode/public/js/scripts.min.js:1
4398 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:115
4531 #: rhodecode/public/js/scripts.js:22052 rhodecode/public/js/scripts.min.js:1
4532 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:127
4399 4533 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:111
4400 4534 msgid "{0} day"
4401 4535 msgstr ""
4402 4536
4403 #: rhodecode/public/js/scripts.js:25572 rhodecode/public/js/scripts.min.js:1
4404 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:117
4537 #: rhodecode/public/js/scripts.js:22053 rhodecode/public/js/scripts.min.js:1
4538 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:129
4405 4539 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:112
4406 4540 msgid "{0} hour"
4407 4541 msgstr ""
4408 4542
4409 #: rhodecode/public/js/scripts.js:25573 rhodecode/public/js/scripts.min.js:1
4410 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:119
4543 #: rhodecode/public/js/scripts.js:22054 rhodecode/public/js/scripts.min.js:1
4544 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:131
4411 4545 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:113
4412 4546 msgid "{0} min"
4413 4547 msgstr ""
4414 4548
4415 #: rhodecode/public/js/scripts.js:25574 rhodecode/public/js/scripts.min.js:1
4416 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:127
4549 #: rhodecode/public/js/scripts.js:22055 rhodecode/public/js/scripts.min.js:1
4550 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:141
4417 4551 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:114
4418 4552 msgid "{0} sec"
4419 4553 msgstr ""
4420 4554
4421 #: rhodecode/public/js/scripts.js:25594 rhodecode/public/js/scripts.min.js:1
4422 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:96
4555 #: rhodecode/public/js/scripts.js:22075 rhodecode/public/js/scripts.min.js:1
4556 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:108
4423 4557 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:134
4424 4558 msgid "in {0}"
4425 4559 msgstr ""
4426 4560
4427 #: rhodecode/public/js/scripts.js:25602 rhodecode/public/js/scripts.min.js:1
4428 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:112
4561 #: rhodecode/public/js/scripts.js:22083 rhodecode/public/js/scripts.min.js:1
4562 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:124
4429 4563 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:142
4430 4564 msgid "{0} ago"
4431 4565 msgstr ""
4432 4566
4433 #: rhodecode/public/js/scripts.js:25614 rhodecode/public/js/scripts.min.js:1
4434 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:132
4567 #: rhodecode/public/js/scripts.js:22095 rhodecode/public/js/scripts.min.js:1
4568 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:146
4435 4569 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:154
4436 4570 msgid "{0}, {1} ago"
4437 4571 msgstr ""
4438 4572
4439 #: rhodecode/public/js/scripts.js:25616 rhodecode/public/js/scripts.min.js:1
4440 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:98
4573 #: rhodecode/public/js/scripts.js:22097 rhodecode/public/js/scripts.min.js:1
4574 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:110
4441 4575 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:156
4442 4576 msgid "in {0}, {1}"
4443 4577 msgstr ""
4444 4578
4445 #: rhodecode/public/js/scripts.js:25620 rhodecode/public/js/scripts.min.js:1
4446 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:113
4579 #: rhodecode/public/js/scripts.js:22101 rhodecode/public/js/scripts.min.js:1
4580 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:125
4447 4581 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:160
4448 4582 msgid "{0} and {1}"
4449 4583 msgstr ""
4450 4584
4451 #: rhodecode/public/js/scripts.js:25622 rhodecode/public/js/scripts.min.js:1
4452 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:114
4585 #: rhodecode/public/js/scripts.js:22103 rhodecode/public/js/scripts.min.js:1
4586 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:126
4453 4587 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:162
4454 4588 msgid "{0} and {1} ago"
4455 4589 msgstr ""
4456 4590
4457 #: rhodecode/public/js/scripts.js:25624 rhodecode/public/js/scripts.min.js:1
4458 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:97
4591 #: rhodecode/public/js/scripts.js:22105 rhodecode/public/js/scripts.min.js:1
4592 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:109
4459 4593 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:164
4460 4594 msgid "in {0} and {1}"
4461 4595 msgstr ""
4462 4596
4463 #: rhodecode/public/js/scripts.js:40622 rhodecode/public/js/scripts.min.js:1
4464 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:29
4597 #: rhodecode/public/js/scripts.js:37103 rhodecode/public/js/scripts.min.js:1
4598 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:38
4465 4599 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:4
4466 4600 msgid "Loading more results..."
4467 4601 msgstr ""
4468 4602
4469 #: rhodecode/public/js/scripts.js:40625 rhodecode/public/js/scripts.min.js:1
4470 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:55
4603 #: rhodecode/public/js/scripts.js:37106 rhodecode/public/js/scripts.min.js:1
4604 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:67
4471 4605 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:7
4472 4606 msgid "Searching..."
4473 4607 msgstr ""
4474 4608
4475 #: rhodecode/public/js/scripts.js:40628 rhodecode/public/js/scripts.min.js:1
4476 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:34
4609 #: rhodecode/public/js/scripts.js:37109 rhodecode/public/js/scripts.min.js:1
4610 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:44
4477 4611 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:10
4478 4612 msgid "No matches found"
4479 4613 msgstr ""
4480 4614
4481 #: rhodecode/public/js/scripts.js:40631 rhodecode/public/js/scripts.min.js:1
4482 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:28
4615 #: rhodecode/public/js/scripts.js:37112 rhodecode/public/js/scripts.min.js:1
4616 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:37
4483 4617 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:13
4484 4618 msgid "Loading failed"
4485 4619 msgstr ""
4486 4620
4487 #: rhodecode/public/js/scripts.js:40635 rhodecode/public/js/scripts.min.js:1
4488 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:46
4621 #: rhodecode/public/js/scripts.js:37116 rhodecode/public/js/scripts.min.js:1
4622 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:58
4489 4623 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:17
4490 4624 msgid "One result is available, press enter to select it."
4491 4625 msgstr ""
4492 4626
4493 #: rhodecode/public/js/scripts.js:40637 rhodecode/public/js/scripts.min.js:1
4494 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:126
4627 #: rhodecode/public/js/scripts.js:37118 rhodecode/public/js/scripts.min.js:1
4628 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:140
4495 4629 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:19
4496 4630 msgid "{0} results are available, use up and down arrow keys to navigate."
4497 4631 msgstr ""
4498 4632
4499 #: rhodecode/public/js/scripts.js:40642 rhodecode/public/js/scripts.min.js:1
4500 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:51
4633 #: rhodecode/public/js/scripts.js:37123 rhodecode/public/js/scripts.min.js:1
4634 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:63
4501 4635 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:24
4502 4636 msgid "Please enter {0} or more character"
4503 4637 msgstr ""
4504 4638
4505 #: rhodecode/public/js/scripts.js:40644 rhodecode/public/js/scripts.min.js:1
4506 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:52
4639 #: rhodecode/public/js/scripts.js:37125 rhodecode/public/js/scripts.min.js:1
4640 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:64
4507 4641 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:26
4508 4642 msgid "Please enter {0} or more characters"
4509 4643 msgstr ""
4510 4644
4511 #: rhodecode/public/js/scripts.js:40649 rhodecode/public/js/scripts.min.js:1
4512 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:49
4645 #: rhodecode/public/js/scripts.js:37130 rhodecode/public/js/scripts.min.js:1
4646 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:61
4513 4647 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:31
4514 4648 msgid "Please delete {0} character"
4515 4649 msgstr ""
4516 4650
4517 #: rhodecode/public/js/scripts.js:40651 rhodecode/public/js/scripts.min.js:1
4518 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:50
4651 #: rhodecode/public/js/scripts.js:37132 rhodecode/public/js/scripts.min.js:1
4652 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:62
4519 4653 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:33
4520 4654 msgid "Please delete {0} characters"
4521 4655 msgstr ""
4522 4656
4523 #: rhodecode/public/js/scripts.js:40655 rhodecode/public/js/scripts.min.js:1
4524 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:86
4657 #: rhodecode/public/js/scripts.js:37136 rhodecode/public/js/scripts.min.js:1
4658 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:98
4525 4659 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:37
4526 4660 msgid "You can only select {0} item"
4527 4661 msgstr ""
4528 4662
4529 #: rhodecode/public/js/scripts.js:40657 rhodecode/public/js/scripts.min.js:1
4530 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:87
4663 #: rhodecode/public/js/scripts.js:37138 rhodecode/public/js/scripts.min.js:1
4664 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:99
4531 4665 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:39
4532 4666 msgid "You can only select {0} items"
4533 4667 msgstr ""
4534 4668
4535 #: rhodecode/public/js/scripts.js:41595 rhodecode/public/js/scripts.min.js:1
4536 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:104
4669 #: rhodecode/public/js/scripts.js:37780 rhodecode/public/js/scripts.min.js:1
4670 #: rhodecode/public/js/src/rhodecode/utils/ajax.js:136
4671 msgid "Ajax Request Error"
4672 msgstr ""
4673
4674 #: rhodecode/public/js/scripts.js:38178 rhodecode/public/js/scripts.min.js:1
4675 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:116
4537 4676 #: rhodecode/public/js/src/rhodecode/changelog.js:35
4538 4677 msgid "showing {0} out of {1} commit"
4539 4678 msgstr ""
4540 4679
4541 #: rhodecode/public/js/scripts.js:41597 rhodecode/public/js/scripts.min.js:1
4542 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:105
4680 #: rhodecode/public/js/scripts.js:38180 rhodecode/public/js/scripts.min.js:1
4681 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:117
4543 4682 #: rhodecode/public/js/src/rhodecode/changelog.js:37
4544 4683 msgid "showing {0} out of {1} commits"
4545 4684 msgstr ""
4546 4685
4547 #: rhodecode/public/js/scripts.js:42136 rhodecode/public/js/scripts.min.js:1
4548 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:58
4686 #: rhodecode/public/js/scripts.js:38718 rhodecode/public/js/scripts.min.js:1
4687 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:70
4549 4688 #: rhodecode/public/js/src/rhodecode/codemirror.js:363
4550 4689 msgid "Set status to Approved"
4551 4690 msgstr ""
4552 4691
4553 #: rhodecode/public/js/scripts.js:42156 rhodecode/public/js/scripts.min.js:1
4554 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:59
4692 #: rhodecode/public/js/scripts.js:38738 rhodecode/public/js/scripts.min.js:1
4693 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:71
4555 4694 #: rhodecode/public/js/src/rhodecode/codemirror.js:383
4556 4695 msgid "Set status to Rejected"
4557 4696 msgstr ""
4558 4697
4559 #: rhodecode/public/js/scripts.js:42175 rhodecode/public/js/scripts.min.js:1
4560 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:76
4698 #: rhodecode/public/js/scripts.js:38757 rhodecode/public/js/scripts.min.js:1
4699 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:88
4561 4700 #: rhodecode/public/js/src/rhodecode/codemirror.js:402
4562 4701 msgid "TODO comment"
4563 4702 msgstr ""
4564 4703
4565 #: rhodecode/public/js/scripts.js:42195 rhodecode/public/js/scripts.min.js:1
4566 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:45
4704 #: rhodecode/public/js/scripts.js:38777 rhodecode/public/js/scripts.min.js:1
4705 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:57
4567 4706 #: rhodecode/public/js/src/rhodecode/codemirror.js:422
4568 4707 msgid "Note Comment"
4569 4708 msgstr ""
4570 4709
4571 #: rhodecode/public/js/scripts.js:42496 rhodecode/public/js/scripts.js:42850
4710 #: rhodecode/public/js/scripts.js:39078 rhodecode/public/js/scripts.js:39432
4572 4711 #: rhodecode/public/js/scripts.min.js:1
4573 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:70
4712 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:82
4574 4713 #: rhodecode/public/js/src/rhodecode/codemirror.js:723
4575 4714 #: rhodecode/public/js/src/rhodecode/comments.js:233
4576 4715 msgid "Status Review"
4577 4716 msgstr ""
4578 4717
4579 #: rhodecode/public/js/scripts.js:42511 rhodecode/public/js/scripts.js:42865
4718 #: rhodecode/public/js/scripts.js:39093 rhodecode/public/js/scripts.js:39447
4580 4719 #: rhodecode/public/js/scripts.min.js:1
4581 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:13
4720 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:17
4582 4721 #: rhodecode/public/js/src/rhodecode/codemirror.js:738
4583 4722 #: rhodecode/public/js/src/rhodecode/comments.js:248
4584 4723 msgid "Comment text will be set automatically based on currently selected status ({0}) ..."
4585 4724 msgstr ""
4586 4725
4587 #: rhodecode/public/js/scripts.js:42592 rhodecode/public/js/scripts.js:43061
4588 #: rhodecode/public/js/scripts.js:44066 rhodecode/public/js/scripts.min.js:1
4589 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:27
4726 #: rhodecode/public/js/scripts.js:39174 rhodecode/public/js/scripts.js:39642
4727 #: rhodecode/public/js/scripts.js:40669 rhodecode/public/js/scripts.min.js:1
4728 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:36
4590 4729 #: rhodecode/public/js/src/rhodecode/codemirror.js:819
4591 #: rhodecode/public/js/src/rhodecode/comments.js:444
4592 #: rhodecode/public/js/src/rhodecode/files.js:495
4593 #: rhodecode/templates/files/files_browser_tree.mako:55
4730 #: rhodecode/public/js/src/rhodecode/comments.js:443
4731 #: rhodecode/public/js/src/rhodecode/files.js:499
4732 #: rhodecode/templates/files/files_browser_tree.mako:54
4594 4733 msgid "Loading ..."
4595 4734 msgstr ""
4596 4735
4597 #: rhodecode/public/js/scripts.js:42766 rhodecode/public/js/scripts.min.js:1
4598 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:103
4736 #: rhodecode/public/js/scripts.js:39348 rhodecode/public/js/scripts.min.js:1
4737 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:115
4599 4738 #: rhodecode/public/js/src/rhodecode/comments.js:149
4600 4739 msgid "resolve comment"
4601 4740 msgstr ""
4602 4741
4603 #: rhodecode/public/js/scripts.js:43010 rhodecode/public/js/scripts.min.js:1
4604 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:73
4605 #: rhodecode/public/js/src/rhodecode/comments.js:393
4742 #: rhodecode/public/js/scripts.js:39591 rhodecode/public/js/scripts.min.js:1
4743 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:85
4744 #: rhodecode/public/js/src/rhodecode/comments.js:392
4606 4745 msgid "Submitting..."
4607 4746 msgstr ""
4608 4747
4609 #: rhodecode/public/js/scripts.js:43175 rhodecode/public/js/scripts.min.js:1
4610 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:16
4611 #: rhodecode/public/js/src/rhodecode/comments.js:560
4612 msgid "Delete this comment?"
4613 msgstr ""
4614
4615 #: rhodecode/public/js/scripts.js:43249 rhodecode/public/js/scripts.min.js:1
4616 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:25
4617 msgid "Leave a comment, or click resolve button to resolve TODO comment #{0}"
4618 msgstr ""
4619
4620 #: rhodecode/public/js/scripts.js:43415 rhodecode/public/js/scripts.min.js:1
4621 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:24
4622 #: rhodecode/public/js/src/rhodecode/comments.js:800
4748 #: rhodecode/public/js/scripts.js:39794 rhodecode/public/js/scripts.min.js:1
4749 #: rhodecode/public/js/src/rhodecode/comments.js:595
4750 msgid "Yes, delete comment #{0}!"
4751 msgstr ""
4752
4753 #: rhodecode/public/js/scripts.js:39849 rhodecode/public/js/scripts.min.js:1
4754 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:34
4755 #: rhodecode/public/js/src/rhodecode/comments.js:650
4756 msgid "Leave a resolution comment, or click resolve button to resolve TODO comment #{0}"
4757 msgstr ""
4758
4759 #: rhodecode/public/js/scripts.js:40015 rhodecode/public/js/scripts.min.js:1
4760 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:32
4761 #: rhodecode/public/js/src/rhodecode/comments.js:816
4623 4762 msgid "Leave a comment on line {0}."
4624 4763 msgstr ""
4625 4764
4626 #: rhodecode/public/js/scripts.js:43541 rhodecode/public/js/scripts.min.js:1
4627 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:77
4628 #: rhodecode/public/js/src/rhodecode/comments.js:926
4765 #: rhodecode/public/js/scripts.js:40140 rhodecode/public/js/scripts.min.js:1
4766 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:89
4767 #: rhodecode/public/js/src/rhodecode/comments.js:941
4629 4768 msgid "TODO from comment {0} was fixed."
4630 4769 msgstr ""
4631 4770
4632 #: rhodecode/public/js/scripts.js:43819 rhodecode/public/js/scripts.min.js:1
4633 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:107
4771 #: rhodecode/public/js/scripts.js:40418 rhodecode/public/js/scripts.min.js:1
4772 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:119
4634 4773 #: rhodecode/public/js/src/rhodecode/files.js:248
4635 4774 msgid "truncated result"
4636 4775 msgstr ""
4637 4776
4638 #: rhodecode/public/js/scripts.js:43821 rhodecode/public/js/scripts.min.js:1
4639 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:108
4777 #: rhodecode/public/js/scripts.js:40420 rhodecode/public/js/scripts.min.js:1
4778 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:120
4640 4779 #: rhodecode/public/js/src/rhodecode/files.js:250
4641 4780 msgid "truncated results"
4642 4781 msgstr ""
4643 4782
4644 #: rhodecode/public/js/scripts.js:43830 rhodecode/public/js/scripts.min.js:1
4645 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:35
4783 #: rhodecode/public/js/scripts.js:40429 rhodecode/public/js/scripts.min.js:1
4784 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:45
4646 4785 #: rhodecode/public/js/src/rhodecode/files.js:259
4647 4786 msgid "No matching files"
4648 4787 msgstr ""
4649 4788
4650 #: rhodecode/public/js/scripts.js:43888 rhodecode/public/js/scripts.min.js:1
4651 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:56
4789 #: rhodecode/public/js/scripts.js:40487 rhodecode/public/js/scripts.min.js:1
4790 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:68
4652 4791 #: rhodecode/public/js/src/rhodecode/files.js:317
4653 4792 msgid "Selection link"
4654 4793 msgstr ""
4655 4794
4656 #: rhodecode/public/js/scripts.js:43981 rhodecode/public/js/scripts.min.js:1
4795 #: rhodecode/public/js/scripts.js:40584 rhodecode/public/js/scripts.min.js:1
4657 4796 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:5
4658 #: rhodecode/public/js/src/rhodecode/files.js:410
4797 #: rhodecode/public/js/src/rhodecode/files.js:414
4659 4798 msgid "All Authors"
4660 4799 msgstr ""
4661 4800
4662 #: rhodecode/public/js/scripts.js:44117 rhodecode/public/js/scripts.min.js:1
4663 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:72
4801 #: rhodecode/public/js/scripts.js:40734 rhodecode/public/js/scripts.js:40737
4802 #: rhodecode/public/js/scripts.min.js:1
4803 #: rhodecode/public/js/src/rhodecode/files.js:564
4804 #: rhodecode/public/js/src/rhodecode/files.js:567
4805 msgid "File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version."
4806 msgstr ""
4807
4808 #: rhodecode/public/js/scripts.js:40740 rhodecode/public/js/scripts.min.js:1
4809 #: rhodecode/public/js/src/rhodecode/files.js:570
4810 msgid "There is an existing path `{0}` at this commit."
4811 msgstr ""
4812
4813 #: rhodecode/public/js/scripts.js:40743 rhodecode/public/js/scripts.min.js:1
4814 #: rhodecode/public/js/src/rhodecode/files.js:573
4815 msgid "There is a later version of file tree available. Click {0} to create a file at the latest tree."
4816 msgstr ""
4817
4818 #: rhodecode/public/js/scripts.js:40797 rhodecode/public/js/scripts.min.js:1
4819 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:84
4664 4820 #: rhodecode/public/js/src/rhodecode/followers.js:26
4665 4821 msgid "Stopped watching this repository"
4666 4822 msgstr ""
4667 4823
4668 #: rhodecode/public/js/scripts.js:44118 rhodecode/public/js/scripts.min.js:1
4669 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:85
4824 #: rhodecode/public/js/scripts.js:40798 rhodecode/public/js/scripts.min.js:1
4825 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:97
4670 4826 #: rhodecode/public/js/src/rhodecode/followers.js:27
4671 4827 #: rhodecode/templates/base/base.mako:301
4672 4828 msgid "Watch"
4673 4829 msgstr ""
4674 4830
4675 #: rhodecode/public/js/scripts.js:44121 rhodecode/public/js/scripts.min.js:1
4676 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:69
4831 #: rhodecode/public/js/scripts.js:40801 rhodecode/public/js/scripts.min.js:1
4832 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:81
4677 4833 #: rhodecode/public/js/src/rhodecode/followers.js:30
4678 4834 msgid "Started watching this repository"
4679 4835 msgstr ""
4680 4836
4681 #: rhodecode/public/js/scripts.js:44122 rhodecode/public/js/scripts.min.js:1
4682 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:81
4837 #: rhodecode/public/js/scripts.js:40802 rhodecode/public/js/scripts.min.js:1
4838 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:93
4683 4839 #: rhodecode/public/js/src/rhodecode/followers.js:31
4684 4840 #: rhodecode/templates/base/base.mako:299
4685 4841 msgid "Unwatch"
4686 4842 msgstr ""
4687 4843
4688 #: rhodecode/public/js/scripts.js:44495 rhodecode/public/js/scripts.min.js:1
4844 #: rhodecode/public/js/scripts.js:41182 rhodecode/public/js/scripts.min.js:1
4689 4845 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:7
4690 #: rhodecode/public/js/src/rhodecode/pullrequests.js:135
4846 #: rhodecode/public/js/src/rhodecode/pullrequests.js:141
4691 4847 msgid "All reviewers must vote."
4692 4848 msgstr ""
4693 4849
4694 #: rhodecode/public/js/scripts.js:44504 rhodecode/public/js/scripts.min.js:1
4850 #: rhodecode/public/js/scripts.js:41191 rhodecode/public/js/scripts.min.js:1
4695 4851 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:6
4696 #: rhodecode/public/js/src/rhodecode/pullrequests.js:144
4852 #: rhodecode/public/js/src/rhodecode/pullrequests.js:150
4697 4853 msgid "All individual reviewers must vote."
4698 4854 msgstr ""
4699 4855
4700 #: rhodecode/public/js/scripts.js:44509 rhodecode/public/js/scripts.min.js:1
4701 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:8
4702 #: rhodecode/public/js/src/rhodecode/pullrequests.js:149
4703 msgid "At least {0} reviewer must vote."
4704 msgstr ""
4705
4706 #: rhodecode/public/js/scripts.js:44515 rhodecode/public/js/scripts.min.js:1
4856 #: rhodecode/public/js/scripts.js:41196 rhodecode/public/js/scripts.min.js:1
4707 4857 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:9
4708 4858 #: rhodecode/public/js/src/rhodecode/pullrequests.js:155
4859 msgid "At least {0} reviewer must vote."
4860 msgstr ""
4861
4862 #: rhodecode/public/js/scripts.js:41202 rhodecode/public/js/scripts.min.js:1
4863 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:10
4864 #: rhodecode/public/js/src/rhodecode/pullrequests.js:161
4709 4865 msgid "At least {0} reviewers must vote."
4710 4866 msgstr ""
4711 4867
4712 #: rhodecode/public/js/scripts.js:44531 rhodecode/public/js/scripts.min.js:1
4713 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:53
4714 #: rhodecode/public/js/src/rhodecode/pullrequests.js:171
4868 #: rhodecode/public/js/scripts.js:41218 rhodecode/public/js/scripts.min.js:1
4869 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:65
4870 #: rhodecode/public/js/src/rhodecode/pullrequests.js:177
4715 4871 msgid "Reviewers picked from source code changes."
4716 4872 msgstr ""
4717 4873
4718 #: rhodecode/public/js/scripts.js:44538 rhodecode/public/js/scripts.min.js:1
4874 #: rhodecode/public/js/scripts.js:41225 rhodecode/public/js/scripts.min.js:1
4719 4875 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:4
4720 #: rhodecode/public/js/src/rhodecode/pullrequests.js:178
4876 #: rhodecode/public/js/src/rhodecode/pullrequests.js:184
4721 4877 msgid "Adding new reviewers is forbidden."
4722 4878 msgstr ""
4723 4879
4724 #: rhodecode/public/js/scripts.js:44545 rhodecode/public/js/scripts.min.js:1
4725 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:10
4726 #: rhodecode/public/js/src/rhodecode/pullrequests.js:185
4880 #: rhodecode/public/js/scripts.js:41232 rhodecode/public/js/scripts.min.js:1
4881 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:11
4882 #: rhodecode/public/js/src/rhodecode/pullrequests.js:191
4727 4883 msgid "Author is not allowed to be a reviewer."
4728 4884 msgstr ""
4729 4885
4730 #: rhodecode/public/js/scripts.js:44559 rhodecode/public/js/scripts.min.js:1
4731 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:14
4732 #: rhodecode/public/js/src/rhodecode/pullrequests.js:199
4886 #: rhodecode/public/js/scripts.js:41246 rhodecode/public/js/scripts.min.js:1
4887 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:18
4888 #: rhodecode/public/js/src/rhodecode/pullrequests.js:205
4733 4889 msgid "Commit Authors are not allowed to be a reviewer."
4734 4890 msgstr ""
4735 4891
4736 #: rhodecode/public/js/scripts.js:44667 rhodecode/public/js/scripts.min.js:1
4737 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:84
4738 #: rhodecode/public/js/src/rhodecode/pullrequests.js:307
4892 #: rhodecode/public/js/scripts.js:41268 rhodecode/public/js/scripts.min.js:1
4893 #: rhodecode/public/js/src/rhodecode/pullrequests.js:227
4894 msgid "Loading diff ..."
4895 msgstr ""
4896
4897 #: rhodecode/public/js/scripts.js:41307 rhodecode/public/js/scripts.min.js:1
4898 #: rhodecode/public/js/src/rhodecode/pullrequests.js:266
4899 msgid "no commits"
4900 msgstr ""
4901
4902 #: rhodecode/public/js/scripts.js:41378 rhodecode/public/js/scripts.min.js:1
4903 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:96
4904 #: rhodecode/public/js/src/rhodecode/pullrequests.js:337
4739 4905 msgid "User `{0}` not allowed to be a reviewer"
4740 4906 msgstr ""
4741 4907
4742 #: rhodecode/public/js/scripts.js:44673 rhodecode/public/js/scripts.min.js:1
4743 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:83
4744 #: rhodecode/public/js/src/rhodecode/pullrequests.js:313
4908 #: rhodecode/public/js/scripts.js:41384 rhodecode/public/js/scripts.min.js:1
4909 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:95
4910 #: rhodecode/public/js/src/rhodecode/pullrequests.js:343
4745 4911 msgid "User `{0}` already in reviewers"
4746 4912 msgstr ""
4747 4913
4748 #: rhodecode/public/js/scripts.js:44773 rhodecode/public/js/scripts.min.js:1
4749 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:89
4750 #: rhodecode/public/js/src/rhodecode/pullrequests.js:413
4914 #: rhodecode/public/js/scripts.js:41487 rhodecode/public/js/scripts.min.js:1
4915 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:101
4916 #: rhodecode/public/js/src/rhodecode/pullrequests.js:446
4751 4917 msgid "added manually by \"{0}\""
4752 4918 msgstr ""
4753 4919
4754 #: rhodecode/public/js/scripts.js:44777 rhodecode/public/js/scripts.min.js:1
4755 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:101
4756 #: rhodecode/public/js/src/rhodecode/pullrequests.js:417
4920 #: rhodecode/public/js/scripts.js:41491 rhodecode/public/js/scripts.min.js:1
4921 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:113
4922 #: rhodecode/public/js/src/rhodecode/pullrequests.js:450
4757 4923 msgid "member of \"{0}\""
4758 4924 msgstr ""
4759 4925
4760 #: rhodecode/public/js/scripts.js:44953 rhodecode/public/js/scripts.min.js:1
4761 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:82
4762 #: rhodecode/public/js/src/rhodecode/pullrequests.js:608
4926 #: rhodecode/public/js/scripts.js:41682 rhodecode/public/js/scripts.min.js:1
4927 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:94
4928 #: rhodecode/public/js/src/rhodecode/pullrequests.js:641
4763 4929 msgid "Updating..."
4764 4930 msgstr ""
4765 4931
4766 #: rhodecode/public/js/scripts.js:44963 rhodecode/public/js/scripts.min.js:1
4767 #: rhodecode/public/js/src/rhodecode/pullrequests.js:618
4932 #: rhodecode/public/js/scripts.js:41692 rhodecode/public/js/scripts.min.js:1
4933 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:28
4934 #: rhodecode/public/js/src/rhodecode/pullrequests.js:651
4768 4935 msgid "Force updating..."
4769 4936 msgstr ""
4770 4937
4771 #: rhodecode/public/js/scripts.js:49591 rhodecode/public/js/scripts.min.js:1
4772 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:93
4938 #: rhodecode/public/js/scripts.js:46140 rhodecode/public/js/scripts.min.js:1
4939 #: rhodecode/public/js/src/rhodecode/users.js:54
4940 msgid "Show this authentication token?"
4941 msgstr ""
4942
4943 #: rhodecode/public/js/scripts.js:46142 rhodecode/public/js/scripts.min.js:1
4944 #: rhodecode/public/js/src/rhodecode/users.js:56
4945 msgid "Show"
4946 msgstr ""
4947
4948 #: rhodecode/public/js/scripts.js:46178 rhodecode/public/js/scripts.min.js:1
4949 #: rhodecode/public/js/src/rhodecode/users.js:92
4950 msgid "Authentication Token"
4951 msgstr ""
4952
4953 #: rhodecode/public/js/scripts.js:46367 rhodecode/public/js/scripts.min.js:1
4954 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:105
4773 4955 #: rhodecode/public/js/src/rhodecode.js:144
4774 4956 msgid "file"
4775 4957 msgstr ""
4776 4958
4777 #: rhodecode/public/js/scripts.js:49735 rhodecode/public/js/scripts.min.js:1
4959 #: rhodecode/public/js/scripts.js:46511 rhodecode/public/js/scripts.min.js:1
4960 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:39
4778 4961 #: rhodecode/public/js/src/rhodecode.js:288
4779 4962 msgid "Loading..."
4780 4963 msgstr ""
4781 4964
4782 #: rhodecode/public/js/scripts.js:50104 rhodecode/public/js/scripts.min.js:1
4783 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:90
4784 #: rhodecode/public/js/src/rhodecode.js:657
4965 #: rhodecode/public/js/scripts.js:46884 rhodecode/public/js/scripts.min.js:1
4966 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:102
4967 #: rhodecode/public/js/src/rhodecode.js:661
4785 4968 msgid "date not in future"
4786 4969 msgstr ""
4787 4970
4788 #: rhodecode/public/js/scripts.js:50112 rhodecode/public/js/scripts.min.js:1
4789 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:67
4790 #: rhodecode/public/js/src/rhodecode.js:665
4971 #: rhodecode/public/js/scripts.js:46892 rhodecode/public/js/scripts.min.js:1
4972 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:79
4973 #: rhodecode/public/js/src/rhodecode.js:669
4791 4974 msgid "Specified expiration date"
4792 4975 msgstr ""
4793 4976
4977 #: rhodecode/public/js/scripts.min.js:1
4978 msgid "action"
4979 msgstr ""
4980
4981 #: rhodecode/public/js/scripts.min.js:1
4982 msgid "target"
4983 msgstr ""
4984
4985 #: rhodecode/public/js/scripts.min.js:1
4986 msgid "text"
4987 msgstr ""
4988
4794 4989 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:2
4795 4990 msgid "(from usergroup {0})"
4796 4991 msgstr ""
4797 4992
4798 4993 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:3
4799 #: rhodecode/templates/codeblocks/diffs.mako:594
4800 #: rhodecode/templates/codeblocks/diffs.mako:598
4994 #: rhodecode/templates/codeblocks/diffs.mako:606
4995 #: rhodecode/templates/codeblocks/diffs.mako:610
4801 4996 msgid "Add another comment"
4802 4997 msgstr ""
4803 4998
4804 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:11
4805 msgid "Changed files"
4999 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:8
5000 msgid "Are you sure to close this pull request without merging?"
4806 5001 msgstr ""
4807 5002
4808 5003 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:12
5004 msgid "Changed files"
5005 msgstr ""
5006
5007 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:13
4809 5008 #: rhodecode/public/js/src/i18n_messages.js:5
4810 5009 #: rhodecode/templates/pullrequests/pullrequest_show.mako:288
4811 5010 msgid "Close"
4812 5011 msgstr ""
4813 5012
5013 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:14
5014 #: rhodecode/templates/codeblocks/diffs.mako:131
5015 msgid "Collapse all files"
5016 msgstr ""
5017
4814 5018 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:15
4815 msgid "Context file: "
4816 msgstr ""
4817
4818 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:17
4819 msgid "Diff to Commit "
4820 msgstr ""
4821
4822 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:18
4823 msgid "Fetching repository state failed. Error code: {0} {1}. Try <a href=\"{2}\">refreshing</a> this page."
5019 msgid "Collapse {0} commit"
5020 msgstr ""
5021
5022 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:16
5023 msgid "Collapse {0} commits"
4824 5024 msgstr ""
4825 5025
4826 5026 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:19
4827 msgid "Fetching repository state failed. Error code: {0} {1}. Try refreshing this page."
5027 msgid "Context file: "
4828 5028 msgstr ""
4829 5029
4830 5030 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:20
4831 msgid "Follow"
5031 msgid "Delete this comment?"
4832 5032 msgstr ""
4833 5033
4834 5034 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:21
4835 msgid "Hide full context diff"
5035 msgid "Diff to Commit "
4836 5036 msgstr ""
4837 5037
4838 5038 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:22
4839 msgid "Hide whitespace changes"
5039 #: rhodecode/templates/codeblocks/diffs.mako:129
5040 msgid "Expand all files"
4840 5041 msgstr ""
4841 5042
4842 5043 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:23
4843 #: rhodecode/public/js/src/i18n_messages.js:4
4844 msgid "Invite reviewers to this discussion"
5044 msgid "Expand {0} commit"
5045 msgstr ""
5046
5047 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:24
5048 msgid "Expand {0} commits"
5049 msgstr ""
5050
5051 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:25
5052 msgid "Fetching repository state failed. Error code: {0} {1}. Try <a href=\"{2}\">refreshing</a> this page."
5053 msgstr ""
5054
5055 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:26
5056 msgid "Fetching repository state failed. Error code: {0} {1}. Try refreshing this page."
5057 msgstr ""
5058
5059 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:27
5060 msgid "Follow"
5061 msgstr ""
5062
5063 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:29
5064 msgid "Hide full context diff"
4845 5065 msgstr ""
4846 5066
4847 5067 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:30
4848 msgid "No bookmarks available yet."
5068 msgid "Hide whitespace changes"
4849 5069 msgstr ""
4850 5070
4851 5071 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:31
4852 msgid "No branches available yet."
4853 msgstr ""
4854
4855 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:32
4856 msgid "No forks available yet."
5072 #: rhodecode/public/js/src/i18n_messages.js:4
5073 msgid "Invite reviewers to this discussion"
4857 5074 msgstr ""
4858 5075
4859 5076 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:33
4860 msgid "No gists available yet."
4861 msgstr ""
4862
4863 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:36
4864 msgid "No pull requests available yet."
4865 msgstr ""
4866
4867 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:37
4868 msgid "No repositories available yet."
4869 msgstr ""
4870
4871 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:38
4872 msgid "No repository groups available yet."
5077 msgid "Leave a comment, or click resolve button to resolve TODO comment #{0}"
4873 5078 msgstr ""
4874 5079
4875 5080 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:40
4876 msgid "No ssh keys available yet."
5081 msgid "No bookmarks available yet."
4877 5082 msgstr ""
4878 5083
4879 5084 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:41
4880 msgid "No tags available yet."
5085 msgid "No branches available yet."
4881 5086 msgstr ""
4882 5087
4883 5088 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:42
4884 msgid "No user groups available yet."
5089 msgid "No forks available yet."
4885 5090 msgstr ""
4886 5091
4887 5092 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:43
4888 msgid "No users available yet."
5093 msgid "No gists available yet."
5094 msgstr ""
5095
5096 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:46
5097 msgid "No pull requests available yet."
4889 5098 msgstr ""
4890 5099
4891 5100 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:47
4892 #: rhodecode/templates/commits/changelog.mako:78
4893 msgid "Open new pull request"
5101 msgid "No repositories available yet."
4894 5102 msgstr ""
4895 5103
4896 5104 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:48
4897 msgid "Open new pull request for selected commit"
5105 msgid "No repositories present."
5106 msgstr ""
5107
5108 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:49
5109 msgid "No repository groups available yet."
5110 msgstr ""
5111
5112 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:50
5113 msgid "No repository groups present."
5114 msgstr ""
5115
5116 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:52
5117 msgid "No ssh keys available yet."
5118 msgstr ""
5119
5120 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:53
5121 msgid "No tags available yet."
4898 5122 msgstr ""
4899 5123
4900 5124 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:54
4901 msgid "Saving..."
4902 msgstr ""
4903
4904 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:57
4905 #: rhodecode/public/js/src/i18n_messages.js:6
4906 #: rhodecode/templates/admin/settings/settings_email.mako:50
4907 msgid "Send"
5125 msgid "No user groups available yet."
5126 msgstr ""
5127
5128 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:55
5129 msgid "No users available yet."
5130 msgstr ""
5131
5132 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:59
5133 #: rhodecode/templates/commits/changelog.mako:78
5134 msgid "Open new pull request"
4908 5135 msgstr ""
4909 5136
4910 5137 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:60
4911 msgid "Show at Commit "
4912 msgstr ""
4913
4914 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:61
4915 msgid "Show commit range {0} ... {1}"
4916 msgstr ""
4917
4918 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:62
4919 msgid "Show full context diff"
4920 msgstr ""
4921
4922 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:63
4923 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:39
4924 msgid "Show more"
4925 msgstr ""
4926
4927 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:64
4928 msgid "Show selected commit __S"
4929 msgstr ""
4930
4931 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:65
4932 msgid "Show selected commits __S ... __E"
5138 msgid "Open new pull request for selected commit"
4933 5139 msgstr ""
4934 5140
4935 5141 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:66
4936 msgid "Show whitespace changes"
4937 msgstr ""
4938
4939 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:68
4940 msgid "Start following this repository"
4941 msgstr ""
4942
4943 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:71
4944 msgid "Stop following this repository"
5142 msgid "Saving..."
5143 msgstr ""
5144
5145 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:69
5146 #: rhodecode/public/js/src/i18n_messages.js:6
5147 #: rhodecode/templates/admin/settings/settings_email.mako:50
5148 msgid "Send"
5149 msgstr ""
5150
5151 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:72
5152 msgid "Show at Commit "
5153 msgstr ""
5154
5155 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:73
5156 msgid "Show commit range {0} ... {1}"
4945 5157 msgstr ""
4946 5158
4947 5159 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:74
4948 #: rhodecode/public/js/src/i18n_messages.js:7
4949 msgid "Switch to chat"
5160 msgid "Show full context diff"
4950 5161 msgstr ""
4951 5162
4952 5163 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:75
4953 #: rhodecode/public/js/src/i18n_messages.js:8
4954 msgid "Switch to comment"
5164 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:40
5165 msgid "Show more"
5166 msgstr ""
5167
5168 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:76
5169 msgid "Show selected commit __S"
5170 msgstr ""
5171
5172 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:77
5173 msgid "Show selected commits __S ... __E"
4955 5174 msgstr ""
4956 5175
4957 5176 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:78
4958 msgid "There are currently no open pull requests requiring your participation."
4959 msgstr ""
4960
4961 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:79
4962 msgid "Toggle Wide Mode diff"
5177 msgid "Show whitespace changes"
4963 5178 msgstr ""
4964 5179
4965 5180 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:80
4966 msgid "Unfollow"
4967 msgstr ""
4968
4969 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:88
4970 #: rhodecode/templates/admin/auth/auth_settings.mako:69
4971 msgid "activated"
5181 msgid "Start following this repository"
5182 msgstr ""
5183
5184 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:83
5185 msgid "Stop following this repository"
5186 msgstr ""
5187
5188 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:86
5189 #: rhodecode/public/js/src/i18n_messages.js:7
5190 msgid "Switch to chat"
5191 msgstr ""
5192
5193 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:87
5194 #: rhodecode/public/js/src/i18n_messages.js:8
5195 msgid "Switch to comment"
5196 msgstr ""
5197
5198 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:90
5199 msgid "There are currently no open pull requests requiring your participation."
4972 5200 msgstr ""
4973 5201
4974 5202 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:91
4975 msgid "disabled"
5203 msgid "Toggle Wide Mode diff"
4976 5204 msgstr ""
4977 5205
4978 5206 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:92
4979 msgid "enabled"
4980 msgstr ""
4981
4982 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:94
4983 msgid "files"
4984 msgstr ""
4985
4986 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:95
4987 msgid "go to numeric commit"
5207 msgid "Unfollow"
4988 5208 msgstr ""
4989 5209
4990 5210 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:100
4991 #: rhodecode/templates/pullrequests/pullrequest.mako:136
4992 msgid "loading..."
4993 msgstr ""
4994
4995 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:102
4996 5211 #: rhodecode/templates/admin/auth/auth_settings.mako:69
4997 msgid "not active"
5212 msgid "activated"
5213 msgstr ""
5214
5215 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:103
5216 msgid "disabled"
5217 msgstr ""
5218
5219 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:104
5220 msgid "enabled"
4998 5221 msgstr ""
4999 5222
5000 5223 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:106
5001 msgid "specify commit"
5002 msgstr ""
5003
5004 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:109
5005 msgid "{0} ({1} inactive) of {2} user groups ({3} inactive)"
5006 msgstr ""
5007
5008 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:110
5009 msgid "{0} ({1} inactive) of {2} users ({3} inactive)"
5010 msgstr ""
5011
5012 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:111
5013 msgid "{0} active out of {1} users"
5014 msgstr ""
5015
5016 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:116
5017 msgid "{0} days"
5224 msgid "files"
5225 msgstr ""
5226
5227 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:107
5228 msgid "go to numeric commit"
5229 msgstr ""
5230
5231 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:112
5232 #: rhodecode/templates/index_base.mako:27
5233 #: rhodecode/templates/pullrequests/pullrequest.mako:136
5234 msgid "loading..."
5235 msgstr ""
5236
5237 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:114
5238 #: rhodecode/templates/admin/auth/auth_settings.mako:69
5239 msgid "not active"
5018 5240 msgstr ""
5019 5241
5020 5242 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:118
5021 msgid "{0} hours"
5243 msgid "specify commit"
5022 5244 msgstr ""
5023 5245
5024 5246 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:121
5025 msgid "{0} months"
5247 msgid "{0} ({1} inactive) of {2} user groups ({3} inactive)"
5026 5248 msgstr ""
5027 5249
5028 5250 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:122
5029 msgid "{0} of {1} repository groups"
5251 msgid "{0} ({1} inactive) of {2} users ({3} inactive)"
5030 5252 msgstr ""
5031 5253
5032 5254 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:123
5033 msgid "{0} out of {1} ssh keys"
5034 msgstr ""
5035
5036 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:124
5037 msgid "{0} out of {1} users"
5038 msgstr ""
5039
5040 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:125
5041 msgid "{0} repository groups"
5255 msgid "{0} active out of {1} users"
5042 5256 msgstr ""
5043 5257
5044 5258 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:128
5259 msgid "{0} days"
5260 msgstr ""
5261
5262 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:130
5263 msgid "{0} hours"
5264 msgstr ""
5265
5266 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:133
5267 msgid "{0} months"
5268 msgstr ""
5269
5270 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:134
5271 msgid "{0} of {1} repositories"
5272 msgstr ""
5273
5274 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:135
5275 msgid "{0} of {1} repository groups"
5276 msgstr ""
5277
5278 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:136
5279 msgid "{0} out of {1} ssh keys"
5280 msgstr ""
5281
5282 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:137
5283 msgid "{0} out of {1} users"
5284 msgstr ""
5285
5286 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:138
5287 msgid "{0} repositories"
5288 msgstr ""
5289
5290 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:139
5291 msgid "{0} repository groups"
5292 msgstr ""
5293
5294 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:142
5045 5295 msgid "{0} user groups ({1} inactive)"
5046 5296 msgstr ""
5047 5297
5048 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:129
5298 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:143
5049 5299 msgid "{0} users ({1} inactive)"
5050 5300 msgstr ""
5051 5301
5052 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:131
5302 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:145
5053 5303 msgid "{0} years"
5054 5304 msgstr ""
5055 5305
5056 5306 #: rhodecode/public/js/src/math_jax/extensions/HelpDialog.js:19
5057 5307 msgid "HelpDialog"
5058 5308 msgstr ""
5059 5309
5060 5310 #: rhodecode/public/js/src/math_jax/jax/output/HTML-CSS/autoload/mglyph.js:19
5061 5311 msgid "MathML"
5062 5312 msgstr ""
5063 5313
5064 #: rhodecode/public/js/src/rhodecode/comments.js:634
5065 msgid "Leave a resolution comment, or click resolve button to resolve TODO comment #{0}"
5066 msgstr ""
5067
5068 5314 #: rhodecode/templates/index.mako:5
5069 5315 msgid "Dashboard"
5070 5316 msgstr ""
5071 5317
5072 #: rhodecode/templates/index_base.mako:20
5318 #: rhodecode/templates/index_base.mako:21
5073 5319 msgid "No repositories or repositories groups exists here."
5074 5320 msgstr ""
5075 5321
5076 #: rhodecode/templates/index_base.mako:62
5077 #: rhodecode/templates/index_base.mako:153
5322 #: rhodecode/templates/index_base.mako:80
5323 #: rhodecode/templates/index_base.mako:167
5078 5324 #: rhodecode/templates/admin/gists/gist_index.mako:107
5079 5325 #: rhodecode/templates/admin/integrations/list.mako:72
5080 5326 #: rhodecode/templates/admin/my_account/my_account_repos.mako:28
5081 5327 #: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:39
5082 5328 #: rhodecode/templates/admin/my_account/my_account_watched.mako:28
5083 5329 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:74
5084 5330 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:16
5085 5331 #: rhodecode/templates/admin/repos/repos.mako:76
5086 5332 #: rhodecode/templates/admin/user_groups/user_groups.mako:76
5087 #: rhodecode/templates/admin/users/user_edit_groups.mako:54
5333 #: rhodecode/templates/admin/users/user_edit_groups.mako:57
5088 5334 #: rhodecode/templates/base/perms_summary.mako:168
5089 5335 #: rhodecode/templates/base/perms_summary.mako:242
5090 5336 #: rhodecode/templates/bookmarks/bookmarks.mako:57
5091 5337 #: rhodecode/templates/branches/branches.mako:56
5092 5338 #: rhodecode/templates/files/files_browser_tree.mako:13
5093 5339 #: rhodecode/templates/tags/tags.mako:57
5094 5340 msgid "Name"
5095 5341 msgstr ""
5096 5342
5097 #: rhodecode/templates/index_base.mako:71
5098 #: rhodecode/templates/index_base.mako:162
5343 #: rhodecode/templates/index_base.mako:89
5344 #: rhodecode/templates/index_base.mako:176
5099 5345 #: rhodecode/templates/admin/gists/gist_index.mako:109
5100 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:15
5101 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:72
5102 #: rhodecode/templates/admin/my_account/my_account_profile.mako:57
5346 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:21
5347 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:81
5348 #: rhodecode/templates/admin/my_account/my_account_profile.mako:68
5103 5349 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:10
5104 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:57
5350 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:58
5105 5351 #: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:44
5106 5352 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:49
5107 5353 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:53
5108 5354 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:55
5109 5355 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:77
5110 #: rhodecode/templates/admin/repos/repo_add_base.mako:66
5111 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:29
5356 #: rhodecode/templates/admin/repos/repo_add_base.mako:83
5357 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:30
5112 5358 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:170
5113 5359 #: rhodecode/templates/admin/repos/repos.mako:84
5114 5360 #: rhodecode/templates/admin/user_groups/user_group_add.mako:42
5115 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:42
5361 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:46
5116 5362 #: rhodecode/templates/admin/user_groups/user_groups.mako:78
5117 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:15
5118 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:72
5119 #: rhodecode/templates/admin/users/user_edit_groups.mako:59
5120 #: rhodecode/templates/admin/users/user_edit_ips.mako:12
5121 #: rhodecode/templates/admin/users/user_edit_profile.mako:71
5122 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:10
5123 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:52
5363 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:26
5364 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:85
5365 #: rhodecode/templates/admin/users/user_edit_groups.mako:62
5366 #: rhodecode/templates/admin/users/user_edit_ips.mako:17
5367 #: rhodecode/templates/admin/users/user_edit_profile.mako:74
5368 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:15
5369 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:57
5124 5370 #: rhodecode/templates/base/issue_tracker_settings.mako:78
5125 #: rhodecode/templates/compare/compare_commits.mako:21
5371 #: rhodecode/templates/compare/compare_commits.mako:19
5126 5372 #: rhodecode/templates/email_templates/pull_request_review.mako:43
5127 5373 #: rhodecode/templates/email_templates/pull_request_review.mako:123
5128 5374 #: rhodecode/templates/email_templates/pull_request_update.mako:43
5129 5375 #: rhodecode/templates/email_templates/pull_request_update.mako:135
5130 5376 #: rhodecode/templates/forks/fork.mako:56
5131 5377 #: rhodecode/templates/forks/forks.mako:62
5132 5378 #: rhodecode/templates/pullrequests/pullrequest.mako:50
5133 #: rhodecode/templates/pullrequests/pullrequest_show.mako:547
5379 #: rhodecode/templates/pullrequests/pullrequest_show.mako:562
5134 5380 #: rhodecode/templates/summary/components.mako:159
5135 5381 #: rhodecode/templates/user_group/profile.mako:25
5136 5382 #: rhodecode/templates/users/user_profile.mako:59
5137 5383 msgid "Description"
5138 5384 msgstr ""
5139 5385
5140 #: rhodecode/templates/index_base.mako:78
5141 #: rhodecode/templates/index_base.mako:169
5386 #: rhodecode/templates/index_base.mako:96
5387 #: rhodecode/templates/index_base.mako:183
5142 5388 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:80
5143 5389 #: rhodecode/templates/admin/repos/repos.mako:91
5144 5390 msgid "Last Change"
5145 5391 msgstr ""
5146 5392
5147 #: rhodecode/templates/index_base.mako:91
5148 #: rhodecode/templates/index_base.mako:182
5393 #: rhodecode/templates/index_base.mako:109
5394 #: rhodecode/templates/index_base.mako:196
5149 5395 #: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:50
5150 5396 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:8
5151 5397 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:37
5152 5398 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:84
5153 5399 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:6
5154 5400 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:152
5155 5401 #: rhodecode/templates/admin/repos/repos.mako:104
5156 5402 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:6
5157 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:24
5403 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:28
5158 5404 #: rhodecode/templates/admin/user_groups/user_groups.mako:86
5159 #: rhodecode/templates/admin/users/user_edit_groups.mako:65
5405 #: rhodecode/templates/admin/users/user_edit_groups.mako:68
5160 5406 #: rhodecode/templates/forks/forks.mako:58
5161 5407 #: rhodecode/templates/summary/components.mako:148
5162 5408 #: rhodecode/templates/user_group/profile.mako:35
5163 5409 msgid "Owner"
5164 5410 msgstr ""
5165 5411
5166 #: rhodecode/templates/index_base.mako:176
5412 #: rhodecode/templates/index_base.mako:190
5167 5413 #: rhodecode/templates/admin/repos/repos.mako:98
5168 5414 #: rhodecode/templates/bookmarks/bookmarks.mako:64
5169 5415 #: rhodecode/templates/branches/branches.mako:63
5170 #: rhodecode/templates/compare/compare_commits.mako:19
5416 #: rhodecode/templates/compare/compare_commits.mako:17
5171 5417 #: rhodecode/templates/email_templates/commit_comment.mako:56
5172 5418 #: rhodecode/templates/email_templates/commit_comment.mako:109
5173 5419 #: rhodecode/templates/email_templates/commit_comment.mako:135
5174 5420 #: rhodecode/templates/files/file_authors_box.mako:28
5175 #: rhodecode/templates/pullrequests/pullrequest_show.mako:545
5421 #: rhodecode/templates/pullrequests/pullrequest_show.mako:560
5176 5422 #: rhodecode/templates/search/search_commit.mako:9
5177 5423 #: rhodecode/templates/summary/components.mako:117
5178 5424 #: rhodecode/templates/summary/components.mako:125
5179 5425 #: rhodecode/templates/summary/summary_commits.mako:8
5180 5426 #: rhodecode/templates/tags/tags.mako:64
5181 5427 msgid "Commit"
5182 5428 msgstr ""
5183 5429
5184 5430 #: rhodecode/templates/index_repo_group.mako:5
5185 5431 #, python-format
5186 5432 msgid "%s Repository group dashboard"
5187 5433 msgstr ""
5188 5434
5189 5435 #: rhodecode/templates/index_repo_group.mako:13
5190 #: rhodecode/templates/base/base.mako:773
5191 #: rhodecode/templates/base/base.mako:774
5436 #: rhodecode/templates/base/base.mako:804
5437 #: rhodecode/templates/base/base.mako:805
5192 5438 msgid "Home"
5193 5439 msgstr ""
5194 5440
5195 5441 #: rhodecode/templates/login.mako:5 rhodecode/templates/login.mako:91
5196 5442 #: rhodecode/templates/debug_style/login.html:60
5197 5443 msgid "Sign In"
5198 5444 msgstr ""
5199 5445
5200 5446 #: rhodecode/templates/login.mako:39
5201 5447 msgid "Sign In using username/password"
5202 5448 msgstr ""
5203 5449
5204 5450 #: rhodecode/templates/login.mako:53
5205 5451 msgid "Forgot your password?"
5206 5452 msgstr ""
5207 5453
5208 5454 #: rhodecode/templates/login.mako:66
5209 5455 msgid "Remember my indefinitely"
5210 5456 msgstr ""
5211 5457
5212 5458 #: rhodecode/templates/login.mako:68
5213 5459 msgid "Remember me for {}"
5214 5460 msgstr ""
5215 5461
5216 5462 #: rhodecode/templates/login.mako:74
5217 5463 msgid "Create a new account."
5218 5464 msgstr ""
5219 5465
5220 5466 #: rhodecode/templates/login.mako:81
5221 5467 msgid "Password reset is disabled."
5222 5468 msgstr ""
5223 5469
5224 5470 #: rhodecode/templates/login.mako:82
5225 5471 msgid "Please contact "
5226 5472 msgstr ""
5227 5473
5228 5474 #: rhodecode/templates/login.mako:84 rhodecode/templates/password_reset.mako:39
5229 5475 #: rhodecode/templates/base/base.mako:59
5230 5476 msgid "Support"
5231 5477 msgstr ""
5232 5478
5233 5479 #: rhodecode/templates/login.mako:85 rhodecode/templates/password_reset.mako:40
5234 5480 msgid "or"
5235 5481 msgstr ""
5236 5482
5237 5483 #: rhodecode/templates/login.mako:87 rhodecode/templates/password_reset.mako:42
5238 5484 msgid "an administrator if you need help."
5239 5485 msgstr ""
5240 5486
5241 5487 #: rhodecode/templates/login.mako:91
5242 5488 msgid "Sign in to {}"
5243 5489 msgstr ""
5244 5490
5245 5491 #: rhodecode/templates/password_reset.mako:5
5246 5492 msgid "Reset Password"
5247 5493 msgstr ""
5248 5494
5249 5495 #: rhodecode/templates/password_reset.mako:37
5250 5496 msgid "Password reset is disabled. Please contact "
5251 5497 msgstr ""
5252 5498
5253 5499 #: rhodecode/templates/password_reset.mako:49
5254 5500 msgid "Reset your Password"
5255 5501 msgstr ""
5256 5502
5257 5503 #: rhodecode/templates/password_reset.mako:50
5258 5504 msgid "Go to the login page to sign in."
5259 5505 msgstr ""
5260 5506
5261 5507 #: rhodecode/templates/password_reset.mako:54
5262 5508 msgid "Email Address"
5263 5509 msgstr ""
5264 5510
5265 5511 #: rhodecode/templates/password_reset.mako:60
5266 5512 msgid "Password reset link will be sent to matching email address"
5267 5513 msgstr ""
5268 5514
5269 5515 #: rhodecode/templates/password_reset.mako:64
5270 5516 #: rhodecode/templates/register.mako:104
5271 5517 msgid "Captcha"
5272 5518 msgstr ""
5273 5519
5274 5520 #: rhodecode/templates/password_reset.mako:75
5275 5521 msgid "Send password reset email"
5276 5522 msgstr ""
5277 5523
5278 5524 #: rhodecode/templates/register.mako:5
5279 5525 msgid "Create an Account"
5280 5526 msgstr ""
5281 5527
5282 5528 #: rhodecode/templates/register.mako:38
5283 5529 msgid "Create an account linked with {}"
5284 5530 msgstr ""
5285 5531
5286 5532 #: rhodecode/templates/register.mako:40
5287 5533 msgid "Create an account"
5288 5534 msgstr ""
5289 5535
5290 5536 #: rhodecode/templates/register.mako:43
5291 5537 msgid "Go to the login page to sign in with an existing account."
5292 5538 msgstr ""
5293 5539
5294 5540 #: rhodecode/templates/register.mako:69
5295 5541 msgid "Re-enter password"
5296 5542 msgstr ""
5297 5543
5298 5544 #: rhodecode/templates/register.mako:81
5299 #: rhodecode/templates/admin/my_account/my_account_profile.mako:37
5300 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:32
5545 #: rhodecode/templates/admin/my_account/my_account_profile.mako:48
5546 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:38
5301 5547 #: rhodecode/templates/admin/users/user_add.mako:68
5302 #: rhodecode/templates/admin/users/user_edit_profile.mako:44
5548 #: rhodecode/templates/admin/users/user_edit_profile.mako:47
5303 5549 #: rhodecode/templates/admin/users/users.mako:78
5304 5550 msgid "First Name"
5305 5551 msgstr ""
5306 5552
5307 5553 #: rhodecode/templates/register.mako:88
5308 #: rhodecode/templates/admin/my_account/my_account_profile.mako:47
5309 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:41
5554 #: rhodecode/templates/admin/my_account/my_account_profile.mako:58
5555 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:47
5310 5556 #: rhodecode/templates/admin/users/user_add.mako:77
5311 #: rhodecode/templates/admin/users/user_edit_profile.mako:53
5557 #: rhodecode/templates/admin/users/user_edit_profile.mako:56
5312 5558 #: rhodecode/templates/admin/users/users.mako:80
5313 5559 msgid "Last Name"
5314 5560 msgstr ""
5315 5561
5316 5562 #: rhodecode/templates/register.mako:116
5317 5563 msgid "Account activation requires admin approval."
5318 5564 msgstr ""
5319 5565
5320 5566 #: rhodecode/templates/register.mako:123
5321 5567 msgid "Create Account"
5322 5568 msgstr ""
5323 5569
5324 5570 #: rhodecode/templates/register.mako:123
5325 5571 msgid "Create Account in {}"
5326 5572 msgstr ""
5327 5573
5328 5574 #: rhodecode/templates/admin/admin_audit_log_entry.mako:6
5329 5575 msgid "Admin audit log entry"
5330 5576 msgstr ""
5331 5577
5332 5578 #: rhodecode/templates/admin/admin_audit_log_entry.mako:26
5333 5579 msgid "Audit long entry"
5334 5580 msgstr ""
5335 5581
5336 5582 #: rhodecode/templates/admin/admin_audit_log_entry.mako:34
5337 5583 #: rhodecode/templates/users/user.mako:4
5338 5584 msgid "User"
5339 5585 msgstr ""
5340 5586
5341 5587 #: rhodecode/templates/admin/admin_audit_log_entry.mako:46
5342 5588 #: rhodecode/templates/admin/admin_log_base.mako:11
5343 5589 #: rhodecode/templates/bookmarks/bookmarks.mako:59
5344 5590 #: rhodecode/templates/branches/branches.mako:58
5345 5591 #: rhodecode/templates/tags/tags.mako:59
5346 5592 msgid "Date"
5347 5593 msgstr ""
5348 5594
5349 5595 #: rhodecode/templates/admin/admin_audit_log_entry.mako:54
5350 5596 #: rhodecode/templates/admin/admin_log_base.mako:12
5351 5597 msgid "IP"
5352 5598 msgstr ""
5353 5599
5354 5600 #: rhodecode/templates/admin/admin_audit_log_entry.mako:63
5355 5601 #: rhodecode/templates/admin/admin_log_base.mako:8
5356 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:19
5602 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:25
5357 5603 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:13
5358 5604 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:55
5359 5605 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:86
5360 5606 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:13
5361 5607 #: rhodecode/templates/admin/repos/repos.mako:116
5362 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:71
5608 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:75
5363 5609 #: rhodecode/templates/admin/user_groups/user_groups.mako:88
5364 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:19
5365 #: rhodecode/templates/admin/users/user_edit_groups.mako:73
5366 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:13
5610 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:30
5611 #: rhodecode/templates/admin/users/user_edit_groups.mako:76
5612 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:18
5367 5613 #: rhodecode/templates/admin/users/users.mako:91
5368 5614 #: rhodecode/templates/forks/forks.mako:69
5369 5615 msgid "Action"
5370 5616 msgstr ""
5371 5617
5372 5618 #: rhodecode/templates/admin/admin_audit_log_entry.mako:81
5373 5619 #: rhodecode/templates/admin/admin_log_base.mako:9
5374 5620 msgid "Action Data"
5375 5621 msgstr ""
5376 5622
5377 5623 #: rhodecode/templates/admin/admin_audit_log_entry.mako:89
5378 5624 #: rhodecode/templates/admin/admin_log_base.mako:47
5379 5625 msgid "data not available for v1 entries type"
5380 5626 msgstr ""
5381 5627
5382 5628 #: rhodecode/templates/admin/admin_audit_log_entry.mako:95
5383 5629 #: rhodecode/templates/admin/admin_log_base.mako:10
5384 5630 #: rhodecode/templates/admin/defaults/defaults.mako:32
5385 5631 #: rhodecode/templates/admin/permissions/permissions_objects.mako:16
5632 #: rhodecode/templates/base/base.mako:649
5633 #: rhodecode/templates/base/base.mako:651
5386 5634 #: rhodecode/templates/base/base.mako:653
5387 #: rhodecode/templates/base/base.mako:655
5388 #: rhodecode/templates/base/base.mako:657
5389 5635 #: rhodecode/templates/search/search_commit.mako:8
5390 5636 #: rhodecode/templates/search/search_path.mako:7
5391 5637 msgid "Repository"
5392 5638 msgstr ""
5393 5639
5394 5640 #: rhodecode/templates/admin/admin_audit_logs.mako:5
5395 5641 #: rhodecode/templates/base/base.mako:106
5396 5642 msgid "Admin audit logs"
5397 5643 msgstr ""
5398 5644
5399 5645 #: rhodecode/templates/admin/admin_audit_logs.mako:25
5400 5646 msgid "filter..."
5401 5647 msgstr ""
5402 5648
5403 5649 #: rhodecode/templates/admin/admin_audit_logs.mako:26
5404 5650 #: rhodecode/templates/admin/repos/repo_edit_audit.mako:15
5405 #: rhodecode/templates/admin/users/user_edit_audit.mako:16
5651 #: rhodecode/templates/admin/users/user_edit_audit.mako:18
5406 5652 #: rhodecode/templates/journal/journal.mako:13
5407 5653 msgid "filter"
5408 5654 msgstr ""
5409 5655
5410 5656 #: rhodecode/templates/admin/admin_audit_logs.mako:27
5411 5657 #: rhodecode/templates/admin/repos/repo_edit.mako:91
5412 5658 #: rhodecode/templates/admin/users/user_edit.mako:48
5413 5659 msgid "Audit logs"
5414 5660 msgstr ""
5415 5661
5416 5662 #: rhodecode/templates/admin/admin_audit_logs.mako:29
5417 5663 #: rhodecode/templates/admin/repos/repo_edit_audit.mako:18
5418 #: rhodecode/templates/admin/users/user_edit_audit.mako:19
5664 #: rhodecode/templates/admin/users/user_edit_audit.mako:21
5419 5665 #: rhodecode/templates/journal/journal.mako:16
5420 5666 msgid "Example Queries"
5421 5667 msgstr ""
5422 5668
5423 5669 #: rhodecode/templates/admin/admin_log_base.mako:6
5424 5670 msgid "Uid"
5425 5671 msgstr ""
5426 5672
5427 5673 #: rhodecode/templates/admin/admin_log_base.mako:42
5428 5674 msgid "toggle"
5429 5675 msgstr ""
5430 5676
5431 5677 #: rhodecode/templates/admin/admin_log_base.mako:68
5432 5678 msgid "No actions yet"
5433 5679 msgstr ""
5434 5680
5435 5681 #: rhodecode/templates/admin/main.mako:5
5436 5682 #: rhodecode/templates/admin/settings/settings.mako:5
5437 5683 msgid "Settings administration"
5438 5684 msgstr ""
5439 5685
5440 5686 #: rhodecode/templates/admin/main.mako:26
5441 5687 msgid "Administration area"
5442 5688 msgstr ""
5443 5689
5444 5690 #: rhodecode/templates/admin/main.mako:30
5445 5691 msgid "Repositories under administration"
5446 5692 msgstr ""
5447 5693
5448 5694 #: rhodecode/templates/admin/main.mako:34
5449 5695 #: rhodecode/templates/admin/repos/repo_add.mako:22
5450 5696 #: rhodecode/templates/admin/repos/repos.mako:31
5451 5697 msgid "Add Repository"
5452 5698 msgstr ""
5453 5699
5454 5700 #: rhodecode/templates/admin/main.mako:39
5455 5701 msgid "Repository groups under administration"
5456 5702 msgstr ""
5457 5703
5458 5704 #: rhodecode/templates/admin/main.mako:43
5459 5705 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:16
5460 5706 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:31
5461 5707 msgid "Add Repository Group"
5462 5708 msgstr ""
5463 5709
5464 5710 #: rhodecode/templates/admin/main.mako:48
5465 5711 msgid "User groups under administration"
5466 5712 msgstr ""
5467 5713
5468 5714 #: rhodecode/templates/admin/main.mako:52
5469 5715 #: rhodecode/templates/admin/user_groups/user_group_add.mako:15
5470 5716 #: rhodecode/templates/admin/user_groups/user_groups.mako:31
5471 5717 msgid "Add User Group"
5472 5718 msgstr ""
5473 5719
5474 5720 #: rhodecode/templates/admin/auth/auth_settings.mako:5
5475 5721 #: rhodecode/templates/admin/auth/plugin_settings.mako:5
5476 5722 msgid "Authentication Settings"
5477 5723 msgstr ""
5478 5724
5479 5725 #: rhodecode/templates/admin/auth/auth_settings.mako:42
5480 5726 msgid "Enabled and Available Plugins"
5481 5727 msgstr ""
5482 5728
5483 5729 #: rhodecode/templates/admin/auth/auth_settings.mako:48
5484 5730 msgid "Ordered Activated Plugins"
5485 5731 msgstr ""
5486 5732
5487 5733 #: rhodecode/templates/admin/auth/auth_settings.mako:53
5488 5734 msgid ""
5489 5735 "List of plugins, separated by commas.\n"
5490 5736 "The order of the plugins is also the order in which RhodeCode Enterprise will try to authenticate a user."
5491 5737 msgstr ""
5492 5738
5493 5739 #: rhodecode/templates/admin/auth/auth_settings.mako:60
5494 5740 msgid "Activate"
5495 5741 msgstr ""
5496 5742
5497 5743 #: rhodecode/templates/admin/auth/auth_settings.mako:61
5498 5744 msgid "Plugin Name"
5499 5745 msgstr ""
5500 5746
5501 5747 #: rhodecode/templates/admin/auth/auth_settings.mako:62
5502 5748 msgid "Documentation"
5503 5749 msgstr ""
5504 5750
5505 5751 #: rhodecode/templates/admin/auth/auth_settings.mako:63
5506 5752 msgid "Plugin ID"
5507 5753 msgstr ""
5508 5754
5509 5755 #: rhodecode/templates/admin/auth/auth_settings.mako:85
5510 5756 #: rhodecode/templates/admin/auth/plugin_settings.mako:96
5511 5757 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:63
5512 5758 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:109
5513 5759 #: rhodecode/templates/admin/permissions/permissions_application.mako:59
5514 5760 #: rhodecode/templates/admin/permissions/permissions_objects.mako:59
5515 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:206
5516 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:71
5517 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:79
5518 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:191
5519 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:243
5761 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:216
5762 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:77
5763 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:66
5764 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:84
5765 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:200
5766 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:250
5520 5767 #: rhodecode/templates/admin/settings/settings_hooks.mako:63
5521 5768 #: rhodecode/templates/admin/settings/settings_issuetracker.mako:15
5522 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:192
5523 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:102
5524 #: rhodecode/templates/admin/users/user_edit_groups.mako:27
5525 #: rhodecode/templates/admin/users/user_edit_profile.mako:145
5769 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:206
5770 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:106
5771 #: rhodecode/templates/admin/users/user_edit_groups.mako:30
5772 #: rhodecode/templates/admin/users/user_edit_profile.mako:154
5526 5773 #: rhodecode/templates/base/default_perms_box.mako:88
5527 5774 msgid "Save"
5528 5775 msgstr ""
5529 5776
5530 5777 #: rhodecode/templates/admin/auth/plugin_settings.mako:46
5531 5778 msgid "Plugin"
5532 5779 msgstr ""
5533 5780
5534 5781 #: rhodecode/templates/admin/defaults/defaults.mako:5
5535 5782 #: rhodecode/templates/admin/defaults/defaults.mako:14
5536 5783 msgid "Repositories defaults"
5537 5784 msgstr ""
5538 5785
5539 5786 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:3
5540 5787 msgid "Default Settings For New Repositories"
5541 5788 msgstr ""
5542 5789
5543 5790 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:14
5544 5791 #: rhodecode/templates/admin/gists/gist_index.mako:105
5545 5792 #: rhodecode/templates/admin/integrations/list.mako:73
5546 #: rhodecode/templates/admin/repos/repo_add_base.mako:57
5793 #: rhodecode/templates/admin/repos/repo_add_base.mako:58
5547 5794 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:12
5548 5795 msgid "Type"
5549 5796 msgstr ""
5550 5797
5551 5798 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:23
5552 #: rhodecode/templates/admin/repos/repo_add_base.mako:89
5799 #: rhodecode/templates/admin/repos/repo_add_base.mako:113
5553 5800 msgid "Private Repository"
5554 5801 msgstr ""
5555 5802
5556 5803 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:27
5557 #: rhodecode/templates/admin/repos/repo_add_base.mako:93
5558 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:109
5559 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:192
5560 #: rhodecode/templates/forks/fork.mako:85
5804 #: rhodecode/templates/admin/repos/repo_add_base.mako:117
5805 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:199
5806 #: rhodecode/templates/forks/fork.mako:92
5561 5807 msgid "Private repositories are only visible to people explicitly added as collaborators."
5562 5808 msgstr ""
5563 5809
5564 5810 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:34
5565 5811 msgid "Enable Statistics"
5566 5812 msgstr ""
5567 5813
5568 5814 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:38
5569 5815 msgid "Enable a statistics window on the repository summary page."
5570 5816 msgstr ""
5571 5817
5572 5818 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:44
5573 5819 msgid "Enable Downloads"
5574 5820 msgstr ""
5575 5821
5576 5822 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:48
5577 5823 msgid "Enable the download option on the repository summary page."
5578 5824 msgstr ""
5579 5825
5580 5826 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:54
5581 5827 msgid "Enable Locking"
5582 5828 msgstr ""
5583 5829
5584 5830 #: rhodecode/templates/admin/defaults/defaults_repositories.mako:58
5585 5831 msgid "Enable automatic repository locking. Pulling from a repository will lock it, and it is unlocked by pushing back by the same user."
5586 5832 msgstr ""
5587 5833
5588 5834 #: rhodecode/templates/admin/gists/gist_edit.mako:5
5589 5835 msgid "Edit Gist"
5590 5836 msgstr ""
5591 5837
5592 5838 #: rhodecode/templates/admin/gists/gist_edit.mako:33
5593 5839 #: rhodecode/templates/admin/gists/gist_new.mako:34
5594 5840 msgid "Gist lifetime"
5595 5841 msgstr ""
5596 5842
5597 5843 #: rhodecode/templates/admin/gists/gist_edit.mako:36
5598 5844 msgid "Gist access level"
5599 5845 msgstr ""
5600 5846
5601 5847 #: rhodecode/templates/admin/gists/gist_edit.mako:40
5602 5848 #: rhodecode/templates/admin/gists/gist_new.mako:40
5603 5849 msgid "Gist description ..."
5604 5850 msgstr ""
5605 5851
5606 5852 #: rhodecode/templates/admin/gists/gist_edit.mako:54
5607 5853 #: rhodecode/templates/admin/gists/gist_new.mako:48
5608 #: rhodecode/templates/files/files_add.mako:68
5854 #: rhodecode/templates/files/files_add.mako:67
5609 5855 #: rhodecode/templates/files/files_edit.mako:69
5610 5856 msgid "plain"
5611 5857 msgstr ""
5612 5858
5613 5859 #: rhodecode/templates/admin/gists/gist_edit.mako:99
5614 5860 msgid "Update Gist"
5615 5861 msgstr ""
5616 5862
5617 5863 #: rhodecode/templates/admin/gists/gist_edit.mako:100
5618 5864 #: rhodecode/templates/base/issue_tracker_settings.mako:150
5619 #: rhodecode/templates/changeset/changeset_file_comment.mako:391
5620 #: rhodecode/templates/codeblocks/diffs.mako:84
5865 #: rhodecode/templates/changeset/changeset_file_comment.mako:395
5866 #: rhodecode/templates/codeblocks/diffs.mako:88
5621 5867 #: rhodecode/templates/pullrequests/pullrequest_show.mako:75
5622 5868 msgid "Cancel"
5623 5869 msgstr ""
5624 5870
5625 5871 #: rhodecode/templates/admin/gists/gist_edit.mako:123
5626 5872 #, python-format
5627 5873 msgid "Gist was updated since you started editing. Copy your changes and click %(here)s to reload the new version."
5628 5874 msgstr ""
5629 5875
5630 5876 #: rhodecode/templates/admin/gists/gist_index.mako:6
5631 5877 msgid "Private Gists for user {}"
5632 5878 msgstr ""
5633 5879
5634 5880 #: rhodecode/templates/admin/gists/gist_index.mako:8
5635 5881 msgid "Public Gists for user {}"
5636 5882 msgstr ""
5637 5883
5638 5884 #: rhodecode/templates/admin/gists/gist_index.mako:10
5639 5885 msgid "Public Gists"
5640 5886 msgstr ""
5641 5887
5642 5888 #: rhodecode/templates/admin/gists/gist_index.mako:30
5643 5889 msgid "All gists"
5644 5890 msgstr ""
5645 5891
5646 5892 #: rhodecode/templates/admin/gists/gist_index.mako:32
5647 5893 msgid "All public"
5648 5894 msgstr ""
5649 5895
5650 5896 #: rhodecode/templates/admin/gists/gist_index.mako:34
5651 5897 msgid "My gists"
5652 5898 msgstr ""
5653 5899
5654 5900 #: rhodecode/templates/admin/gists/gist_index.mako:35
5655 5901 msgid "My private"
5656 5902 msgstr ""
5657 5903
5658 5904 #: rhodecode/templates/admin/gists/gist_index.mako:36
5659 5905 msgid "My public"
5660 5906 msgstr ""
5661 5907
5662 5908 #: rhodecode/templates/admin/gists/gist_index.mako:43
5663 5909 msgid "Create New Gist"
5664 5910 msgstr ""
5665 5911
5666 5912 #: rhodecode/templates/admin/gists/gist_index.mako:54
5913 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:23
5667 5914 #: rhodecode/templates/admin/my_account/my_account_repos.mako:7
5668 5915 #: rhodecode/templates/admin/my_account/my_account_watched.mako:7
5669 5916 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:11
5670 5917 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:25
5671 5918 #: rhodecode/templates/admin/repos/repos.mako:25
5672 5919 #: rhodecode/templates/admin/user_groups/user_groups.mako:25
5673 5920 #: rhodecode/templates/admin/users/users.mako:26
5674 5921 #: rhodecode/templates/bookmarks/bookmarks.mako:33
5675 5922 #: rhodecode/templates/branches/branches.mako:33
5676 5923 #: rhodecode/templates/journal/journal.mako:12
5677 5924 #: rhodecode/templates/pullrequests/pullrequests.mako:53
5678 5925 #: rhodecode/templates/tags/tags.mako:33
5679 5926 msgid "quick filter..."
5680 5927 msgstr ""
5681 5928
5682 5929 #: rhodecode/templates/admin/gists/gist_index.mako:103
5683 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:59
5930 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:91
5684 5931 #: rhodecode/templates/bookmarks/bookmarks.mako:61
5685 5932 #: rhodecode/templates/branches/branches.mako:60
5686 5933 #: rhodecode/templates/commits/changelog.mako:119
5687 #: rhodecode/templates/compare/compare_commits.mako:18
5934 #: rhodecode/templates/compare/compare_commits.mako:16
5688 5935 #: rhodecode/templates/files/files_browser_tree.mako:17
5689 #: rhodecode/templates/pullrequests/pullrequest_show.mako:544
5936 #: rhodecode/templates/pullrequests/pullrequest_show.mako:559
5690 5937 #: rhodecode/templates/pullrequests/pullrequests.mako:98
5691 5938 #: rhodecode/templates/search/search_commit.mako:18
5692 5939 #: rhodecode/templates/summary/summary_commits.mako:11
5693 5940 #: rhodecode/templates/tags/tags.mako:61
5694 5941 msgid "Author"
5695 5942 msgstr ""
5696 5943
5697 5944 #: rhodecode/templates/admin/gists/gist_index.mako:111
5698 5945 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:11
5699 5946 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:51
5700 5947 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:9
5701 5948 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:7
5702 5949 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:7
5703 5950 #: rhodecode/templates/admin/users/user_edit_advanced.mako:6
5704 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:11
5705 #: rhodecode/templates/pullrequests/pullrequest_show.mako:52
5951 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:16
5952 #: rhodecode/templates/pullrequests/pullrequest_show.mako:51
5706 5953 msgid "Created on"
5707 5954 msgstr ""
5708 5955
5709 5956 #: rhodecode/templates/admin/gists/gist_index.mako:113
5710 5957 msgid "Expires"
5711 5958 msgstr ""
5712 5959
5713 5960 #: rhodecode/templates/admin/gists/gist_new.mako:5
5714 #: rhodecode/templates/base/base.mako:572
5961 #: rhodecode/templates/base/base.mako:568
5715 5962 msgid "New Gist"
5716 5963 msgstr ""
5717 5964
5718 5965 #: rhodecode/templates/admin/gists/gist_new.mako:31
5719 5966 msgid "Gist id"
5720 5967 msgstr ""
5721 5968
5722 5969 #: rhodecode/templates/admin/gists/gist_new.mako:32
5723 5970 msgid "Auto generated"
5724 5971 msgstr ""
5725 5972
5726 5973 #: rhodecode/templates/admin/gists/gist_new.mako:37
5727 5974 msgid "Private Gist access level"
5728 5975 msgstr ""
5729 5976
5730 5977 #: rhodecode/templates/admin/gists/gist_new.mako:47
5731 5978 msgid "name gist file..."
5732 5979 msgstr ""
5733 5980
5734 5981 #: rhodecode/templates/admin/gists/gist_new.mako:61
5735 5982 msgid "Create Gist"
5736 5983 msgstr ""
5737 5984
5738 5985 #: rhodecode/templates/admin/gists/gist_new.mako:69
5739 5986 #: rhodecode/templates/admin/gists/gist_new.mako:70
5740 #: rhodecode/templates/data_table/_dt_elements.mako:344
5987 #: rhodecode/templates/data_table/_dt_elements.mako:352
5741 5988 msgid "Private Gist"
5742 5989 msgstr ""
5743 5990
5744 5991 #: rhodecode/templates/admin/gists/gist_new.mako:70
5745 5992 msgid "Private Gists are not listed and only accessible through their secret url."
5746 5993 msgstr ""
5747 5994
5748 5995 #: rhodecode/templates/admin/gists/gist_new.mako:73
5749 5996 #: rhodecode/templates/admin/gists/gist_new.mako:74
5750 #: rhodecode/templates/data_table/_dt_elements.mako:342
5997 #: rhodecode/templates/data_table/_dt_elements.mako:350
5751 5998 msgid "Public Gist"
5752 5999 msgstr ""
5753 6000
5754 6001 #: rhodecode/templates/admin/gists/gist_new.mako:74
5755 6002 msgid "Public Gists are accessible to anyone and listed in Gists page."
5756 6003 msgstr ""
5757 6004
5758 6005 #: rhodecode/templates/admin/gists/gist_show.mako:14
5759 6006 #: rhodecode/templates/admin/gists/gist_show.mako:21
5760 6007 msgid "Gist"
5761 6008 msgstr ""
5762 6009
5763 6010 #: rhodecode/templates/admin/gists/gist_show.mako:41
5764 6011 msgid "Copy the url"
5765 6012 msgstr ""
5766 6013
5767 6014 #: rhodecode/templates/admin/gists/gist_show.mako:47
5768 6015 #: rhodecode/templates/files/files_source.mako:106
5769 6016 msgid "Copy content"
5770 6017 msgstr ""
5771 6018
5772 6019 #: rhodecode/templates/admin/gists/gist_show.mako:52
5773 6020 msgid "Show as Raw"
5774 6021 msgstr ""
5775 6022
5776 #: rhodecode/templates/admin/gists/gist_show.mako:57
5777 msgid "Confirm to delete this Gist"
5778 msgstr ""
5779
5780 #: rhodecode/templates/admin/gists/gist_show.mako:70
6023 #: rhodecode/templates/admin/gists/gist_show.mako:73
5781 6024 msgid "created"
5782 6025 msgstr ""
5783 6026
5784 #: rhodecode/templates/admin/gists/gist_show.mako:71
6027 #: rhodecode/templates/admin/gists/gist_show.mako:74
5785 6028 msgid "expires"
5786 6029 msgstr ""
5787 6030
5788 #: rhodecode/templates/admin/gists/gist_show.mako:92
6031 #: rhodecode/templates/admin/gists/gist_show.mako:95
5789 6032 #: rhodecode/templates/files/files_delete.mako:58
5790 #: rhodecode/templates/files/files_source.mako:125
6033 #: rhodecode/templates/files/files_source.mako:128
5791 6034 msgid "Show as raw"
5792 6035 msgstr ""
5793 6036
5794 6037 #: rhodecode/templates/admin/integrations/base.mako:14
5795 6038 msgid "Integrations Settings"
5796 6039 msgstr ""
5797 6040
5798 6041 #: rhodecode/templates/admin/integrations/base.mako:23
5799 6042 #: rhodecode/templates/admin/integrations/form.mako:8
5800 6043 #: rhodecode/templates/admin/integrations/form.mako:21
5801 6044 #: rhodecode/templates/admin/integrations/form.mako:32
5802 6045 #: rhodecode/templates/admin/integrations/global.mako:14
5803 6046 #: rhodecode/templates/admin/integrations/list.mako:21
5804 6047 #: rhodecode/templates/admin/integrations/list.mako:25
5805 6048 #: rhodecode/templates/admin/integrations/list.mako:29
5806 6049 #: rhodecode/templates/admin/integrations/list.mako:36
5807 6050 #: rhodecode/templates/admin/integrations/new.mako:15
5808 6051 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:33
5809 6052 #: rhodecode/templates/admin/repos/repo_edit.mako:74
5810 6053 #: rhodecode/templates/base/base.mako:113
5811 6054 msgid "Integrations"
5812 6055 msgstr ""
5813 6056
5814 6057 #: rhodecode/templates/admin/integrations/form.mako:30
5815 6058 #: rhodecode/templates/admin/integrations/list.mako:16
5816 6059 #: rhodecode/templates/admin/integrations/new.mako:7
5817 6060 #: rhodecode/templates/admin/integrations/new.mako:9
5818 6061 #: rhodecode/templates/admin/integrations/new.mako:13
5819 6062 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:30
5820 6063 #: rhodecode/templates/admin/repos/repo_edit.mako:15
5821 6064 #: rhodecode/templates/admin/repos/repo_edit.mako:42
5822 6065 #: rhodecode/templates/admin/settings/settings.mako:14
5823 6066 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:34
6067 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:9
5824 6068 #: rhodecode/templates/base/base.mako:115
5825 6069 msgid "Settings"
5826 6070 msgstr ""
5827 6071
5828 6072 #: rhodecode/templates/admin/integrations/form.mako:60
5829 6073 #, python-format
5830 6074 msgid "Create New %(integration_type)s Integration"
5831 6075 msgstr ""
5832 6076
5833 6077 #: rhodecode/templates/admin/integrations/global.mako:5
5834 6078 msgid "Integrations administration"
5835 6079 msgstr ""
5836 6080
5837 6081 #: rhodecode/templates/admin/integrations/list.mako:44
5838 6082 msgid "Current Integrations for Repository: {repo_name}"
5839 6083 msgstr ""
5840 6084
5841 6085 #: rhodecode/templates/admin/integrations/list.mako:46
5842 6086 msgid "Repository Group Integrations: {}"
5843 6087 msgstr ""
5844 6088
5845 6089 #: rhodecode/templates/admin/integrations/list.mako:48
5846 6090 msgid "Current Integrations"
5847 6091 msgstr ""
5848 6092
5849 6093 #: rhodecode/templates/admin/integrations/list.mako:65
5850 6094 #: rhodecode/templates/admin/integrations/new.mako:18
5851 6095 msgid "Create new integration"
5852 6096 msgstr ""
5853 6097
5854 6098 #: rhodecode/templates/admin/integrations/list.mako:74
5855 6099 msgid "Scope"
5856 6100 msgstr ""
5857 6101
5858 6102 #: rhodecode/templates/admin/integrations/list.mako:75
5859 6103 #: rhodecode/templates/compare/compare_diff.mako:84
5860 6104 msgid "Actions"
5861 6105 msgstr ""
5862 6106
5863 6107 #: rhodecode/templates/admin/integrations/list.mako:85
5864 6108 msgid "No {type} integrations for repo {repo} exist yet."
5865 6109 msgstr ""
5866 6110
5867 6111 #: rhodecode/templates/admin/integrations/list.mako:87
5868 6112 msgid "No {type} integrations for repogroup {repogroup} exist yet."
5869 6113 msgstr ""
5870 6114
5871 6115 #: rhodecode/templates/admin/integrations/list.mako:89
5872 6116 msgid "No {type} integrations exist yet."
5873 6117 msgstr ""
5874 6118
5875 6119 #: rhodecode/templates/admin/integrations/list.mako:103
5876 6120 msgid "Create one"
5877 6121 msgstr ""
5878 6122
5879 6123 #: rhodecode/templates/admin/integrations/list.mako:132
5880 6124 #: rhodecode/templates/hovercards/hovercard_pull_request.mako:19
5881 6125 msgid "repo"
5882 6126 msgstr ""
5883 6127
5884 6128 #: rhodecode/templates/admin/integrations/list.mako:136
5885 6129 msgid "repogroup"
5886 6130 msgstr ""
5887 6131
5888 6132 #: rhodecode/templates/admin/integrations/list.mako:138
5889 6133 msgid "child repos only"
5890 6134 msgstr ""
5891 6135
5892 6136 #: rhodecode/templates/admin/integrations/list.mako:140
5893 6137 msgid "cascade to all"
5894 6138 msgstr ""
5895 6139
5896 6140 #: rhodecode/templates/admin/integrations/list.mako:145
5897 6141 msgid "top level repos only"
5898 6142 msgstr ""
5899 6143
5900 6144 #: rhodecode/templates/admin/integrations/list.mako:147
5901 6145 msgid "global"
5902 6146 msgstr ""
5903 6147
5904 6148 #: rhodecode/templates/admin/integrations/list.mako:153
5905 6149 msgid "unknown integration"
5906 6150 msgstr ""
5907 6151
5908 6152 #: rhodecode/templates/admin/integrations/new.mako:23
5909 6153 msgid "Create New Integration for repository: {repo_name}"
5910 6154 msgstr ""
5911 6155
5912 6156 #: rhodecode/templates/admin/integrations/new.mako:25
5913 6157 msgid "Create New Integration for repository group: {repo_group_name}"
5914 6158 msgstr ""
5915 6159
5916 6160 #: rhodecode/templates/admin/integrations/new.mako:27
5917 6161 msgid "Create New Global Integration"
5918 6162 msgstr ""
5919 6163
5920 6164 #: rhodecode/templates/admin/integrations/new.mako:55
5921 6165 msgid "No description available"
5922 6166 msgstr ""
5923 6167
5924 6168 #: rhodecode/templates/admin/my_account/my_account.mako:5
5925 #: rhodecode/templates/base/base.mako:617
6169 #: rhodecode/templates/base/base.mako:613
5926 6170 msgid "My account"
5927 6171 msgstr ""
5928 6172
5929 6173 #: rhodecode/templates/admin/my_account/my_account.mako:12
5930 6174 msgid "My Account"
5931 6175 msgstr ""
5932 6176
5933 6177 #: rhodecode/templates/admin/my_account/my_account.mako:29
5934 6178 #: rhodecode/templates/email_templates/user_registration.mako:54
5935 6179 msgid "Profile"
5936 6180 msgstr ""
5937 6181
5938 6182 #: rhodecode/templates/admin/my_account/my_account.mako:30
5939 6183 #: rhodecode/templates/admin/users/user_edit.mako:45
5940 6184 #: rhodecode/templates/debug_style/index.html:55
5941 6185 msgid "Emails"
5942 6186 msgstr ""
5943 6187
5944 6188 #: rhodecode/templates/admin/my_account/my_account.mako:33
5945 6189 msgid "Auth Tokens"
5946 6190 msgstr ""
5947 6191
5948 6192 #: rhodecode/templates/admin/my_account/my_account.mako:34
5949 6193 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:3
5950 6194 #: rhodecode/templates/admin/permissions/permissions.mako:51
5951 6195 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:4
5952 6196 #: rhodecode/templates/admin/users/user_edit.mako:41
5953 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:3
6197 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:7
5954 6198 msgid "SSH Keys"
5955 6199 msgstr ""
5956 6200
5957 6201 #: rhodecode/templates/admin/my_account/my_account.mako:35
5958 6202 #: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:5
5959 6203 msgid "User Group Membership"
5960 6204 msgstr ""
5961 6205
5962 6206 #: rhodecode/templates/admin/my_account/my_account.mako:40
5963 6207 msgid "External Identities"
5964 6208 msgstr ""
5965 6209
5966 6210 #: rhodecode/templates/admin/my_account/my_account.mako:43
5967 6211 msgid "Owned Repositories"
5968 6212 msgstr ""
5969 6213
5970 6214 #: rhodecode/templates/admin/my_account/my_account.mako:44
5971 6215 msgid "Watched Repositories"
5972 6216 msgstr ""
5973 6217
5974 6218 #: rhodecode/templates/admin/my_account/my_account.mako:45
5975 6219 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:42
5976 6220 #: rhodecode/templates/base/base.mako:376
5977 #: rhodecode/templates/base/base.mako:621
6221 #: rhodecode/templates/base/base.mako:617
5978 6222 msgid "Pull Requests"
5979 6223 msgstr ""
5980 6224
5981 6225 #: rhodecode/templates/admin/my_account/my_account.mako:46
5982 6226 #: rhodecode/templates/admin/permissions/permissions.mako:14
5983 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:31
5984 6227 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:35
5985 6228 #: rhodecode/templates/base/base.mako:111
5986 6229 msgid "Permissions"
5987 6230 msgstr ""
5988 6231
5989 6232 #: rhodecode/templates/admin/my_account/my_account.mako:47
5990 6233 msgid "Live Notifications"
5991 6234 msgstr ""
5992 6235
5993 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:3
5994 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:3
6236 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:9
6237 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:13
5995 6238 msgid "Authentication Tokens"
5996 6239 msgstr ""
5997 6240
5998 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:8
5999 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:8
6000 msgid "Authentication tokens can be used to interact with the API, or VCS-over-http. Each token can have a role. Token with a role can be used only in given context, e.g. VCS tokens can be used together with the authtoken auth plugin for git/hg/svn operations only."
6001 msgstr ""
6002
6003 6241 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:14
6004 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:14
6242 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:19
6243 msgid "Authentication tokens can be used to interact with the API, or VCS-over-http. Each token can have a role. Token with a role can be used only in given context, e.g. VCS tokens can be used together with the authtoken auth plugin for git/hg/svn operations only."
6244 msgstr ""
6245
6246 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:20
6247 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:25
6005 6248 msgid "Token"
6006 6249 msgstr ""
6007 6250
6008 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:17
6009 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:17
6251 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:23
6252 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:28
6010 6253 msgid "Repository Scope"
6011 6254 msgstr ""
6012 6255
6013 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:18
6014 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:18
6256 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:24
6257 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:29
6015 6258 msgid "Expiration"
6016 6259 msgstr ""
6017 6260
6018 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:49
6019 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:49
6020 #, python-format
6021 msgid "Confirm to remove this auth token: %s"
6022 msgstr ""
6023
6024 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:57
6025 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:57
6261 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:66
6262 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:70
6026 6263 msgid "No additional auth tokens specified"
6027 6264 msgstr ""
6028 6265
6029 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:69
6030 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:69
6266 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:78
6267 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:82
6031 6268 msgid "New authentication token"
6032 6269 msgstr ""
6033 6270
6034 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:83
6035 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:83
6271 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:92
6272 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:96
6036 6273 msgid "Repository scope works only with tokens with VCS type."
6037 6274 msgstr ""
6038 6275
6039 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:87
6040 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:71
6276 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:96
6277 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:72
6041 6278 #: rhodecode/templates/admin/permissions/permissions_ips.mako:63
6042 6279 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:65
6043 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:87
6044 #: rhodecode/templates/admin/users/user_edit_emails.mako:62
6045 #: rhodecode/templates/admin/users/user_edit_ips.mako:70
6046 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:66
6280 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:100
6281 #: rhodecode/templates/admin/users/user_edit_emails.mako:65
6282 #: rhodecode/templates/admin/users/user_edit_ips.mako:75
6283 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:71
6047 6284 msgid "Add"
6048 6285 msgstr ""
6049 6286
6050 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:120
6051 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:121
6287 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:129
6288 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:134
6052 6289 msgid "Select or enter expiration date"
6053 6290 msgstr ""
6054 6291
6055 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:155
6056 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:156
6292 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:164
6293 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:169
6057 6294 msgid "repository scope"
6058 6295 msgstr ""
6059 6296
6060 6297 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:7
6061 6298 msgid "Position"
6062 6299 msgstr ""
6063 6300
6064 6301 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:17
6065 6302 msgid "Bookmark title (max 30 characters, optional)"
6066 6303 msgstr ""
6067 6304
6068 6305 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:24
6069 6306 msgid "Clear"
6070 6307 msgstr ""
6071 6308
6072 6309 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:30
6073 6310 msgid "Server URL is available as ${server_url} variable. E.g. Redirect url: ${server_url}/_admin/exception_tracker"
6074 6311 msgstr ""
6075 6312
6076 6313 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:34
6077 6314 msgid "Redirect URL"
6078 6315 msgstr ""
6079 6316
6080 6317 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:44
6081 6318 msgid "Repository template"
6082 6319 msgstr ""
6083 6320
6084 6321 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:50
6085 6322 msgid "Repository group template"
6086 6323 msgstr ""
6087 6324
6088 6325 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:56
6089 6326 msgid "Template Repository or Repository group"
6090 6327 msgstr ""
6091 6328
6092 6329 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:66
6093 6330 msgid "Available as ${repo_url} e.g. Redirect url: ${repo_url}/changelog"
6094 6331 msgstr ""
6095 6332
6096 6333 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:68
6097 6334 msgid "Available as ${repo_group_url} e.g. Redirect url: ${repo_group_url}"
6098 6335 msgstr ""
6099 6336
6100 6337 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:70
6101 6338 msgid "Available as full url variables in redirect url. i.e: ${repo_url}, ${repo_group_url}."
6102 6339 msgstr ""
6103 6340
6104 6341 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:80
6105 6342 msgid "Your Bookmarks"
6106 6343 msgstr ""
6107 6344
6108 6345 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:85
6109 6346 msgid "Store upto 10 bookmark links to favorite repositories, external issue tracker or CI server. "
6110 6347 msgstr ""
6111 6348
6112 6349 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:87
6113 6350 msgid "Bookmarks are accessible from your username dropdown or by keyboard shortcut `g 0-9`"
6114 6351 msgstr ""
6115 6352
6116 6353 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:141
6117 6354 msgid "repository"
6118 6355 msgstr ""
6119 6356
6120 6357 #: rhodecode/templates/admin/my_account/my_account_bookmarks.mako:192
6121 6358 msgid "repository group"
6122 6359 msgstr ""
6123 6360
6124 6361 #: rhodecode/templates/admin/my_account/my_account_emails.mako:5
6125 6362 msgid "Account Emails"
6126 6363 msgstr ""
6127 6364
6128 6365 #: rhodecode/templates/admin/my_account/my_account_emails.mako:17
6129 #: rhodecode/templates/admin/users/user_edit_emails.mako:16
6366 #: rhodecode/templates/admin/users/user_edit_emails.mako:19
6130 6367 msgid "Primary"
6131 6368 msgstr ""
6132 6369
6133 #: rhodecode/templates/admin/my_account/my_account_emails.mako:31
6134 msgid "Confirm to delete this email: {}"
6135 msgstr ""
6136
6137 #: rhodecode/templates/admin/my_account/my_account_emails.mako:42
6138 #: rhodecode/templates/admin/users/user_edit_emails.mako:41
6370 #: rhodecode/templates/admin/my_account/my_account_emails.mako:43
6371 #: rhodecode/templates/admin/users/user_edit_emails.mako:44
6139 6372 msgid "No additional emails specified"
6140 6373 msgstr ""
6141 6374
6142 #: rhodecode/templates/admin/my_account/my_account_emails.mako:51
6143 #: rhodecode/templates/admin/my_account/my_account_password.mako:6
6144 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:17
6145 msgid "Your user account details are managed by an external source. Details cannot be managed here."
6146 msgstr ""
6147
6148 6375 #: rhodecode/templates/admin/my_account/my_account_emails.mako:52
6149 #: rhodecode/templates/admin/my_account/my_account_password.mako:7
6150 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:18
6376 #: rhodecode/templates/admin/my_account/my_account_password.mako:6
6377 msgid "Your user account details are managed by an external source. Details cannot be managed here."
6378 msgstr ""
6379
6380 #: rhodecode/templates/admin/my_account/my_account_emails.mako:53
6381 #: rhodecode/templates/admin/my_account/my_account_password.mako:9
6151 6382 msgid "Source type"
6152 6383 msgstr ""
6153 6384
6154 6385 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:4
6155 6386 msgid "Your Live Notification Settings"
6156 6387 msgstr ""
6157 6388
6158 6389 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:16
6159 6390 msgid "Notifications Status"
6160 6391 msgstr ""
6161 6392
6162 6393 #: rhodecode/templates/admin/my_account/my_account_notifications.mako:40
6163 6394 msgid "Test Notifications"
6164 6395 msgstr ""
6165 6396
6166 6397 #: rhodecode/templates/admin/my_account/my_account_password.mako:3
6167 6398 msgid "Change Your Account Password"
6168 6399 msgstr ""
6169 6400
6401 #: rhodecode/templates/admin/my_account/my_account_password.mako:7
6402 #: rhodecode/templates/admin/my_account/my_account_profile.mako:18
6403 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:19
6404 msgid "For VCS access please generate"
6405 msgstr ""
6406
6170 6407 #: rhodecode/templates/admin/my_account/my_account_profile.mako:6
6171 6408 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:4
6172 6409 msgid "My Profile"
6173 6410 msgstr ""
6174 6411
6175 #: rhodecode/templates/admin/my_account/my_account_profile.mako:13
6176 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:54
6177 #: rhodecode/templates/admin/users/user_edit_profile.mako:23
6412 #: rhodecode/templates/admin/my_account/my_account_profile.mako:15
6413 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:16
6414 #: rhodecode/templates/admin/users/user_edit_profile.mako:19
6415 #, python-format
6416 msgid "This user was created from external source (%s). Editing some of the settings is limited."
6417 msgstr ""
6418
6419 #: rhodecode/templates/admin/my_account/my_account_profile.mako:24
6420 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:60
6421 #: rhodecode/templates/admin/users/user_edit_profile.mako:26
6178 6422 #: rhodecode/templates/users/user_profile.mako:15
6179 6423 msgid "Photo"
6180 6424 msgstr ""
6181 6425
6182 #: rhodecode/templates/admin/my_account/my_account_profile.mako:71
6426 #: rhodecode/templates/admin/my_account/my_account_profile.mako:82
6183 6427 #: rhodecode/templates/users/user_profile.mako:73
6184 6428 msgid "Missing email, please update your user email address."
6185 6429 msgstr ""
6186 6430
6187 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:59
6431 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:65
6188 6432 msgid "Change your avatar at"
6189 6433 msgstr ""
6190 6434
6191 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:6
6192 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:8
6193 msgid "Show Closed Pull Requests"
6194 msgstr ""
6195
6196 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:15
6435 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:13
6436 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:40
6437 msgid "All"
6438 msgstr ""
6439
6440 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:14
6441 msgid "All + Closed"
6442 msgstr ""
6443
6444 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:33
6197 6445 msgid "Pull Requests You Participate In"
6198 6446 msgstr ""
6199 6447
6200 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:51
6448 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:67
6201 6449 msgid "Target Repo"
6202 6450 msgstr ""
6203 6451
6204 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:55
6452 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:79
6205 6453 #: rhodecode/templates/pullrequests/pullrequests.mako:94
6206 6454 msgid "Id"
6207 6455 msgstr ""
6208 6456
6209 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:57
6457 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:85
6210 6458 #: rhodecode/templates/admin/settings/settings_global.mako:9
6211 6459 #: rhodecode/templates/email_templates/pull_request_review.mako:41
6212 6460 #: rhodecode/templates/email_templates/pull_request_update.mako:41
6213 6461 #: rhodecode/templates/pullrequests/pullrequest.mako:38
6214 6462 #: rhodecode/templates/pullrequests/pullrequests.mako:96
6215 6463 msgid "Title"
6216 6464 msgstr ""
6217 6465
6218 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:63
6466 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:103
6219 6467 #: rhodecode/templates/pullrequests/pullrequests.mako:102
6220 6468 msgid "Last Update"
6221 6469 msgstr ""
6222 6470
6223 6471 #: rhodecode/templates/admin/my_account/my_account_repos.mako:3
6224 6472 msgid "Repositories You Own"
6225 6473 msgstr ""
6226 6474
6227 6475 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:9
6228 6476 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:47
6229 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:9
6477 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:14
6230 6478 msgid "Fingerprint"
6231 6479 msgstr ""
6232 6480
6233 6481 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:12
6234 6482 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:53
6235 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:12
6483 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:17
6236 6484 msgid "Accessed on"
6237 6485 msgstr ""
6238 6486
6239 6487 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:16
6240 6488 msgid "SSH Keys usage is currently disabled, please ask your administrator to enable them."
6241 6489 msgstr ""
6242 6490
6243 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:32
6244 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:29
6245 #, python-format
6246 msgid "Confirm to remove ssh key %s"
6247 msgstr ""
6248
6249 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:40
6250 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:37
6491 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:41
6492 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:42
6251 6493 msgid "No additional ssh keys specified"
6252 6494 msgstr ""
6253 6495
6254 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:54
6255 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:49
6496 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:55
6497 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:54
6256 6498 msgid "New ssh key"
6257 6499 msgstr ""
6258 6500
6259 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:59
6260 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:54
6501 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:60
6502 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:59
6261 6503 msgid "Generate random RSA key"
6262 6504 msgstr ""
6263 6505
6264 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:66
6265 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:61
6506 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:67
6507 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:66
6266 6508 msgid "Public key, begins with 'ssh-rsa', 'ssh-dss', 'ssh-ed25519', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', or 'ecdsa-sha2-nistp521'"
6267 6509 msgstr ""
6268 6510
6269 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:75
6511 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:76
6270 6512 msgid "Click add to use this generated SSH key"
6271 6513 msgstr ""
6272 6514
6273 6515 #: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:49
6274 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:47
6516 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:51
6275 6517 #: rhodecode/templates/admin/user_groups/user_group_add.mako:51
6276 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:51
6518 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:55
6277 6519 #: rhodecode/templates/admin/user_groups/user_groups.mako:84
6278 6520 #: rhodecode/templates/admin/users/user_add.mako:97
6279 #: rhodecode/templates/admin/users/user_edit_groups.mako:64
6280 #: rhodecode/templates/admin/users/user_edit_profile.mako:101
6521 #: rhodecode/templates/admin/users/user_edit_groups.mako:67
6522 #: rhodecode/templates/admin/users/user_edit_profile.mako:110
6281 6523 #: rhodecode/templates/admin/users/users.mako:85
6282 6524 #: rhodecode/templates/user_group/profile.mako:44
6283 6525 msgid "Active"
6284 6526 msgstr ""
6285 6527
6286 6528 #: rhodecode/templates/admin/my_account/my_account_watched.mako:3
6287 6529 msgid "Your Watched Repositories"
6288 6530 msgstr ""
6289 6531
6290 6532 #: rhodecode/templates/admin/notifications/notifications_data.mako:5
6291 6533 msgid "My notifications"
6292 6534 msgstr ""
6293 6535
6294 6536 #: rhodecode/templates/admin/notifications/notifications_data.mako:26
6295 6537 msgid "Mark as read"
6296 6538 msgstr ""
6297 6539
6298 6540 #: rhodecode/templates/admin/notifications/notifications_data.mako:42
6299 6541 msgid "No notifications here yet"
6300 6542 msgstr ""
6301 6543
6302 6544 #: rhodecode/templates/admin/notifications/notifications_show.mako:5
6303 6545 #: rhodecode/templates/admin/notifications/notifications_show.mako:14
6304 6546 #: rhodecode/templates/debug_style/email_plain_rendered.mako:5
6305 6547 #: rhodecode/templates/debug_style/email_plain_rendered.mako:14
6306 6548 msgid "Show notification"
6307 6549 msgstr ""
6308 6550
6309 6551 #: rhodecode/templates/admin/notifications/notifications_show.mako:12
6310 6552 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:5
6311 6553 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:20
6312 6554 #: rhodecode/templates/debug_style/email_plain_rendered.mako:12
6313 6555 msgid "My Notifications"
6314 6556 msgstr ""
6315 6557
6316 6558 #: rhodecode/templates/admin/notifications/notifications_show.mako:42
6317 6559 #: rhodecode/templates/debug_style/email_plain_rendered.mako:38
6318 6560 msgid "Subject"
6319 6561 msgstr ""
6320 6562
6321 6563 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:25
6322 6564 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:29
6323 6565 msgid "Mark all as read"
6324 6566 msgstr ""
6325 6567
6326 6568 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:39
6327 6569 msgid "Unread"
6328 6570 msgstr ""
6329 6571
6330 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:40
6331 msgid "All"
6332 msgstr ""
6333
6334 6572 #: rhodecode/templates/admin/notifications/notifications_show_all.mako:41
6335 6573 #: rhodecode/templates/changeset/changeset.mako:172
6336 #: rhodecode/templates/pullrequests/pullrequest_show.mako:656
6574 #: rhodecode/templates/pullrequests/pullrequest_show.mako:671
6337 6575 msgid "Comments"
6338 6576 msgstr ""
6339 6577
6340 6578 #: rhodecode/templates/admin/permissions/permissions.mako:5
6341 6579 msgid "Permissions Administration"
6342 6580 msgstr ""
6343 6581
6344 6582 #: rhodecode/templates/admin/permissions/permissions.mako:33
6345 6583 msgid "Application"
6346 6584 msgstr ""
6347 6585
6348 6586 #: rhodecode/templates/admin/permissions/permissions.mako:39
6349 6587 msgid "Object"
6350 6588 msgstr ""
6351 6589
6352 6590 #: rhodecode/templates/admin/permissions/permissions.mako:45
6353 6591 msgid "IP Whitelist"
6354 6592 msgstr ""
6355 6593
6356 6594 #: rhodecode/templates/admin/permissions/permissions.mako:48
6357 6595 msgid "AuthToken Access"
6358 6596 msgstr ""
6359 6597
6360 6598 #: rhodecode/templates/admin/permissions/permissions.mako:54
6361 6599 msgid "Overview"
6362 6600 msgstr ""
6363 6601
6364 6602 #: rhodecode/templates/admin/permissions/permissions_application.mako:3
6365 6603 msgid "System Wide Application Permissions"
6366 6604 msgstr ""
6367 6605
6368 6606 #: rhodecode/templates/admin/permissions/permissions_application.mako:12
6369 6607 msgid "Anonymous Access"
6370 6608 msgstr ""
6371 6609
6372 6610 #: rhodecode/templates/admin/permissions/permissions_application.mako:18
6373 6611 #, python-format
6374 6612 msgid "Allow access to RhodeCode Enterprise without requiring users to login. Anonymous users get the %s permission settings."
6375 6613 msgstr ""
6376 6614
6377 6615 #: rhodecode/templates/admin/permissions/permissions_application.mako:24
6378 6616 msgid "Registration"
6379 6617 msgstr ""
6380 6618
6381 6619 #: rhodecode/templates/admin/permissions/permissions_application.mako:33
6382 6620 msgid "Password Reset"
6383 6621 msgstr ""
6384 6622
6385 6623 #: rhodecode/templates/admin/permissions/permissions_application.mako:42
6386 6624 msgid "Registration Page Message"
6387 6625 msgstr ""
6388 6626
6389 6627 #: rhodecode/templates/admin/permissions/permissions_application.mako:46
6390 6628 msgid "Custom message to be displayed on the registration page. HTML syntax is supported."
6391 6629 msgstr ""
6392 6630
6393 6631 #: rhodecode/templates/admin/permissions/permissions_application.mako:52
6394 6632 msgid "External Authentication Account Activation"
6395 6633 msgstr ""
6396 6634
6397 6635 #: rhodecode/templates/admin/permissions/permissions_auth_token_access.mako:5
6398 6636 msgid "View whitelist"
6399 6637 msgstr ""
6400 6638
6401 6639 #: rhodecode/templates/admin/permissions/permissions_auth_token_access.mako:36
6402 6640 msgid "List of views available for usage in whitelist access"
6403 6641 msgstr ""
6404 6642
6405 6643 #: rhodecode/templates/admin/permissions/permissions_branch.mako:3
6406 6644 msgid "Default Permissions for Branches."
6407 6645 msgstr ""
6408 6646
6409 6647 #: rhodecode/templates/admin/permissions/permissions_branch.mako:6
6410 6648 #: rhodecode/templates/admin/repos/repo_edit_automation.mako:6
6411 6649 #: rhodecode/templates/admin/repos/repo_edit_permissions_branch.mako:6
6412 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:62
6650 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:67
6413 6651 #: rhodecode/templates/admin/repos/repo_edit_reviewers.mako:6
6414 6652 #: rhodecode/templates/admin/settings/settings_automation.mako:6
6415 6653 #: rhodecode/templates/artifacts/artifact_list.mako:24
6416 6654 msgid "This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license."
6417 6655 msgstr ""
6418 6656
6419 6657 #: rhodecode/templates/admin/permissions/permissions_ips.mako:5
6420 6658 msgid "Default IP Whitelist For All Users"
6421 6659 msgstr ""
6422 6660
6423 6661 #: rhodecode/templates/admin/permissions/permissions_ips.mako:9
6424 #: rhodecode/templates/admin/users/user_edit_ips.mako:7
6662 #: rhodecode/templates/admin/users/user_edit_ips.mako:12
6425 6663 msgid "Current IP address"
6426 6664 msgstr ""
6427 6665
6428 6666 #: rhodecode/templates/admin/permissions/permissions_ips.mako:30
6429 #: rhodecode/templates/admin/users/user_edit_ips.mako:36
6667 #: rhodecode/templates/admin/users/user_edit_ips.mako:41
6430 6668 #, python-format
6431 6669 msgid "Confirm to delete this ip: %s"
6432 6670 msgstr ""
6433 6671
6434 6672 #: rhodecode/templates/admin/permissions/permissions_ips.mako:37
6435 #: rhodecode/templates/admin/users/user_edit_ips.mako:44
6673 #: rhodecode/templates/admin/users/user_edit_ips.mako:49
6436 6674 msgid "All IP addresses are allowed"
6437 6675 msgstr ""
6438 6676
6439 6677 #: rhodecode/templates/admin/permissions/permissions_ips.mako:52
6440 #: rhodecode/templates/admin/users/user_edit_ips.mako:60
6678 #: rhodecode/templates/admin/users/user_edit_ips.mako:65
6441 6679 msgid "New IP Address"
6442 6680 msgstr ""
6443 6681
6444 6682 #: rhodecode/templates/admin/permissions/permissions_ips.mako:56
6445 #: rhodecode/templates/admin/users/user_edit_ips.mako:63
6683 #: rhodecode/templates/admin/users/user_edit_ips.mako:68
6446 6684 msgid "Description..."
6447 6685 msgstr ""
6448 6686
6449 6687 #: rhodecode/templates/admin/permissions/permissions_ips.mako:57
6450 6688 msgid ""
6451 6689 "Enter a comma separated list of IP Addresses like 127.0.0.1,\n"
6452 6690 "or use an IP Address with a mask 127.0.0.1/24, to create a network range.\n"
6453 6691 "To specify multiple addresses in a range, use the 127.0.0.1-127.0.0.10 syntax"
6454 6692 msgstr ""
6455 6693
6456 6694 #: rhodecode/templates/admin/permissions/permissions_objects.mako:3
6457 6695 msgid "Default Permissions for Repositories, User Groups and Repository Groups."
6458 6696 msgstr ""
6459 6697
6460 6698 #: rhodecode/templates/admin/permissions/permissions_objects.mako:7
6461 6699 msgid "Default access permissions. This defines permissions for the `default` user from which other users inherit permissions."
6462 6700 msgstr ""
6463 6701
6464 6702 #: rhodecode/templates/admin/permissions/permissions_objects.mako:9
6465 6703 msgid "Check the overwrite checkbox to force change all previously defined permissions for `default` user to the new selected value."
6466 6704 msgstr ""
6467 6705
6468 6706 #: rhodecode/templates/admin/permissions/permissions_objects.mako:23
6469 6707 msgid "All default permissions on each repository will be reset to chosen permission, note that all custom default permission on repositories will be lost"
6470 6708 msgstr ""
6471 6709
6472 6710 #: rhodecode/templates/admin/permissions/permissions_objects.mako:24
6473 6711 #: rhodecode/templates/admin/permissions/permissions_objects.mako:38
6474 6712 #: rhodecode/templates/admin/permissions/permissions_objects.mako:52
6475 6713 msgid "Overwrite Existing Settings"
6476 6714 msgstr ""
6477 6715
6478 6716 #: rhodecode/templates/admin/permissions/permissions_objects.mako:37
6479 6717 msgid "All default permissions on each repository group will be reset to chosen permission, note that all custom default permission on repository groups will be lost"
6480 6718 msgstr ""
6481 6719
6482 6720 #: rhodecode/templates/admin/permissions/permissions_objects.mako:45
6483 6721 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:14
6484 6722 msgid "User Groups"
6485 6723 msgstr ""
6486 6724
6487 6725 #: rhodecode/templates/admin/permissions/permissions_objects.mako:51
6488 6726 msgid "All default permissions on each user group will be reset to chosen permission, note that all custom default permission on user groups will be lost"
6489 6727 msgstr ""
6490 6728
6491 6729 #: rhodecode/templates/admin/permissions/permissions_perms.mako:1
6492 6730 msgid "Default User Permissions Overview"
6493 6731 msgstr ""
6494 6732
6495 6733 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:7
6496 6734 msgid "Update SSH keys file"
6497 6735 msgstr ""
6498 6736
6499 6737 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:5
6500 6738 msgid "Add repository group"
6501 6739 msgstr ""
6502 6740
6503 6741 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:14
6504 6742 #: rhodecode/templates/admin/users/user_edit_advanced.mako:13
6505 6743 #: rhodecode/templates/base/base.mako:108
6506 6744 #: rhodecode/templates/base/base.mako:129
6507 6745 msgid "Repository groups"
6508 6746 msgstr ""
6509 6747
6510 6748 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:35
6511 6749 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:15
6512 6750 #: rhodecode/templates/admin/user_groups/user_group_add.mako:34
6513 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:15
6751 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:19
6514 6752 msgid "Group name"
6515 6753 msgstr ""
6516 6754
6517 6755 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:44
6518 6756 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:25
6519 6757 #: rhodecode/templates/admin/repos/repo_add_base.mako:43
6520 6758 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:33
6521 #: rhodecode/templates/base/base.mako:666
6522 #: rhodecode/templates/data_table/_dt_elements.mako:215
6759 #: rhodecode/templates/base/base.mako:662
6760 #: rhodecode/templates/data_table/_dt_elements.mako:217
6523 6761 #: rhodecode/templates/forks/fork.mako:41
6524 6762 msgid "Repository group"
6525 6763 msgstr ""
6526 6764
6527 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:58
6528 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:62
6529 msgid "Plain text format with support of {metatags}"
6530 msgstr ""
6531
6532 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:68
6533 #: rhodecode/templates/admin/repos/repo_add_base.mako:80
6765 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:60
6766 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:64
6767 #: rhodecode/templates/admin/repos/repo_add_base.mako:90
6768 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:179
6769 #: rhodecode/templates/admin/users/user_edit_profile.mako:81
6770 #: rhodecode/templates/forks/fork.mako:63
6771 msgid "Plain text format with {metatags} support."
6772 msgstr ""
6773
6774 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:62
6775 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:66
6776 #: rhodecode/templates/admin/repos/repo_add_base.mako:92
6777 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:181
6778 #: rhodecode/templates/admin/users/user_edit_profile.mako:83
6779 #: rhodecode/templates/forks/fork.mako:65
6780 msgid "Plain text format."
6781 msgstr ""
6782
6783 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:74
6784 #: rhodecode/templates/admin/repos/repo_add_base.mako:104
6534 6785 msgid "Copy Parent Group Permissions"
6535 6786 msgstr ""
6536 6787
6537 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:72
6538 #: rhodecode/templates/admin/repos/repo_add_base.mako:84
6788 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:78
6789 #: rhodecode/templates/admin/repos/repo_add_base.mako:108
6539 6790 msgid "Copy permissions from parent repository group."
6540 6791 msgstr ""
6541 6792
6542 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:77
6793 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:83
6543 6794 msgid "Create Repository Group"
6544 6795 msgstr ""
6545 6796
6546 6797 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:5
6547 6798 #, python-format
6548 6799 msgid "%s repository group settings"
6549 6800 msgstr ""
6550 6801
6802 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:31
6803 #: rhodecode/templates/admin/repos/repo_edit.mako:45
6804 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:8
6805 #: rhodecode/templates/admin/users/user_edit_advanced.mako:30
6806 msgid "Access Permissions"
6807 msgstr ""
6808
6551 6809 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:32
6552 6810 #: rhodecode/templates/admin/repos/repo_edit.mako:51
6553 6811 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:36
6812 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:24
6554 6813 #: rhodecode/templates/admin/users/user_edit.mako:42
6555 6814 msgid "Advanced"
6556 6815 msgstr ""
6557 6816
6558 6817 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:7
6559 6818 msgid "Repository Group ID"
6560 6819 msgstr ""
6561 6820
6562 6821 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:10
6563 6822 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:8
6564 6823 msgid "Updated on"
6565 6824 msgstr ""
6566 6825
6567 6826 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:11
6568 6827 msgid "Cached Commit source"
6569 6828 msgstr ""
6570 6829
6571 6830 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:12
6572 6831 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:9
6573 6832 msgid "Cached Commit id"
6574 6833 msgstr ""
6575 6834
6576 6835 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:13
6577 6836 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:10
6578 6837 msgid "Cached Commit date"
6579 6838 msgstr ""
6580 6839
6581 6840 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:15
6582 6841 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:11
6583 6842 msgid "Cached Commit data"
6584 6843 msgstr ""
6585 6844
6586 6845 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:17
6587 6846 msgid "Is Personal Group"
6588 6847 msgstr ""
6589 6848
6590 6849 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:19
6591 6850 msgid "Total repositories"
6592 6851 msgstr ""
6593 6852
6594 6853 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:20
6595 6854 msgid "Top level repositories"
6596 6855 msgstr ""
6597 6856
6598 6857 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:22
6599 6858 msgid "Children groups"
6600 6859 msgstr ""
6601 6860
6602 6861 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:28
6603 6862 msgid "Repository Group Advanced: {}"
6604 6863 msgstr ""
6605 6864
6606 6865 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:38
6607 6866 msgid "Delete repository group"
6608 6867 msgstr ""
6609 6868
6610 6869 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:67
6611 6870 #, python-format
6612 6871 msgid "Confirm to delete this group: %s"
6613 6872 msgstr ""
6614 6873
6615 6874 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:68
6616 6875 msgid "Delete this repository group"
6617 6876 msgstr ""
6618 6877
6619 6878 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:5
6620 6879 msgid "Repository Group Permissions: {}"
6621 6880 msgstr ""
6622 6881
6623 6882 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:15
6624 6883 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:15
6625 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:15
6884 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:19
6626 6885 msgid "User/User Group"
6627 6886 msgstr ""
6628 6887
6629 6888 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:32
6630 6889 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:31
6631 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:33
6890 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:37
6632 6891 msgid "super-admin"
6633 6892 msgstr ""
6634 6893
6635 6894 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:35
6636 6895 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:34
6637 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:36
6896 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:40
6638 6897 msgid "owner"
6639 6898 msgstr ""
6640 6899
6641 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:64
6642 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:107
6643 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:86
6644 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:66
6645 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:109
6646 msgid "permission for all other users"
6900 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:66
6901 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:114
6902 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:92
6903 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:72
6904 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:120
6905 msgid "permission for other logged in and anonymous users"
6647 6906 msgstr ""
6648 6907
6649 6908 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:68
6650 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:111
6651 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:90
6652 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:70
6653 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:113
6909 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:116
6910 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:94
6911 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:74
6912 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:122
6913 msgid "permission for other logged in users"
6914 msgstr ""
6915
6916 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:73
6917 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:121
6918 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:99
6919 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:79
6920 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:127
6654 6921 msgid "inactive duplicate"
6655 6922 msgstr ""
6656 6923
6657 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:77
6658 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:157
6659 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:106
6660 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:155
6924 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:82
6925 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:167
6926 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:115
6927 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:164
6661 6928 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:46
6662 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:79
6663 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:158
6929 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:88
6930 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:172
6664 6931 msgid "Remove"
6665 6932 msgstr ""
6666 6933
6667 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:114
6668 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:116
6934 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:124
6935 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:130
6669 6936 msgid "delegated admin"
6670 6937 msgstr ""
6671 6938
6672 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:152
6673 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:150
6674 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:153
6939 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:162
6940 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:159
6941 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:167
6675 6942 msgid "members"
6676 6943 msgstr ""
6677 6944
6678 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:184
6679 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:182
6680 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:184
6681 msgid "Add user/user group"
6682 msgstr ""
6683
6684 6945 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:194
6946 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:191
6947 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:198
6948 msgid "Add user/user group"
6949 msgstr ""
6950
6951 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:204
6685 6952 msgid "Apply to children"
6686 6953 msgstr ""
6687 6954
6688 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:200
6955 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:210
6689 6956 msgid "Both"
6690 6957 msgstr ""
6691 6958
6692 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:201
6959 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:211
6693 6960 msgid "Set or revoke permissions to selected types of children of this group, including non-private repositories and other groups if chosen."
6694 6961 msgstr ""
6695 6962
6696 6963 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:6
6697 6964 msgid "Repository Group Settings: {}"
6698 6965 msgstr ""
6699 6966
6700 6967 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:31
6701 6968 msgid "Optional select a parent group to move this repository group into."
6702 6969 msgstr ""
6703 6970
6704 6971 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:49
6705 6972 msgid "Change owner of this repository group."
6706 6973 msgstr ""
6707 6974
6708 6975 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:5
6709 6976 msgid "Repository groups administration"
6710 6977 msgstr ""
6711 6978
6712 6979 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:82
6713 6980 msgid "Number of top level repositories"
6714 6981 msgstr ""
6715 6982
6716 6983 #: rhodecode/templates/admin/repos/repo_add.mako:5
6717 6984 msgid "Add repository"
6718 6985 msgstr ""
6719 6986
6720 6987 #: rhodecode/templates/admin/repos/repo_add_base.mako:9
6721 6988 msgid "Repository name"
6722 6989 msgstr ""
6723 6990
6724 6991 #: rhodecode/templates/admin/repos/repo_add_base.mako:14
6725 6992 msgid "Import Existing Repository ?"
6726 6993 msgstr ""
6727 6994
6728 6995 #: rhodecode/templates/admin/repos/repo_add_base.mako:23
6729 6996 #: rhodecode/templates/base/base.mako:323
6730 6997 msgid "Clone from"
6731 6998 msgstr ""
6732 6999
6733 7000 #: rhodecode/templates/admin/repos/repo_add_base.mako:49
6734 7001 #: rhodecode/templates/forks/fork.mako:47
6735 7002 #, python-format
6736 7003 msgid "Select my personal group (%(repo_group_name)s)"
6737 7004 msgstr ""
6738 7005
6739 7006 #: rhodecode/templates/admin/repos/repo_add_base.mako:52
6740 7007 #: rhodecode/templates/forks/fork.mako:50
6741 7008 msgid "Optionally select a group to put this repository into."
6742 7009 msgstr ""
6743 7010
6744 #: rhodecode/templates/admin/repos/repo_add_base.mako:61
7011 #: rhodecode/templates/admin/repos/repo_add_base.mako:78
6745 7012 msgid "Set the type of repository to create."
6746 7013 msgstr ""
6747 7014
6748 #: rhodecode/templates/admin/repos/repo_add_base.mako:71
6749 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:177
6750 #: rhodecode/templates/admin/users/user_edit_profile.mako:76
6751 #: rhodecode/templates/forks/fork.mako:61
6752 msgid "Plain text format with support of {metatags}. Add a README file for longer descriptions"
6753 msgstr ""
6754
6755 #: rhodecode/templates/admin/repos/repo_add_base.mako:97
7015 #: rhodecode/templates/admin/repos/repo_add_base.mako:94
7016 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:183
7017 #: rhodecode/templates/forks/fork.mako:67
7018 msgid "Add a README file for longer descriptions"
7019 msgstr ""
7020
7021 #: rhodecode/templates/admin/repos/repo_add_base.mako:121
6756 7022 msgid "Create Repository"
6757 7023 msgstr ""
6758 7024
6759 7025 #: rhodecode/templates/admin/repos/repo_creating.mako:5
6760 7026 msgid "{} Creating repository"
6761 7027 msgstr ""
6762 7028
6763 7029 #: rhodecode/templates/admin/repos/repo_creating.mako:12
6764 7030 msgid "Creating repository"
6765 7031 msgstr ""
6766 7032
6767 7033 #: rhodecode/templates/admin/repos/repo_creating.mako:26
6768 7034 #, python-format
6769 7035 msgid "Repository \"%(repo_name)s\" is being created, you will be redirected when this process is finished.repo_name"
6770 7036 msgstr ""
6771 7037
6772 7038 #: rhodecode/templates/admin/repos/repo_edit.mako:8
6773 7039 msgid "{} repository settings"
6774 7040 msgstr ""
6775 7041
6776 #: rhodecode/templates/admin/repos/repo_edit.mako:45
6777 msgid "Access Permissions"
6778 msgstr ""
6779
6780 7042 #: rhodecode/templates/admin/repos/repo_edit.mako:48
6781 7043 msgid "Branch Permissions"
6782 7044 msgstr ""
6783 7045
6784 7046 #: rhodecode/templates/admin/repos/repo_edit.mako:54
6785 7047 msgid "VCS"
6786 7048 msgstr ""
6787 7049
6788 7050 #: rhodecode/templates/admin/repos/repo_edit.mako:57
6789 7051 msgid "Extra Fields"
6790 7052 msgstr ""
6791 7053
6792 7054 #: rhodecode/templates/admin/repos/repo_edit.mako:60
6793 7055 msgid "Issue Tracker"
6794 7056 msgstr ""
6795 7057
6796 7058 #: rhodecode/templates/admin/repos/repo_edit.mako:63
6797 7059 #: rhodecode/templates/admin/users/user_edit.mako:49
6798 #: rhodecode/templates/admin/users/user_edit_caches.mako:5
7060 #: rhodecode/templates/admin/users/user_edit_caches.mako:7
6799 7061 msgid "Caches"
6800 7062 msgstr ""
6801 7063
6802 7064 #: rhodecode/templates/admin/repos/repo_edit.mako:67
6803 7065 msgid "Remote sync"
6804 7066 msgstr ""
6805 7067
6806 7068 #: rhodecode/templates/admin/repos/repo_edit.mako:71
6807 7069 msgid "Statistics"
6808 7070 msgstr ""
6809 7071
6810 7072 #: rhodecode/templates/admin/repos/repo_edit.mako:78
6811 7073 msgid "Reviewer Rules"
6812 7074 msgstr ""
6813 7075
6814 7076 #: rhodecode/templates/admin/repos/repo_edit.mako:82
6815 7077 msgid "Automation"
6816 7078 msgstr ""
6817 7079
6818 7080 #: rhodecode/templates/admin/repos/repo_edit.mako:85
6819 7081 #: rhodecode/templates/admin/repos/repo_edit_maintenance.mako:3
6820 7082 msgid "Maintenance"
6821 7083 msgstr ""
6822 7084
6823 7085 #: rhodecode/templates/admin/repos/repo_edit.mako:88
6824 7086 msgid "Strip"
6825 7087 msgstr ""
6826 7088
6827 7089 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:5
6828 7090 msgid "Repository ID"
6829 7091 msgstr ""
6830 7092
6831 7093 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:12
6832 7094 msgid "Attached scoped tokens"
6833 7095 msgstr ""
6834 7096
6835 7097 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:13
6836 7098 msgid "Pull requests source"
6837 7099 msgstr ""
6838 7100
6839 7101 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:14
6840 7102 msgid "Pull requests target"
6841 7103 msgstr ""
6842 7104
6843 7105 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:15
6844 7106 msgid "Attached Artifacts"
6845 7107 msgstr ""
6846 7108
6847 7109 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:21
6848 7110 #, python-format
6849 7111 msgid "Repository: %s"
6850 7112 msgstr ""
6851 7113
6852 7114 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:31
6853 7115 msgid "Fork Reference"
6854 7116 msgstr ""
6855 7117
6856 7118 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:37
6857 7119 #, python-format
6858 7120 msgid "This repository is a fork of %(repo_link)s"
6859 7121 msgstr ""
6860 7122
6861 7123 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:43
6862 7124 msgid "Set"
6863 7125 msgstr ""
6864 7126
6865 7127 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:46
6866 7128 msgid "Manually set this repository as a fork of another from the list"
6867 7129 msgstr ""
6868 7130
6869 7131 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:55
6870 7132 msgid "Public Journal Visibility"
6871 7133 msgstr ""
6872 7134
6873 7135 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:62
6874 7136 msgid "Remove from Public Journal"
6875 7137 msgstr ""
6876 7138
6877 7139 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:66
6878 7140 msgid "Add to Public Journal"
6879 7141 msgstr ""
6880 7142
6881 7143 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:71
6882 7144 msgid "All actions made on this repository will be visible to everyone following the public journal."
6883 7145 msgstr ""
6884 7146
6885 7147 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:80
6886 7148 msgid "Locking state"
6887 7149 msgstr ""
6888 7150
6889 7151 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:89
6890 7152 msgid "This Repository is not currently locked."
6891 7153 msgstr ""
6892 7154
6893 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:96
6894 msgid "Confirm to unlock repository."
6895 msgstr ""
6896
6897 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:98
7155 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:99
6898 7156 msgid "Unlock repository"
6899 7157 msgstr ""
6900 7158
6901 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:103
6902 msgid "Confirm to lock repository."
6903 msgstr ""
6904
6905 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:105
7159 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:107
6906 7160 msgid "Lock repository"
6907 7161 msgstr ""
6908 7162
6909 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:111
7163 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:113
6910 7164 msgid "Force repository locking. This only works when anonymous access is disabled. Pulling from the repository locks the repository to that user until the same user pushes to that repository again."
6911 7165 msgstr ""
6912 7166
6913 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:121
7167 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:123
6914 7168 msgid "Hooks"
6915 7169 msgstr ""
6916 7170
6917 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:125
6918 msgid "Hook type"
6919 msgstr ""
6920
6921 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:126
6922 msgid "Hook version"
6923 msgstr ""
6924
6925 7171 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:127
7172 msgid "Hook type"
7173 msgstr ""
7174
7175 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:128
7176 msgid "Hook version"
7177 msgstr ""
7178
7179 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:129
6926 7180 msgid "Current version"
6927 7181 msgstr ""
6928 7182
6929 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:130
7183 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:132
6930 7184 msgid "PRE HOOK"
6931 7185 msgstr ""
6932 7186
6933 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:135
7187 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:137
6934 7188 msgid "POST HOOK"
6935 7189 msgstr ""
6936 7190
6937 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:141
7191 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:143
6938 7192 msgid "Unable to read hook information from VCS Server"
6939 7193 msgstr ""
6940 7194
6941 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:147
7195 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:149
6942 7196 msgid "Confirm to reinstall hooks for this repository."
6943 7197 msgstr ""
6944 7198
6945 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:148
7199 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:150
6946 7200 msgid "Update Hooks"
6947 7201 msgstr ""
6948 7202
6949 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:155
7203 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:154
7204 msgid "Outdated hooks detected, please update hooks using `Update Hooks` action."
7205 msgstr ""
7206
7207 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:162
6950 7208 msgid "Archive repository"
6951 7209 msgstr ""
6952 7210
6953 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:164
6954 #, python-format
6955 msgid "Confirm to archive this repository: %s"
6956 msgstr ""
6957
6958 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:165
7211 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:173
6959 7212 msgid "Archive this repository"
6960 7213 msgstr ""
6961 7214
6962 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:170
7215 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:178
6963 7216 msgid "Archiving the repository will make it entirely read-only. The repository cannot be committed to.It is hidden from the search results and dashboard. "
6964 7217 msgstr ""
6965 7218
6966 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:182
7219 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:190
6967 7220 msgid "Delete repository"
6968 7221 msgstr ""
6969 7222
6970 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:193
7223 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:201
6971 7224 msgid "Detach forks"
6972 7225 msgstr ""
6973 7226
6974 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:198
7227 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:206
6975 7228 msgid "Delete forks"
6976 7229 msgstr ""
6977 7230
6978 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:208
7231 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:216
6979 7232 msgid "Consider to archive this repository instead."
6980 7233 msgstr ""
6981 7234
6982 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:219
6983 #: rhodecode/templates/data_table/_dt_elements.mako:180
6984 #, python-format
6985 msgid "Confirm to delete this repository: %s"
6986 msgstr ""
6987
6988 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:220
7235 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:229
6989 7236 msgid "Delete this repository"
6990 7237 msgstr ""
6991 7238
6992 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:225
7239 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:234
6993 7240 msgid "This repository will be renamed in a special way in order to make it inaccessible to RhodeCode Enterprise and its VCS systems. If you need to fully delete it from the file system, please do it manually, or with rhodecode-cleanup-repos command available in rhodecode-tools."
6994 7241 msgstr ""
6995 7242
6996 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:259
7243 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:268
6997 7244 msgid "Change repository"
6998 7245 msgstr ""
6999 7246
7000 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:259
7247 #: rhodecode/templates/admin/repos/repo_edit_advanced.mako:268
7001 7248 msgid "Pick repository"
7002 7249 msgstr ""
7003 7250
7004 7251 #: rhodecode/templates/admin/repos/repo_edit_audit.mako:7
7005 7252 msgid "Repository Audit Logs"
7006 7253 msgstr ""
7007 7254
7008 7255 #: rhodecode/templates/admin/repos/repo_edit_audit.mako:14
7009 #: rhodecode/templates/admin/users/user_edit_audit.mako:15
7256 #: rhodecode/templates/admin/users/user_edit_audit.mako:17
7010 7257 msgid "audit filter..."
7011 7258 msgstr ""
7012 7259
7013 7260 #: rhodecode/templates/admin/repos/repo_edit_automation.mako:3
7014 7261 msgid "Repo Automation"
7015 7262 msgstr ""
7016 7263
7017 7264 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:3
7018 7265 msgid "Invalidate Cache for Repository"
7019 7266 msgstr ""
7020 7267
7021 7268 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:7
7022 7269 msgid "Manually invalidate the repository cache. On the next access a repository cache will be recreated."
7023 7270 msgstr ""
7024 7271
7025 7272 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:10
7026 7273 msgid "Cache purge can be automated by such api call. Can be called periodically in crontab etc."
7027 7274 msgstr ""
7028 7275
7029 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:20
7276 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:23
7030 7277 msgid "Invalidate repository cache"
7031 7278 msgstr ""
7032 7279
7033 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:20
7034 msgid "Confirm to invalidate repository cache"
7035 msgstr ""
7036
7037 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:32
7280 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:36
7038 7281 msgid "Invalidation keys"
7039 7282 msgstr ""
7040 7283
7041 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:40
7042 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:84
7043 #: rhodecode/templates/admin/users/user_edit_caches.mako:19
7044 msgid "Show all"
7045 msgstr ""
7046
7047 7284 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:44
7048 7285 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:88
7286 #: rhodecode/templates/admin/users/user_edit_caches.mako:22
7287 msgid "Show all"
7288 msgstr ""
7289
7290 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:48
7291 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:92
7049 7292 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:11
7050 7293 msgid "Key"
7051 7294 msgstr ""
7052 7295
7053 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:45
7296 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:49
7054 7297 msgid "State UID"
7055 7298 msgstr ""
7056 7299
7057 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:46
7300 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:50
7058 7301 msgid "Namespace"
7059 7302 msgstr ""
7060 7303
7061 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:65
7304 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:69
7062 7305 msgid "Cache keys"
7063 7306 msgstr ""
7064 7307
7065 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:89
7308 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:93
7066 7309 msgid "Region"
7067 7310 msgstr ""
7068 7311
7069 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:106
7312 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:110
7070 7313 msgid "Shadow Repositories"
7071 7314 msgstr ""
7072 7315
7073 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:118
7316 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:122
7074 7317 msgid "No Shadow repositories exist for this repository."
7075 7318 msgstr ""
7076 7319
7077 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:129
7320 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:133
7078 7321 msgid "Diff Caches"
7079 7322 msgstr ""
7080 7323
7081 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:137
7324 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:141
7082 7325 msgid "Cached diff name"
7083 7326 msgstr ""
7084 7327
7085 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:145
7086 msgid "Cached diff files"
7087 msgstr ""
7088
7089 7328 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:149
7329 msgid "Cached diff files"
7330 msgstr ""
7331
7332 #: rhodecode/templates/admin/repos/repo_edit_caches.mako:153
7090 7333 msgid "Cached diff size"
7091 7334 msgstr ""
7092 7335
7093 7336 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:3
7094 7337 msgid "Custom extra fields for this repository"
7095 7338 msgstr ""
7096 7339
7097 7340 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:10
7098 7341 msgid "Label"
7099 7342 msgstr ""
7100 7343
7101 7344 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:24
7102 7345 #, python-format
7103 7346 msgid "Confirm to delete this field: %s"
7104 7347 msgstr ""
7105 7348
7106 7349 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:40
7107 7350 msgid "New Field Key"
7108 7351 msgstr ""
7109 7352
7110 7353 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:48
7111 7354 msgid "New Field Label"
7112 7355 msgstr ""
7113 7356
7114 7357 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:51
7115 7358 msgid "Enter short label"
7116 7359 msgstr ""
7117 7360
7118 7361 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:57
7119 7362 msgid "New Field Description"
7120 7363 msgstr ""
7121 7364
7122 7365 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:60
7123 7366 msgid "Enter a full description for the field"
7124 7367 msgstr ""
7125 7368
7126 7369 #: rhodecode/templates/admin/repos/repo_edit_fields.mako:73
7127 7370 msgid "Extra fields are disabled. You can enable them from the Admin/Settings/Visual page."
7128 7371 msgstr ""
7129 7372
7130 7373 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:9
7131 7374 #: rhodecode/templates/admin/repos/repo_edit_vcs.mako:9
7132 7375 msgid "Inherit from global settings"
7133 7376 msgstr ""
7134 7377
7135 7378 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:14
7136 7379 msgid "Select to inherit global patterns for issue tracker."
7137 7380 msgstr ""
7138 7381
7139 7382 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:24
7140 7383 msgid "Inherited Issue Tracker Patterns"
7141 7384 msgstr ""
7142 7385
7143 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:30
7386 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:31
7144 7387 #: rhodecode/templates/base/issue_tracker_settings.mako:79
7145 7388 #: rhodecode/templates/base/perms_summary.mako:169
7146 7389 msgid "Pattern"
7147 7390 msgstr ""
7148 7391
7149 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:31
7392 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:32
7150 7393 #: rhodecode/templates/base/issue_tracker_settings.mako:80
7151 7394 msgid "Url"
7152 7395 msgstr ""
7153 7396
7154 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:32
7397 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:33
7155 7398 msgid "Prefix"
7156 7399 msgstr ""
7157 7400
7158 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:70
7401 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:75
7159 7402 #: rhodecode/templates/admin/settings/settings_issuetracker.mako:5
7160 7403 msgid "Issue Tracker / Wiki Patterns"
7161 7404 msgstr ""
7162 7405
7163 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:91
7406 #: rhodecode/templates/admin/repos/repo_edit_issuetracker.mako:95
7164 7407 #: rhodecode/templates/admin/settings/settings_issuetracker.mako:24
7165 7408 msgid "Test Patterns"
7166 7409 msgstr ""
7167 7410
7168 7411 #: rhodecode/templates/admin/repos/repo_edit_maintenance.mako:8
7169 7412 msgid "Perform maintenance tasks for this repo"
7170 7413 msgstr ""
7171 7414
7172 7415 #: rhodecode/templates/admin/repos/repo_edit_maintenance.mako:10
7173 7416 msgid "Following tasks will be performed"
7174 7417 msgstr ""
7175 7418
7176 7419 #: rhodecode/templates/admin/repos/repo_edit_maintenance.mako:17
7177 7420 msgid "Maintenance can be automated by such api call. Can be called periodically in crontab etc."
7178 7421 msgstr ""
7179 7422
7180 7423 #: rhodecode/templates/admin/repos/repo_edit_maintenance.mako:25
7181 7424 msgid "No maintenance tasks for this repo available"
7182 7425 msgstr ""
7183 7426
7184 7427 #: rhodecode/templates/admin/repos/repo_edit_maintenance.mako:34
7185 7428 msgid "Run Maintenance"
7186 7429 msgstr ""
7187 7430
7188 7431 #: rhodecode/templates/admin/repos/repo_edit_maintenance.mako:49
7189 7432 msgid "Performing Maintenance"
7190 7433 msgstr ""
7191 7434
7192 7435 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:5
7193 7436 msgid "Repository Access Permissions"
7194 7437 msgstr ""
7195 7438
7196 7439 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:55
7197 7440 msgid "private repository"
7198 7441 msgstr ""
7199 7442
7200 7443 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:60
7201 7444 msgid "only users/user groups explicitly added here will have access"
7202 7445 msgstr ""
7203 7446
7204 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:94
7447 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:62
7448 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:118
7449 msgid "Private repositories are only visible to people explicitly added as collaborators. Default permissions wont apply"
7450 msgstr ""
7451
7452 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:63
7453 msgid "un-set private mode"
7454 msgstr ""
7455
7456 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:103
7205 7457 msgid "used by {} branch rule, requires write+ permissions"
7206 7458 msgstr ""
7207 7459
7208 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:96
7460 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:105
7209 7461 msgid "used by {} branch rules, requires write+ permissions"
7210 7462 msgstr ""
7211 7463
7212 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:110
7464 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:119
7213 7465 msgid "set private mode"
7214 7466 msgstr ""
7215 7467
7216 7468 #: rhodecode/templates/admin/repos/repo_edit_permissions_branch.mako:3
7217 7469 msgid "Repository Branch Permissions."
7218 7470 msgstr ""
7219 7471
7220 7472 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:3
7221 7473 msgid "Remote Sync"
7222 7474 msgstr ""
7223 7475
7224 7476 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:7
7225 7477 msgid "Manually pull/push changes from/to external URLs."
7226 7478 msgstr ""
7227 7479
7228 7480 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:11
7229 7481 msgid "Pull url"
7230 7482 msgstr ""
7231 7483
7232 7484 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:16
7233 7485 msgid "This repository does not have any pull url set."
7234 7486 msgstr ""
7235 7487
7236 7488 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:17
7237 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:55
7489 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:60
7238 7490 msgid "Set remote url."
7239 7491 msgstr ""
7240 7492
7241 7493 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:26
7242 7494 msgid "Pull can be automated by such api call. Can be called periodically in crontab etc."
7243 7495 msgstr ""
7244 7496
7245 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:40
7497 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:44
7246 7498 msgid "Pull changes from remote location"
7247 7499 msgstr ""
7248 7500
7249 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:40
7250 msgid "Confirm to pull changes from remote side"
7251 msgstr ""
7252
7253 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:49
7254 msgid "Push url"
7255 msgstr ""
7256
7257 7501 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:54
7502 msgid "Push url"
7503 msgstr ""
7504
7505 #: rhodecode/templates/admin/repos/repo_edit_remote.mako:59
7258 7506 msgid "This repository does not have any push url set."
7259 7507 msgstr ""
7260 7508
7261 7509 #: rhodecode/templates/admin/repos/repo_edit_reviewers.mako:3
7262 7510 msgid "Default Reviewer Rules"
7263 7511 msgstr ""
7264 7512
7265 7513 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:6
7266 7514 #, python-format
7267 7515 msgid "Settings for Repository: %s"
7268 7516 msgstr ""
7269 7517
7270 7518 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:22
7271 7519 msgid "permalink id"
7272 7520 msgstr ""
7273 7521
7274 7522 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:22
7275 7523 msgid "what is that ?"
7276 7524 msgstr ""
7277 7525
7278 7526 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:24
7279 7527 msgid "URL by id"
7280 7528 msgstr ""
7281 7529
7282 7530 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:25
7283 7531 msgid ""
7284 7532 "In case this repository is renamed or moved into another group the repository url changes.\n"
7285 7533 " Using above url guarantees that this repository will always be accessible under such url.\n"
7286 7534 " Useful for CI systems, or any other cases that you need to hardcode the url into 3rd party service."
7287 7535 msgstr ""
7288 7536
7289 7537 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:41
7290 7538 #, python-format
7291 7539 msgid "Select my personal group (`%(repo_group_name)s`)"
7292 7540 msgstr ""
7293 7541
7294 7542 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:44
7295 7543 msgid "Optional select a group to put this repository into."
7296 7544 msgstr ""
7297 7545
7298 7546 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:52
7299 7547 msgid "Remote pull uri"
7300 7548 msgstr ""
7301 7549
7302 7550 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:60
7303 7551 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:102
7304 7552 #: rhodecode/templates/base/perms_summary.mako:111
7305 7553 #: rhodecode/templates/base/perms_summary.mako:228
7306 7554 #: rhodecode/templates/base/perms_summary.mako:306
7307 7555 #: rhodecode/templates/base/perms_summary.mako:308
7308 7556 #: rhodecode/templates/debug_style/form-elements.html:45
7309 7557 msgid "edit"
7310 7558 msgstr ""
7311 7559
7312 7560 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:66
7313 7561 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:108
7314 7562 msgid "enter new value, or leave empty to remove"
7315 7563 msgstr ""
7316 7564
7317 7565 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:76
7318 7566 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:118
7319 7567 msgid "cancel"
7320 7568 msgstr ""
7321 7569
7322 7570 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:87
7323 7571 msgid "http[s] url where from repository was imported. This field can used for doing {sync_link}."
7324 7572 msgstr ""
7325 7573
7326 7574 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:88
7327 7575 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:130
7328 7576 msgid "This field is stored encrypted inside Database, a format of http://user:password@server.com/repo_name can be used and will be hidden from display."
7329 7577 msgstr ""
7330 7578
7331 7579 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:94
7332 7580 msgid "Remote push uri"
7333 7581 msgstr ""
7334 7582
7335 7583 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:129
7336 7584 msgid "http[s] url to sync data back. This field can used for doing {sync_link}."
7337 7585 msgstr ""
7338 7586
7339 7587 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:141
7340 7588 msgid "Landing commit"
7341 7589 msgstr ""
7342 7590
7343 7591 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:146
7344 7592 msgid "The default commit for file pages, downloads, full text search index, and README generation."
7345 7593 msgstr ""
7346 7594
7347 7595 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:164
7348 7596 msgid "Change owner of this repository."
7349 7597 msgstr ""
7350 7598
7351 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:187
7599 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:194
7352 7600 #: rhodecode/templates/data_table/_dt_elements.mako:104
7353 7601 msgid "Private repository"
7354 7602 msgstr ""
7355 7603
7356 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:197
7604 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:204
7357 7605 #: rhodecode/templates/summary/components.mako:238
7358 7606 msgid "Enable statistics"
7359 7607 msgstr ""
7360 7608
7361 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:202
7609 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:209
7362 7610 msgid "Enable statistics window on summary page."
7363 7611 msgstr ""
7364 7612
7365 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:207
7613 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:214
7366 7614 #: rhodecode/templates/summary/components.mako:184
7367 7615 msgid "Enable downloads"
7368 7616 msgstr ""
7369 7617
7370 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:212
7618 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:219
7371 7619 msgid "Enable download menu on summary page."
7372 7620 msgstr ""
7373 7621
7374 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:217
7622 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:224
7375 7623 msgid "Enable automatic locking"
7376 7624 msgstr ""
7377 7625
7378 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:222
7626 #: rhodecode/templates/admin/repos/repo_edit_settings.mako:229
7379 7627 msgid "Enable automatic locking on repository. Pulling from this repository creates a lock that can be released by pushing back by the same user"
7380 7628 msgstr ""
7381 7629
7382 7630 #: rhodecode/templates/admin/repos/repo_edit_statistics.mako:3
7383 7631 msgid "Repository statistics"
7384 7632 msgstr ""
7385 7633
7386 7634 #: rhodecode/templates/admin/repos/repo_edit_statistics.mako:11
7387 7635 msgid "Processed commits"
7388 7636 msgstr ""
7389 7637
7390 7638 #: rhodecode/templates/admin/repos/repo_edit_statistics.mako:12
7391 7639 msgid "Processed progress"
7392 7640 msgstr ""
7393 7641
7394 7642 #: rhodecode/templates/admin/repos/repo_edit_statistics.mako:15
7395 7643 msgid "Reset statistics"
7396 7644 msgstr ""
7397 7645
7398 7646 #: rhodecode/templates/admin/repos/repo_edit_statistics.mako:15
7399 7647 msgid "Confirm to remove current statistics"
7400 7648 msgstr ""
7401 7649
7402 7650 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:3
7403 7651 msgid "Strip commits from repository"
7404 7652 msgstr ""
7405 7653
7406 7654 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:7
7407 7655 #, python-format
7408 7656 msgid "Please provide up to %d commits commits to strip"
7409 7657 msgstr ""
7410 7658
7411 7659 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:9
7412 7660 msgid "In the first step commits will be verified for existance in the repository"
7413 7661 msgstr ""
7414 7662
7415 7663 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:10
7416 7664 msgid "In the second step, correct commits will be available for stripping"
7417 7665 msgstr ""
7418 7666
7419 7667 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:16
7420 7668 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:52
7421 7669 msgid "Enter full 40 character commit sha"
7422 7670 msgstr ""
7423 7671
7424 7672 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:18
7425 7673 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:54
7426 7674 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:95
7427 7675 msgid "Add another commit"
7428 7676 msgstr ""
7429 7677
7430 7678 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:27
7431 7679 msgid "Check commits"
7432 7680 msgstr ""
7433 7681
7434 7682 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:33
7435 7683 msgid "Sorry this functionality is not available for SVN repository"
7436 7684 msgstr ""
7437 7685
7438 7686 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:114
7439 7687 msgid "Checking commits"
7440 7688 msgstr ""
7441 7689
7442 7690 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:142
7443 7691 msgid " commit verified positive"
7444 7692 msgstr ""
7445 7693
7446 7694 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:154
7447 7695 msgid " commit verified negative"
7448 7696 msgstr ""
7449 7697
7450 7698 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:179
7451 7699 msgid " commit striped successfully"
7452 7700 msgstr ""
7453 7701
7454 7702 #: rhodecode/templates/admin/repos/repo_edit_strip.mako:182
7455 7703 msgid " commit strip failed"
7456 7704 msgstr ""
7457 7705
7458 7706 #: rhodecode/templates/admin/repos/repo_edit_vcs.mako:13
7459 7707 msgid "Select to inherit global vcs settings."
7460 7708 msgstr ""
7461 7709
7462 7710 #: rhodecode/templates/admin/repos/repo_edit_vcs.mako:43
7463 7711 #: rhodecode/templates/admin/settings/settings_global.mako:140
7464 7712 #: rhodecode/templates/admin/settings/settings_labs.mako:48
7465 7713 #: rhodecode/templates/admin/settings/settings_vcs.mako:13
7466 7714 #: rhodecode/templates/admin/settings/settings_visual.mako:214
7467 7715 msgid "Save settings"
7468 7716 msgstr ""
7469 7717
7470 7718 #: rhodecode/templates/admin/repos/repos.mako:5
7471 7719 msgid "Repositories administration"
7472 7720 msgstr ""
7473 7721
7474 7722 #: rhodecode/templates/admin/repos/repos.mako:110
7475 7723 msgid "State"
7476 7724 msgstr ""
7477 7725
7478 7726 #: rhodecode/templates/admin/settings/settings_automation.mako:3
7479 7727 msgid "Admin Automation"
7480 7728 msgstr ""
7481 7729
7482 7730 #: rhodecode/templates/admin/settings/settings_email.mako:3
7483 7731 msgid "Email Configuration"
7484 7732 msgstr ""
7485 7733
7486 7734 #: rhodecode/templates/admin/settings/settings_email.mako:8
7487 7735 msgid "Email prefix"
7488 7736 msgstr ""
7489 7737
7490 7738 #: rhodecode/templates/admin/settings/settings_email.mako:9
7491 7739 msgid "Email from"
7492 7740 msgstr ""
7493 7741
7494 7742 #: rhodecode/templates/admin/settings/settings_email.mako:11
7495 7743 msgid "SMTP server"
7496 7744 msgstr ""
7497 7745
7498 7746 #: rhodecode/templates/admin/settings/settings_email.mako:12
7499 7747 msgid "SMTP username"
7500 7748 msgstr ""
7501 7749
7502 7750 #: rhodecode/templates/admin/settings/settings_email.mako:13
7503 7751 msgid "SMTP password"
7504 7752 msgstr ""
7505 7753
7506 7754 #: rhodecode/templates/admin/settings/settings_email.mako:14
7507 7755 msgid "SMTP port"
7508 7756 msgstr ""
7509 7757
7510 7758 #: rhodecode/templates/admin/settings/settings_email.mako:16
7511 7759 msgid "SMTP use TLS"
7512 7760 msgstr ""
7513 7761
7514 7762 #: rhodecode/templates/admin/settings/settings_email.mako:17
7515 7763 msgid "SMTP use SSL"
7516 7764 msgstr ""
7517 7765
7518 7766 #: rhodecode/templates/admin/settings/settings_email.mako:28
7519 7767 msgid "You can adjust those settings in [DEFAULT] section of .ini file located at"
7520 7768 msgstr ""
7521 7769
7522 7770 #: rhodecode/templates/admin/settings/settings_email.mako:36
7523 7771 msgid "Test Email"
7524 7772 msgstr ""
7525 7773
7526 7774 #: rhodecode/templates/admin/settings/settings_email.mako:42
7527 7775 msgid "enter valid email"
7528 7776 msgstr ""
7529 7777
7530 7778 #: rhodecode/templates/admin/settings/settings_email.mako:46
7531 7779 msgid "Send an auto-generated email from this server to above email..."
7532 7780 msgstr ""
7533 7781
7534 7782 #: rhodecode/templates/admin/settings/settings_exceptions.mako:3
7535 7783 msgid "Exceptions Tracker - Exception ID"
7536 7784 msgstr ""
7537 7785
7538 7786 #: rhodecode/templates/admin/settings/settings_exceptions.mako:8
7787 #: rhodecode/templates/email_templates/exception_tracker.mako:14
7539 7788 msgid "Exception `{}` generated on UTC date: {}"
7540 7789 msgstr ""
7541 7790
7542 #: rhodecode/templates/admin/settings/settings_exceptions.mako:12
7543 msgid "Unable to Read Exception. It might be removed or non-existing."
7544 msgstr ""
7545
7546 7791 #: rhodecode/templates/admin/settings/settings_exceptions.mako:21
7792 msgid "Unable to Read Exception. It might be removed or non-existing."
7793 msgstr ""
7794
7795 #: rhodecode/templates/admin/settings/settings_exceptions.mako:30
7547 7796 msgid "Delete this Exception"
7548 7797 msgstr ""
7549 7798
7550 #: rhodecode/templates/admin/settings/settings_exceptions.mako:29
7551 msgid "Confirm to delete this exception"
7552 msgstr ""
7553
7554 #: rhodecode/templates/admin/settings/settings_exceptions.mako:31
7799 #: rhodecode/templates/admin/settings/settings_exceptions.mako:40
7555 7800 msgid "Delete This Exception"
7556 7801 msgstr ""
7557 7802
7558 7803 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:3
7559 7804 msgid "Exceptions Tracker "
7560 7805 msgstr ""
7561 7806
7562 7807 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:7
7563 7808 msgid "There is {} stored exception."
7564 7809 msgstr ""
7565 7810
7566 7811 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:9
7567 7812 msgid "There are total {} stored exceptions."
7568 7813 msgstr ""
7569 7814
7570 7815 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:12
7571 7816 msgid "Store directory"
7572 7817 msgstr ""
7573 7818
7574 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:19
7575 msgid "Confirm to delete all exceptions"
7576 msgstr ""
7577
7578 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:22
7819 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:23
7579 7820 msgid "Delete All `{}`"
7580 7821 msgstr ""
7581 7822
7582 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:24
7823 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:25
7583 7824 msgid "Delete All"
7584 7825 msgstr ""
7585 7826
7586 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:38
7827 #: rhodecode/templates/admin/settings/settings_exceptions_browse.mako:39
7587 7828 msgid "Exceptions Tracker - Showing the last {} Exceptions"
7588 7829 msgstr ""
7589 7830
7590 7831 #: rhodecode/templates/admin/settings/settings_global.mako:5
7591 7832 msgid "Branding"
7592 7833 msgstr ""
7593 7834
7594 7835 #: rhodecode/templates/admin/settings/settings_global.mako:16
7595 7836 msgid "Set a custom title for your RhodeCode instance (limited to 40 characters)."
7596 7837 msgstr ""
7597 7838
7598 7839 #: rhodecode/templates/admin/settings/settings_global.mako:20
7599 7840 msgid "HTTP[S] authentication realm"
7600 7841 msgstr ""
7601 7842
7602 7843 #: rhodecode/templates/admin/settings/settings_global.mako:27
7603 7844 msgid "Set a custom text that is shown as authentication message to clients trying to connect."
7604 7845 msgstr ""
7605 7846
7606 7847 #: rhodecode/templates/admin/settings/settings_global.mako:36
7607 #: rhodecode/templates/admin/users/user_edit_advanced.mako:80
7848 #: rhodecode/templates/admin/users/user_edit_advanced.mako:83
7608 7849 msgid "Personal Repository Group"
7609 7850 msgstr ""
7610 7851
7611 7852 #: rhodecode/templates/admin/settings/settings_global.mako:41
7612 7853 msgid "Create Personal Repository Group"
7613 7854 msgstr ""
7614 7855
7615 7856 #: rhodecode/templates/admin/settings/settings_global.mako:44
7616 7857 msgid "Always create Personal Repository Groups for new users."
7617 7858 msgstr ""
7618 7859
7619 7860 #: rhodecode/templates/admin/settings/settings_global.mako:45
7620 7861 msgid "When creating new users from add user form or API you can still turn this off via a checkbox or flag"
7621 7862 msgstr ""
7622 7863
7623 7864 #: rhodecode/templates/admin/settings/settings_global.mako:49
7624 7865 msgid "Personal Repo Group Pattern"
7625 7866 msgstr ""
7626 7867
7627 7868 #: rhodecode/templates/admin/settings/settings_global.mako:55
7628 7869 msgid "Pattern used to create Personal Repository Groups. Prefix can be other existing repository group path[s], eg. /u/${username}"
7629 7870 msgstr ""
7630 7871
7631 7872 #: rhodecode/templates/admin/settings/settings_global.mako:56
7632 7873 msgid "Available variables are currently ${username} and ${user_id}"
7633 7874 msgstr ""
7634 7875
7635 7876 #: rhodecode/templates/admin/settings/settings_global.mako:64
7636 7877 msgid "Registration Captcha"
7637 7878 msgstr ""
7638 7879
7639 7880 #: rhodecode/templates/admin/settings/settings_global.mako:68
7640 7881 msgid "Google reCaptcha v2 site key."
7641 7882 msgstr ""
7642 7883
7643 7884 #: rhodecode/templates/admin/settings/settings_global.mako:75
7644 7885 msgid "Site key for reCaptcha v2 system."
7645 7886 msgstr ""
7646 7887
7647 7888 #: rhodecode/templates/admin/settings/settings_global.mako:80
7648 7889 msgid "Google reCaptcha v2 secret key."
7649 7890 msgstr ""
7650 7891
7651 7892 #: rhodecode/templates/admin/settings/settings_global.mako:87
7652 7893 msgid "Secret key for reCaptcha v2 system. Setting this value will enable captcha on registration and password reset forms."
7653 7894 msgstr ""
7654 7895
7655 7896 #: rhodecode/templates/admin/settings/settings_global.mako:95
7656 7897 msgid "Custom Header Code"
7657 7898 msgstr ""
7658 7899
7659 7900 #: rhodecode/templates/admin/settings/settings_global.mako:100
7660 7901 #: rhodecode/templates/admin/settings/settings_global.mako:124
7661 7902 #: rhodecode/templates/debug_style/form-elements-small.html:59
7662 7903 #: rhodecode/templates/debug_style/form-elements.html:57
7663 7904 #: rhodecode/templates/debug_style/form-elements.html:82
7664 7905 #: rhodecode/templates/debug_style/form-elements.html:225
7665 7906 #: rhodecode/templates/debug_style/form-elements.html:381
7666 7907 #: rhodecode/templates/debug_style/form-elements.html:407
7667 7908 #: rhodecode/templates/debug_style/form-elements.html:515
7668 7909 #: rhodecode/templates/debug_style/form-elements.html:519
7669 7910 #: rhodecode/templates/debug_style/form-elements.html:537
7670 7911 #: rhodecode/templates/debug_style/form-elements.html:581
7671 7912 #: rhodecode/templates/debug_style/form-inline.html:38
7672 7913 #: rhodecode/templates/debug_style/form-inline.html:139
7673 7914 #: rhodecode/templates/debug_style/form-inline.html:147
7674 7915 #: rhodecode/templates/debug_style/form-vertical.html:60
7675 7916 #: rhodecode/templates/debug_style/forms.html:37
7676 7917 #: rhodecode/templates/debug_style/forms.html:60
7677 7918 #: rhodecode/templates/debug_style/forms.html:78
7678 7919 #: rhodecode/templates/debug_style/forms.html:96
7679 7920 #: rhodecode/templates/debug_style/layout-form-sidebar.html:44
7680 7921 msgid "Templates..."
7681 7922 msgstr ""
7682 7923
7683 7924 #: rhodecode/templates/admin/settings/settings_global.mako:103
7684 7925 #: rhodecode/templates/admin/settings/settings_global.mako:127
7685 7926 #: rhodecode/templates/debug_style/form-elements-small.html:62
7686 7927 #: rhodecode/templates/debug_style/form-elements.html:60
7687 7928 #: rhodecode/templates/debug_style/form-elements.html:85
7688 7929 #: rhodecode/templates/debug_style/form-elements.html:228
7689 7930 #: rhodecode/templates/debug_style/form-elements.html:384
7690 7931 #: rhodecode/templates/debug_style/form-elements.html:410
7691 7932 #: rhodecode/templates/debug_style/form-elements.html:518
7692 7933 #: rhodecode/templates/debug_style/form-elements.html:522
7693 7934 #: rhodecode/templates/debug_style/form-elements.html:540
7694 7935 #: rhodecode/templates/debug_style/form-elements.html:584
7695 7936 #: rhodecode/templates/debug_style/form-inline.html:41
7696 7937 #: rhodecode/templates/debug_style/form-inline.html:142
7697 7938 #: rhodecode/templates/debug_style/form-inline.html:150
7698 7939 #: rhodecode/templates/debug_style/form-vertical.html:63
7699 7940 #: rhodecode/templates/debug_style/forms.html:40
7700 7941 #: rhodecode/templates/debug_style/forms.html:63
7701 7942 #: rhodecode/templates/debug_style/forms.html:81
7702 7943 #: rhodecode/templates/debug_style/forms.html:99
7703 7944 #: rhodecode/templates/debug_style/layout-form-sidebar.html:47
7704 7945 msgid "Server Announcement"
7705 7946 msgstr ""
7706 7947
7707 7948 #: rhodecode/templates/admin/settings/settings_global.mako:104
7708 7949 msgid "Flash message filtering"
7709 7950 msgstr ""
7710 7951
7711 7952 #: rhodecode/templates/admin/settings/settings_global.mako:105
7712 7953 msgid "Custom logos"
7713 7954 msgstr ""
7714 7955
7715 7956 #: rhodecode/templates/admin/settings/settings_global.mako:111
7716 7957 msgid "Custom js/css code added at the end of the <head/> tag."
7717 7958 msgstr ""
7718 7959
7719 7960 #: rhodecode/templates/admin/settings/settings_global.mako:112
7720 7961 msgid "Use <script/> or <style/> tags to define custom scripting or styling."
7721 7962 msgstr ""
7722 7963
7723 7964 #: rhodecode/templates/admin/settings/settings_global.mako:119
7724 7965 msgid "Custom Footer Code"
7725 7966 msgstr ""
7726 7967
7727 7968 #: rhodecode/templates/admin/settings/settings_global.mako:133
7728 7969 msgid "Custom js/css code added at the end of the <body> tag."
7729 7970 msgstr ""
7730 7971
7731 7972 #: rhodecode/templates/admin/settings/settings_global.mako:134
7732 7973 msgid "Use <script> or <style> tags to define custom scripting or styling."
7733 7974 msgstr ""
7734 7975
7735 7976 #: rhodecode/templates/admin/settings/settings_hooks.mako:3
7736 7977 msgid "Built in Mercurial hooks - read only"
7737 7978 msgstr ""
7738 7979
7739 7980 #: rhodecode/templates/admin/settings/settings_hooks.mako:19
7740 7981 msgid "Hooks can be used to trigger actions on certain events such as push / pull. They can trigger Python functions or external applications."
7741 7982 msgstr ""
7742 7983
7743 7984 #: rhodecode/templates/admin/settings/settings_hooks.mako:27
7744 7985 msgid "Custom hooks"
7745 7986 msgstr ""
7746 7987
7747 7988 #: rhodecode/templates/admin/settings/settings_labs.mako:3
7748 7989 msgid "Labs Settings"
7749 7990 msgstr ""
7750 7991
7751 7992 #: rhodecode/templates/admin/settings/settings_labs.mako:10
7752 7993 msgid "There are no Labs settings currently"
7753 7994 msgstr ""
7754 7995
7755 7996 #: rhodecode/templates/admin/settings/settings_mapping.mako:5
7756 7997 msgid "Import New Groups or Repositories"
7757 7998 msgstr ""
7758 7999
7759 8000 #: rhodecode/templates/admin/settings/settings_mapping.mako:10
7760 8001 msgid "Destroy old data"
7761 8002 msgstr ""
7762 8003
7763 8004 #: rhodecode/templates/admin/settings/settings_mapping.mako:12
7764 8005 msgid "In case a repository or a group was deleted from the filesystem and it still exists in the database, check this option to remove obsolete data from the database."
7765 8006 msgstr ""
7766 8007
7767 8008 #: rhodecode/templates/admin/settings/settings_mapping.mako:16
7768 8009 msgid "Invalidate cache for all repositories"
7769 8010 msgstr ""
7770 8011
7771 8012 #: rhodecode/templates/admin/settings/settings_mapping.mako:18
7772 8013 msgid "Each cache data for repositories will be cleaned with this option selected. Use this to reload data and clear cache keys."
7773 8014 msgstr ""
7774 8015
7775 8016 #: rhodecode/templates/admin/settings/settings_mapping.mako:21
7776 8017 msgid "Rescan Filesystem"
7777 8018 msgstr ""
7778 8019
7779 8020 #: rhodecode/templates/admin/settings/settings_open_source.mako:11
7780 8021 msgid "Licenses of Third Party Packages"
7781 8022 msgstr ""
7782 8023
7783 8024 #: rhodecode/templates/admin/settings/settings_process_management.mako:3
7784 8025 #: rhodecode/templates/admin/settings/settings_system.mako:3
7785 8026 msgid "Checking for updates..."
7786 8027 msgstr ""
7787 8028
7788 8029 #: rhodecode/templates/admin/settings/settings_process_management.mako:9
7789 8030 msgid "Gunicorn process management"
7790 8031 msgstr ""
7791 8032
7792 8033 #: rhodecode/templates/admin/settings/settings_process_management.mako:11
7793 8034 msgid "start auto refresh"
7794 8035 msgstr ""
7795 8036
7796 8037 #: rhodecode/templates/admin/settings/settings_process_management.mako:12
7797 8038 msgid "stop auto refresh"
7798 8039 msgstr ""
7799 8040
7800 8041 #: rhodecode/templates/admin/settings/settings_search.mako:3
7801 8042 msgid "RhodeCode Full Text Search"
7802 8043 msgstr ""
7803 8044
7804 8045 #: rhodecode/templates/admin/settings/settings_sessions.mako:3
7805 8046 msgid "User Sessions Configuration"
7806 8047 msgstr ""
7807 8048
7808 8049 #: rhodecode/templates/admin/settings/settings_sessions.mako:8
7809 8050 msgid "Session type"
7810 8051 msgstr ""
7811 8052
7812 8053 #: rhodecode/templates/admin/settings/settings_sessions.mako:9
7813 8054 msgid "Session expiration period"
7814 8055 msgstr ""
7815 8056
7816 8057 #: rhodecode/templates/admin/settings/settings_sessions.mako:11
7817 8058 msgid "Total sessions"
7818 8059 msgstr ""
7819 8060
7820 8061 #: rhodecode/templates/admin/settings/settings_sessions.mako:12
7821 8062 msgid "Expired sessions ({} days)"
7822 8063 msgstr ""
7823 8064
7824 8065 #: rhodecode/templates/admin/settings/settings_sessions.mako:28
7825 8066 msgid "Cleanup Old Sessions"
7826 8067 msgstr ""
7827 8068
7828 8069 #: rhodecode/templates/admin/settings/settings_sessions.mako:34
7829 8070 msgid "Cleanup user sessions that were not active during chosen time frame."
7830 8071 msgstr ""
7831 8072
7832 8073 #: rhodecode/templates/admin/settings/settings_sessions.mako:35
7833 8074 msgid "After performing this action users whose session will be removed will be required to log in again."
7834 8075 msgstr ""
7835 8076
7836 8077 #: rhodecode/templates/admin/settings/settings_sessions.mako:36
7837 8078 msgid "Picking `All` will log-out you, and all users in the system."
7838 8079 msgstr ""
7839 8080
7840 8081 #: rhodecode/templates/admin/settings/settings_sessions.mako:55
7841 8082 msgid "Confirm to cleanup user sessions"
7842 8083 msgstr ""
7843 8084
7844 8085 #: rhodecode/templates/admin/settings/settings_sessions.mako:56
7845 8086 msgid "Cleanup sessions"
7846 8087 msgstr ""
7847 8088
7848 8089 #: rhodecode/templates/admin/settings/settings_system.mako:9
7849 8090 msgid "System Info"
7850 8091 msgstr ""
7851 8092
7852 8093 #: rhodecode/templates/admin/settings/settings_system.mako:11
7853 8094 msgid "create summary snapshot"
7854 8095 msgstr ""
7855 8096
7856 8097 #: rhodecode/templates/admin/settings/settings_system.mako:46
7857 8098 msgid "Python Packages"
7858 8099 msgstr ""
7859 8100
7860 8101 #: rhodecode/templates/admin/settings/settings_visual.mako:5
7861 8102 #: rhodecode/templates/base/vcs_settings.mako:10
7862 8103 msgid "General"
7863 8104 msgstr ""
7864 8105
7865 8106 #: rhodecode/templates/admin/settings/settings_visual.mako:10
7866 8107 msgid "Use repository extra fields"
7867 8108 msgstr ""
7868 8109
7869 8110 #: rhodecode/templates/admin/settings/settings_visual.mako:12
7870 8111 msgid "Allows storing additional customized fields per repository."
7871 8112 msgstr ""
7872 8113
7873 8114 #: rhodecode/templates/admin/settings/settings_visual.mako:17
7874 8115 msgid "Show RhodeCode version"
7875 8116 msgstr ""
7876 8117
7877 8118 #: rhodecode/templates/admin/settings/settings_visual.mako:19
7878 8119 msgid "Shows or hides a version number of RhodeCode displayed in the footer."
7879 8120 msgstr ""
7880 8121
7881 8122 #: rhodecode/templates/admin/settings/settings_visual.mako:26
7882 8123 msgid "Gravatars"
7883 8124 msgstr ""
7884 8125
7885 8126 #: rhodecode/templates/admin/settings/settings_visual.mako:31
7886 8127 msgid "Use Gravatars based avatars"
7887 8128 msgstr ""
7888 8129
7889 8130 #: rhodecode/templates/admin/settings/settings_visual.mako:33
7890 8131 msgid "Use gravatar.com as avatar system for RhodeCode accounts. If this is disabled avatars are generated based on initials and email."
7891 8132 msgstr ""
7892 8133
7893 8134 #: rhodecode/templates/admin/settings/settings_visual.mako:36
7894 8135 msgid "Gravatar URL"
7895 8136 msgstr ""
7896 8137
7897 8138 #: rhodecode/templates/admin/settings/settings_visual.mako:44
7898 8139 msgid ""
7899 8140 "Gravatar url allows you to use other avatar server application.\n"
7900 8141 " Following variables of the URL will be replaced accordingly.\n"
7901 8142 " {scheme} 'http' or 'https' sent from running RhodeCode server,\n"
7902 8143 " {email} user email,\n"
7903 8144 " {md5email} md5 hash of the user email (like at gravatar.com),\n"
7904 8145 " {size} size of the image that is expected from the server application,\n"
7905 8146 " {netloc} network location/server host of running RhodeCode server"
7906 8147 msgstr ""
7907 8148
7908 8149 #: rhodecode/templates/admin/settings/settings_visual.mako:59
7909 8150 msgid "Meta-Tagging"
7910 8151 msgstr ""
7911 8152
7912 8153 #: rhodecode/templates/admin/settings/settings_visual.mako:64
7913 8154 msgid "Stylify recognised meta tags"
7914 8155 msgstr ""
7915 8156
7916 8157 #: rhodecode/templates/admin/settings/settings_visual.mako:66
7917 8158 msgid "Parses meta tags from repository or repository group description fields and turns them into colored tags."
7918 8159 msgstr ""
7919 8160
7920 8161 #: rhodecode/templates/admin/settings/settings_visual.mako:77
7921 8162 msgid "Dashboard Items"
7922 8163 msgstr ""
7923 8164
7924 8165 #: rhodecode/templates/admin/settings/settings_visual.mako:81
7925 8166 msgid "Main page dashboard items"
7926 8167 msgstr ""
7927 8168
7928 8169 #: rhodecode/templates/admin/settings/settings_visual.mako:87
7929 8170 msgid "Number of items displayed in the main page dashboard before pagination is shown."
7930 8171 msgstr ""
7931 8172
7932 8173 #: rhodecode/templates/admin/settings/settings_visual.mako:91
7933 8174 msgid "Admin pages items"
7934 8175 msgstr ""
7935 8176
7936 8177 #: rhodecode/templates/admin/settings/settings_visual.mako:97
7937 8178 msgid "Number of items displayed in the admin pages grids before pagination is shown."
7938 8179 msgstr ""
7939 8180
7940 8181 #: rhodecode/templates/admin/settings/settings_visual.mako:106
7941 8182 msgid "Commit ID Style"
7942 8183 msgstr ""
7943 8184
7944 8185 #: rhodecode/templates/admin/settings/settings_visual.mako:110
7945 8186 msgid "Commit sha length"
7946 8187 msgstr ""
7947 8188
7948 8189 #: rhodecode/templates/admin/settings/settings_visual.mako:117
7949 8190 msgid ""
7950 8191 "Number of chars to show in commit sha displayed in web interface.\n"
7951 8192 " By default it's shown as r123:9043a6a4c226 this value defines the\n"
7952 8193 " length of the sha after the `r123:` part."
7953 8194 msgstr ""
7954 8195
7955 8196 #: rhodecode/templates/admin/settings/settings_visual.mako:125
7956 8197 msgid "Show commit ID numeric reference"
7957 8198 msgstr ""
7958 8199
7959 8200 #: rhodecode/templates/admin/settings/settings_visual.mako:125
7960 8201 msgid "Commit show revision number"
7961 8202 msgstr ""
7962 8203
7963 8204 #: rhodecode/templates/admin/settings/settings_visual.mako:127
7964 8205 msgid ""
7965 8206 "Show revision number in commit sha displayed in web interface.\n"
7966 8207 " By default it's shown as r123:9043a6a4c226 this value defines the\n"
7967 8208 " if the `r123:` part is shown."
7968 8209 msgstr ""
7969 8210
7970 8211 #: rhodecode/templates/admin/settings/settings_visual.mako:136
7971 8212 #: rhodecode/templates/debug_style/index.html:64
7972 8213 msgid "Icons"
7973 8214 msgstr ""
7974 8215
7975 8216 #: rhodecode/templates/admin/settings/settings_visual.mako:141
7976 8217 msgid "Show public repo icon on repositories"
7977 8218 msgstr ""
7978 8219
7979 8220 #: rhodecode/templates/admin/settings/settings_visual.mako:147
7980 8221 msgid "Show private repo icon on repositories"
7981 8222 msgstr ""
7982 8223
7983 8224 #: rhodecode/templates/admin/settings/settings_visual.mako:149
7984 8225 msgid "Show public/private icons next to repositories names."
7985 8226 msgstr ""
7986 8227
7987 8228 #: rhodecode/templates/admin/settings/settings_visual.mako:156
7988 8229 msgid "Markup Renderer"
7989 8230 msgstr ""
7990 8231
7991 8232 #: rhodecode/templates/admin/settings/settings_visual.mako:163
7992 8233 msgid "Default renderer used to render comments, pull request descriptions and other description elements. After change old entries will still work correctly."
7993 8234 msgstr ""
7994 8235
7995 8236 #: rhodecode/templates/admin/settings/settings_visual.mako:170
7996 8237 msgid "Clone URL templates"
7997 8238 msgstr ""
7998 8239
7999 8240 #: rhodecode/templates/admin/settings/settings_visual.mako:181
8000 8241 msgid ""
8001 8242 "Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n"
8002 8243 " {scheme} 'http' or 'https' sent from running RhodeCode server,\n"
8003 8244 " {user} current user username,\n"
8004 8245 " {sys_user} current system user running this process, Useful for ssh,\n"
8005 8246 " {hostname} hostname of this server running RhodeCode,\n"
8006 8247 " {netloc} network location/server host of running RhodeCode server,\n"
8007 8248 " {repo} full repository name,\n"
8008 8249 " {repoid} ID of repository, can be used to contruct clone-by-id"
8009 8250 msgstr ""
8010 8251
8011 8252 #: rhodecode/templates/admin/settings/settings_visual.mako:196
8012 8253 msgid "Custom Support Link"
8013 8254 msgstr ""
8014 8255
8015 8256 #: rhodecode/templates/admin/settings/settings_visual.mako:204
8016 8257 #, python-format
8017 8258 msgid ""
8018 8259 "Custom url for the support link located at the bottom.\n"
8019 8260 " The default is set to %(default_url)s. In case there's a need\n"
8020 8261 " to change the support link to internal issue tracker, it should be done here.\n"
8021 8262 " "
8022 8263 msgstr ""
8023 8264
8024 8265 #: rhodecode/templates/admin/user_groups/user_group_add.mako:5
8025 8266 msgid "Add user group"
8026 8267 msgstr ""
8027 8268
8028 8269 #: rhodecode/templates/admin/user_groups/user_group_add.mako:13
8029 8270 #: rhodecode/templates/admin/users/user_edit_advanced.mako:14
8030 8271 #: rhodecode/templates/base/base.mako:110
8031 8272 #: rhodecode/templates/base/base.mako:132
8032 8273 msgid "User groups"
8033 8274 msgstr ""
8034 8275
8035 8276 #: rhodecode/templates/admin/user_groups/user_group_add.mako:46
8036 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:46
8277 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:50
8037 8278 msgid "Short, optional description for this user group."
8038 8279 msgstr ""
8039 8280
8040 8281 #: rhodecode/templates/admin/user_groups/user_group_add.mako:59
8041 8282 msgid "Create User Group"
8042 8283 msgstr ""
8043 8284
8044 8285 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:5
8045 8286 msgid "{} user group settings"
8046 8287 msgstr ""
8047 8288
8048 8289 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:37
8049 8290 #: rhodecode/templates/admin/users/user_edit.mako:43
8050 8291 msgid "Global permissions"
8051 8292 msgstr ""
8052 8293
8053 8294 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:38
8054 8295 #: rhodecode/templates/admin/users/user_edit.mako:44
8055 8296 msgid "Permissions summary"
8056 8297 msgstr ""
8057 8298
8058 8299 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:5
8059 8300 msgid "User Group ID"
8060 8301 msgstr ""
8061 8302
8062 8303 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:9
8063 8304 #: rhodecode/templates/admin/user_groups/user_groups.mako:80
8064 8305 #: rhodecode/templates/debug_style/form-elements.html:509
8065 8306 #: rhodecode/templates/user_group/profile.mako:55
8066 8307 msgid "Members"
8067 8308 msgstr ""
8068 8309
8069 8310 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:10
8070 8311 msgid "Automatic member sync"
8071 8312 msgstr ""
8072 8313
8073 8314 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:12
8074 8315 msgid "Assigned to repositories"
8075 8316 msgstr ""
8076 8317
8077 8318 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:13
8078 8319 msgid "Assigned to repo groups"
8079 8320 msgstr ""
8080 8321
8081 8322 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:15
8082 8323 #: rhodecode/templates/admin/users/user_edit_advanced.mako:19
8083 8324 msgid "Assigned to review rules"
8084 8325 msgstr ""
8085 8326
8086 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:21
8087 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:6
8088 #, python-format
8089 msgid "User Group: %s"
8090 msgstr ""
8091
8092 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:31
8327 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:22
8328 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:6
8329 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:7
8330 #: rhodecode/templates/data_table/_dt_elements.mako:305
8331 #: rhodecode/templates/user_group/user_group.mako:4
8332 msgid "User group"
8333 msgstr ""
8334
8335 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:35
8093 8336 msgid "Group members sync"
8094 8337 msgstr ""
8095 8338
8096 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:38
8339 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:42
8097 8340 msgid "This group is set to be automatically synchronised."
8098 8341 msgstr ""
8099 8342
8100 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:39
8101 msgid "This group synchronization was set by"
8102 msgstr ""
8103
8104 8343 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:43
8344 msgid "This group synchronization was set by"
8345 msgstr ""
8346
8347 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:47
8105 8348 msgid "This group is not set to be automatically synchronised"
8106 8349 msgstr ""
8107 8350
8108 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:52
8351 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:56
8109 8352 msgid "Disable synchronization"
8110 8353 msgstr ""
8111 8354
8112 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:54
8355 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:58
8113 8356 msgid "Enable synchronization"
8114 8357 msgstr ""
8115 8358
8116 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:60
8359 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:64
8117 8360 msgid "Users will be added or removed from this group when they authenticate with RhodeCode system, based on LDAP group membership. This requires `LDAP+User group` authentication plugin to be configured and enabled. (EE only feature)"
8118 8361 msgstr ""
8119 8362
8120 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:73
8363 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:77
8121 8364 msgid "Delete User Group"
8122 8365 msgstr ""
8123 8366
8124 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:79
8367 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:83
8125 8368 #, python-format
8126 8369 msgid "Confirm to delete user group `%(ugroup)s` with all permission assignments"
8127 8370 msgstr ""
8128 8371
8129 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:81
8372 #: rhodecode/templates/admin/user_groups/user_group_edit_advanced.mako:85
8130 8373 msgid "Delete This User Group"
8131 8374 msgstr ""
8132 8375
8133 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:5
8134 msgid "User Group Permissions"
8135 msgstr ""
8136
8137 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:36
8376 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:40
8138 8377 msgid "Change owner of this user group."
8139 8378 msgstr ""
8140 8379
8141 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:60
8380 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:64
8142 8381 msgid "Add members"
8143 8382 msgstr ""
8144 8383
8145 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:96
8384 #: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:100
8146 8385 #: rhodecode/templates/user_group/profile.mako:78
8147 8386 msgid "No members yet"
8148 8387 msgstr ""
8149 8388
8150 8389 #: rhodecode/templates/admin/user_groups/user_groups.mako:5
8151 #: rhodecode/templates/admin/users/user_edit_groups.mako:6
8390 #: rhodecode/templates/admin/users/user_edit_groups.mako:8
8152 8391 msgid "User groups administration"
8153 8392 msgstr ""
8154 8393
8155 8394 #: rhodecode/templates/admin/user_groups/user_groups.mako:82
8156 8395 msgid "Sync"
8157 8396 msgstr ""
8158 8397
8159 8398 #: rhodecode/templates/admin/users/user_add.mako:5
8160 8399 msgid "Add user"
8161 8400 msgstr ""
8162 8401
8163 8402 #: rhodecode/templates/admin/users/user_add.mako:13
8164 8403 #: rhodecode/templates/admin/users/user_edit.mako:14
8165 8404 #: rhodecode/templates/base/base.mako:109
8166 8405 msgid "Users"
8167 8406 msgstr ""
8168 8407
8169 8408 #: rhodecode/templates/admin/users/user_add.mako:15
8170 8409 #: rhodecode/templates/admin/users/users.mako:31
8171 8410 msgid "Add User"
8172 8411 msgstr ""
8173 8412
8174 8413 #: rhodecode/templates/admin/users/user_add.mako:53
8175 8414 msgid "Password confirmation"
8176 8415 msgstr ""
8177 8416
8178 8417 #: rhodecode/templates/admin/users/user_add.mako:59
8179 8418 msgid "Generate password"
8180 8419 msgstr ""
8181 8420
8182 8421 #: rhodecode/templates/admin/users/user_add.mako:106
8183 8422 msgid "Password change"
8184 8423 msgstr ""
8185 8424
8186 8425 #: rhodecode/templates/admin/users/user_add.mako:110
8187 8426 msgid "Force user to change his password on the next login"
8188 8427 msgstr ""
8189 8428
8190 8429 #: rhodecode/templates/admin/users/user_add.mako:116
8191 8430 msgid "Add personal repository group"
8192 8431 msgstr ""
8193 8432
8194 8433 #: rhodecode/templates/admin/users/user_add.mako:121
8195 8434 msgid "New group will be created at: `/{path}`"
8196 8435 msgstr ""
8197 8436
8198 8437 #: rhodecode/templates/admin/users/user_add.mako:122
8199 8438 msgid "User will be automatically set as this group owner."
8200 8439 msgstr ""
8201 8440
8202 8441 #: rhodecode/templates/admin/users/user_add.mako:128
8203 8442 msgid "Create User"
8204 8443 msgstr ""
8205 8444
8206 8445 #: rhodecode/templates/admin/users/user_add.mako:139
8207 8446 msgid "generated password:"
8208 8447 msgstr ""
8209 8448
8210 8449 #: rhodecode/templates/admin/users/user_edit.mako:5
8211 8450 msgid "{} user settings"
8212 8451 msgstr ""
8213 8452
8214 8453 #: rhodecode/templates/admin/users/user_edit.mako:31
8215 8454 msgid "This user is set as disabled"
8216 8455 msgstr ""
8217 8456
8218 8457 #: rhodecode/templates/admin/users/user_edit.mako:39
8219 #: rhodecode/templates/admin/users/user_edit_profile.mako:5
8458 #: rhodecode/templates/admin/users/user_edit_profile.mako:7
8220 8459 #: rhodecode/templates/users/user_profile.mako:6
8221 8460 msgid "User Profile"
8222 8461 msgstr ""
8223 8462
8224 8463 #: rhodecode/templates/admin/users/user_edit.mako:40
8225 8464 msgid "Auth tokens"
8226 8465 msgstr ""
8227 8466
8228 8467 #: rhodecode/templates/admin/users/user_edit.mako:46
8229 8468 msgid "Ip Whitelist"
8230 8469 msgstr ""
8231 8470
8232 8471 #: rhodecode/templates/admin/users/user_edit.mako:47
8233 8472 msgid "User Groups Management"
8234 8473 msgstr ""
8235 8474
8236 8475 #: rhodecode/templates/admin/users/user_edit_advanced.mako:5
8237 8476 msgid "User ID"
8238 8477 msgstr ""
8239 8478
8240 8479 #: rhodecode/templates/admin/users/user_edit_advanced.mako:7
8241 8480 msgid "Source of Record"
8242 8481 msgstr ""
8243 8482
8244 8483 #: rhodecode/templates/admin/users/user_edit_advanced.mako:9
8245 8484 msgid "Last login"
8246 8485 msgstr ""
8247 8486
8248 8487 #: rhodecode/templates/admin/users/user_edit_advanced.mako:10
8249 8488 #: rhodecode/templates/admin/users/users.mako:83
8250 8489 #: rhodecode/templates/forks/forks.mako:67
8251 8490 msgid "Last activity"
8252 8491 msgstr ""
8253 8492
8254 8493 #: rhodecode/templates/admin/users/user_edit_advanced.mako:16
8255 8494 msgid "Owned Artifacts"
8256 8495 msgstr ""
8257 8496
8258 8497 #: rhodecode/templates/admin/users/user_edit_advanced.mako:18
8259 8498 msgid "Reviewer of pull requests"
8260 8499 msgstr ""
8261 8500
8262 8501 #: rhodecode/templates/admin/users/user_edit_advanced.mako:21
8263 8502 msgid "Member of User groups"
8264 8503 msgstr ""
8265 8504
8266 8505 #: rhodecode/templates/admin/users/user_edit_advanced.mako:22
8267 8506 msgid "Force password change"
8268 8507 msgstr ""
8269 8508
8270 #: rhodecode/templates/admin/users/user_edit_advanced.mako:28
8271 msgid "User: {}"
8272 msgstr ""
8273
8274 #: rhodecode/templates/admin/users/user_edit_advanced.mako:46
8509 #: rhodecode/templates/admin/users/user_edit_advanced.mako:49
8275 8510 msgid "Force Password Reset"
8276 8511 msgstr ""
8277 8512
8278 #: rhodecode/templates/admin/users/user_edit_advanced.mako:52
8513 #: rhodecode/templates/admin/users/user_edit_advanced.mako:55
8279 8514 msgid "Disable forced password reset"
8280 8515 msgstr ""
8281 8516
8282 #: rhodecode/templates/admin/users/user_edit_advanced.mako:57
8517 #: rhodecode/templates/admin/users/user_edit_advanced.mako:60
8283 8518 msgid "Clear the forced password change flag."
8284 8519 msgstr ""
8285 8520
8286 #: rhodecode/templates/admin/users/user_edit_advanced.mako:64
8521 #: rhodecode/templates/admin/users/user_edit_advanced.mako:67
8287 8522 msgid "Confirm to enable forced password change"
8288 8523 msgstr ""
8289 8524
8290 #: rhodecode/templates/admin/users/user_edit_advanced.mako:65
8525 #: rhodecode/templates/admin/users/user_edit_advanced.mako:68
8291 8526 msgid "Enable forced password reset"
8292 8527 msgstr ""
8293 8528
8294 #: rhodecode/templates/admin/users/user_edit_advanced.mako:70
8529 #: rhodecode/templates/admin/users/user_edit_advanced.mako:73
8295 8530 msgid "When this is enabled user will have to change they password when they next use RhodeCode system. This will also forbid vcs operations until someone makes a password change in the web interface"
8296 8531 msgstr ""
8297 8532
8298 #: rhodecode/templates/admin/users/user_edit_advanced.mako:86
8299 msgid "Users personal repository group"
8300 msgstr ""
8301
8302 8533 #: rhodecode/templates/admin/users/user_edit_advanced.mako:89
8534 msgid "Users personal repository group"
8535 msgstr ""
8536
8537 #: rhodecode/templates/admin/users/user_edit_advanced.mako:92
8303 8538 msgid "This user currently does not have a personal repository group"
8304 8539 msgstr ""
8305 8540
8306 #: rhodecode/templates/admin/users/user_edit_advanced.mako:91
8541 #: rhodecode/templates/admin/users/user_edit_advanced.mako:94
8307 8542 #, python-format
8308 8543 msgid "New group will be created at: `/%(path)s`"
8309 8544 msgstr ""
8310 8545
8311 #: rhodecode/templates/admin/users/user_edit_advanced.mako:96
8546 #: rhodecode/templates/admin/users/user_edit_advanced.mako:99
8312 8547 msgid "Create personal repository group"
8313 8548 msgstr ""
8314 8549
8315 #: rhodecode/templates/admin/users/user_edit_advanced.mako:105
8550 #: rhodecode/templates/admin/users/user_edit_advanced.mako:108
8316 8551 msgid "Delete User"
8317 8552 msgstr ""
8318 8553
8319 #: rhodecode/templates/admin/users/user_edit_advanced.mako:116
8320 msgid "Detach repositories"
8321 msgstr ""
8322
8323 8554 #: rhodecode/templates/admin/users/user_edit_advanced.mako:119
8324 #: rhodecode/templates/admin/users/user_edit_advanced.mako:131
8325 #: rhodecode/templates/admin/users/user_edit_advanced.mako:143
8555 msgid "Detach repositories"
8556 msgstr ""
8557
8558 #: rhodecode/templates/admin/users/user_edit_advanced.mako:122
8559 #: rhodecode/templates/admin/users/user_edit_advanced.mako:134
8560 #: rhodecode/templates/admin/users/user_edit_advanced.mako:146
8326 8561 msgid "Delete repositories"
8327 8562 msgstr ""
8328 8563
8329 #: rhodecode/templates/admin/users/user_edit_advanced.mako:128
8564 #: rhodecode/templates/admin/users/user_edit_advanced.mako:131
8330 8565 msgid "Detach repository groups"
8331 8566 msgstr ""
8332 8567
8333 #: rhodecode/templates/admin/users/user_edit_advanced.mako:140
8568 #: rhodecode/templates/admin/users/user_edit_advanced.mako:143
8334 8569 msgid "Detach user groups"
8335 8570 msgstr ""
8336 8571
8337 #: rhodecode/templates/admin/users/user_edit_advanced.mako:152
8338 msgid "Detach Artifacts"
8339 msgstr ""
8340
8341 8572 #: rhodecode/templates/admin/users/user_edit_advanced.mako:155
8573 msgid "Detach pull requests"
8574 msgstr ""
8575
8576 #: rhodecode/templates/admin/users/user_edit_advanced.mako:158
8577 msgid "Delete pull requests"
8578 msgstr ""
8579
8580 #: rhodecode/templates/admin/users/user_edit_advanced.mako:167
8581 msgid "Detach Artifacts"
8582 msgstr ""
8583
8584 #: rhodecode/templates/admin/users/user_edit_advanced.mako:170
8342 8585 msgid "Delete Artifacts"
8343 8586 msgstr ""
8344 8587
8345 #: rhodecode/templates/admin/users/user_edit_advanced.mako:165
8588 #: rhodecode/templates/admin/users/user_edit_advanced.mako:180
8346 8589 msgid "New owner for detached objects"
8347 8590 msgstr ""
8348 8591
8349 #: rhodecode/templates/admin/users/user_edit_advanced.mako:172
8592 #: rhodecode/templates/admin/users/user_edit_advanced.mako:188
8350 8593 msgid "When selecting the detach option, the depending objects owned by this user will be assigned to the above user."
8351 8594 msgstr ""
8352 8595
8353 #: rhodecode/templates/admin/users/user_edit_advanced.mako:174
8596 #: rhodecode/templates/admin/users/user_edit_advanced.mako:190
8354 8597 msgid "The delete option will delete the user and all his owned objects!"
8355 8598 msgstr ""
8356 8599
8357 #: rhodecode/templates/admin/users/user_edit_advanced.mako:187
8358 #: rhodecode/templates/data_table/_dt_elements.mako:269
8359 #, python-format
8360 msgid "Confirm to delete this user: %s"
8361 msgstr ""
8362
8363 #: rhodecode/templates/admin/users/user_edit_advanced.mako:189
8600 #: rhodecode/templates/admin/users/user_edit_advanced.mako:205
8364 8601 msgid "Delete this user"
8365 8602 msgstr ""
8366 8603
8367 #: rhodecode/templates/admin/users/user_edit_audit.mako:7
8368 msgid "User Audit Logs"
8369 msgstr ""
8370
8371 #: rhodecode/templates/admin/users/user_edit_audit.mako:10
8604 #: rhodecode/templates/admin/users/user_edit_audit.mako:9
8605 msgid "Audit Logs"
8606 msgstr ""
8607
8608 #: rhodecode/templates/admin/users/user_edit_audit.mako:12
8372 8609 msgid "Download as JSON"
8373 8610 msgstr ""
8374 8611
8375 #: rhodecode/templates/admin/users/user_edit_caches.mako:33
8612 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:62
8613 #, python-format
8614 msgid "Confirm to remove this auth token: %s"
8615 msgstr ""
8616
8617 #: rhodecode/templates/admin/users/user_edit_caches.mako:36
8376 8618 msgid "Invalidate user cache"
8377 8619 msgstr ""
8378 8620
8379 #: rhodecode/templates/admin/users/user_edit_caches.mako:33
8621 #: rhodecode/templates/admin/users/user_edit_caches.mako:36
8380 8622 msgid "Confirm to invalidate user cache"
8381 8623 msgstr ""
8382 8624
8383 #: rhodecode/templates/admin/users/user_edit_emails.mako:5
8625 #: rhodecode/templates/admin/users/user_edit_emails.mako:7
8384 8626 msgid "Additional Email Addresses"
8385 8627 msgstr ""
8386 8628
8387 #: rhodecode/templates/admin/users/user_edit_emails.mako:30
8629 #: rhodecode/templates/admin/users/user_edit_emails.mako:33
8388 8630 #, python-format
8389 8631 msgid "Confirm to delete this email: %s"
8390 8632 msgstr ""
8391 8633
8392 #: rhodecode/templates/admin/users/user_edit_emails.mako:55
8634 #: rhodecode/templates/admin/users/user_edit_emails.mako:58
8393 8635 msgid "New email address"
8394 8636 msgstr ""
8395 8637
8396 #: rhodecode/templates/admin/users/user_edit_groups.mako:12
8638 #: rhodecode/templates/admin/users/user_edit_groups.mako:15
8397 8639 #, python-format
8398 8640 msgid "Add `%s` to user group"
8399 8641 msgstr ""
8400 8642
8401 #: rhodecode/templates/admin/users/user_edit_ips.mako:3
8643 #: rhodecode/templates/admin/users/user_edit_ips.mako:7
8402 8644 msgid "Custom IP Whitelist"
8403 8645 msgstr ""
8404 8646
8405 #: rhodecode/templates/admin/users/user_edit_ips.mako:10
8647 #: rhodecode/templates/admin/users/user_edit_ips.mako:15
8406 8648 msgid "IP Address"
8407 8649 msgstr ""
8408 8650
8409 #: rhodecode/templates/admin/users/user_edit_ips.mako:11
8651 #: rhodecode/templates/admin/users/user_edit_ips.mako:16
8410 8652 msgid "IP Range"
8411 8653 msgstr ""
8412 8654
8413 #: rhodecode/templates/admin/users/user_edit_ips.mako:20
8655 #: rhodecode/templates/admin/users/user_edit_ips.mako:25
8414 8656 #, python-format
8415 8657 msgid "Inherited from %s"
8416 8658 msgstr ""
8417 8659
8418 #: rhodecode/templates/admin/users/user_edit_ips.mako:64
8660 #: rhodecode/templates/admin/users/user_edit_ips.mako:69
8419 8661 msgid ""
8420 8662 "Enter comma separated list of ip addresses like 10.0.0.1,10.0.0.2.\n"
8421 8663 "Use a ip address with a mask 127.0.0.1/24, to create a network match pattern.\n"
8422 8664 "To specify multiple entries on an address range use 127.0.0.1-127.0.0.10 syntax"
8423 8665 msgstr ""
8424 8666
8425 #: rhodecode/templates/admin/users/user_edit_profile.mako:16
8426 #, python-format
8427 msgid "This user was created from external source (%s). Editing some of the settings is limited."
8428 msgstr ""
8429
8430 #: rhodecode/templates/admin/users/user_edit_profile.mako:28
8667 #: rhodecode/templates/admin/users/user_edit_profile.mako:31
8431 8668 msgid "Change the avatar at"
8432 8669 msgstr ""
8433 8670
8434 #: rhodecode/templates/admin/users/user_edit_profile.mako:85
8671 #: rhodecode/templates/admin/users/user_edit_profile.mako:94
8435 8672 msgid "New Password"
8436 8673 msgstr ""
8437 8674
8438 #: rhodecode/templates/admin/users/user_edit_profile.mako:93
8675 #: rhodecode/templates/admin/users/user_edit_profile.mako:102
8439 8676 msgid "New Password Confirmation"
8440 8677 msgstr ""
8441 8678
8442 #: rhodecode/templates/admin/users/user_edit_profile.mako:109
8679 #: rhodecode/templates/admin/users/user_edit_profile.mako:118
8443 8680 #: rhodecode/templates/admin/users/users.mako:87
8444 8681 #: rhodecode/templates/base/perms_summary.mako:145
8445 8682 msgid "Super-admin"
8446 8683 msgstr ""
8447 8684
8448 #: rhodecode/templates/admin/users/user_edit_profile.mako:117
8685 #: rhodecode/templates/admin/users/user_edit_profile.mako:126
8449 8686 msgid "Authentication type"
8450 8687 msgstr ""
8451 8688
8452 #: rhodecode/templates/admin/users/user_edit_profile.mako:121
8689 #: rhodecode/templates/admin/users/user_edit_profile.mako:130
8453 8690 msgid "When user was created using an external source. He is bound to authentication using this method."
8454 8691 msgstr ""
8455 8692
8456 #: rhodecode/templates/admin/users/user_edit_profile.mako:126
8457 msgid "Name in Source of Record"
8458 msgstr ""
8459
8460 8693 #: rhodecode/templates/admin/users/user_edit_profile.mako:135
8694 msgid "Name in Source of Record"
8695 msgstr ""
8696
8697 #: rhodecode/templates/admin/users/user_edit_profile.mako:144
8461 8698 msgid "Language"
8462 8699 msgstr ""
8463 8700
8464 #: rhodecode/templates/admin/users/user_edit_profile.mako:141
8701 #: rhodecode/templates/admin/users/user_edit_profile.mako:150
8465 8702 #, python-format
8466 8703 msgid "User interface language. Help translate %(rc_link)s into your language."
8467 8704 msgstr ""
8468 8705
8469 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:70
8706 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:34
8707 #, python-format
8708 msgid "Confirm to remove ssh key %s"
8709 msgstr ""
8710
8711 #: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:75
8470 8712 msgid "Click add to use this generate SSH key"
8471 8713 msgstr ""
8472 8714
8473 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:3
8715 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:7
8474 8716 msgid "New SSH Key generation"
8475 8717 msgstr ""
8476 8718
8477 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:8
8719 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:13
8478 8720 msgid "Below is a 2048 bit generated SSH RSA key."
8479 8721 msgstr ""
8480 8722
8481 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:9
8723 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:13
8724 msgid "If you use older systems please try to generate a"
8725 msgstr ""
8726
8727 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:13
8728 msgid "legacy format"
8729 msgstr ""
8730
8731 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:14
8482 8732 msgid "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."
8483 8733 msgstr ""
8484 8734
8485 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:11
8735 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:16
8486 8736 msgid "Private key"
8487 8737 msgstr ""
8488 8738
8489 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:27
8739 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:32
8490 8740 msgid "Public key"
8491 8741 msgstr ""
8492 8742
8493 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:38
8494 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:40
8743 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:43
8744 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:45
8495 8745 msgid "Use this generated key"
8496 8746 msgstr ""
8497 8747
8498 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:42
8748 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:47
8499 8749 msgid "Confirmation required on the next screen"
8500 8750 msgstr ""
8501 8751
8502 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:46
8752 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:51
8503 8753 msgid "SSH key generator has been disabled."
8504 8754 msgstr ""
8505 8755
8506 8756 #: rhodecode/templates/admin/users/users.mako:5
8507 8757 msgid "Users administration"
8508 8758 msgstr ""
8509 8759
8510 8760 #: rhodecode/templates/admin/users/users.mako:89
8511 8761 msgid "Auth type"
8512 8762 msgstr ""
8513 8763
8514 8764 #: rhodecode/templates/artifacts/artifact_list.mako:5
8515 8765 msgid "{} Artifacts"
8516 8766 msgstr ""
8517 8767
8518 8768 #: rhodecode/templates/base/base.mako:66
8519 8769 msgid "RhodeCode instance id: {}"
8520 8770 msgstr ""
8521 8771
8522 8772 #: rhodecode/templates/base/base.mako:94
8523 8773 msgid "Super-admin Panel"
8524 8774 msgstr ""
8525 8775
8526 8776 #: rhodecode/templates/base/base.mako:96
8527 8777 msgid "Delegated Admin Panel"
8528 8778 msgstr ""
8529 8779
8530 8780 #: rhodecode/templates/base/base.mako:112
8531 8781 msgid "Authentication"
8532 8782 msgstr ""
8533 8783
8534 8784 #: rhodecode/templates/base/base.mako:114
8535 8785 msgid "Defaults"
8536 8786 msgstr ""
8537 8787
8538 8788 #: rhodecode/templates/base/base.mako:154
8539 8789 #: rhodecode/templates/base/base.mako:194
8540 8790 #: rhodecode/templates/changeset/changeset.mako:154
8541 8791 #: rhodecode/templates/files/files_source_header.mako:57
8542 #: rhodecode/templates/files/files_tree_header.mako:43
8792 #: rhodecode/templates/files/files_tree_header.mako:44
8543 8793 #: rhodecode/templates/summary/components.mako:250
8544 8794 msgid "Show More"
8545 8795 msgstr ""
8546 8796
8547 8797 #: rhodecode/templates/base/base.mako:295
8548 8798 #: rhodecode/templates/base/base.mako:306
8549 8799 msgid "RSS Feed"
8550 8800 msgstr ""
8551 8801
8552 8802 #: rhodecode/templates/base/base.mako:297
8553 8803 msgid "Watch this Repository and actions on it in your personalized journal"
8554 8804 msgstr ""
8555 8805
8556 8806 #: rhodecode/templates/base/base.mako:315
8557 8807 msgid "Fork of"
8558 8808 msgstr ""
8559 8809
8560 8810 #: rhodecode/templates/base/base.mako:332
8561 8811 #, python-format
8562 8812 msgid "Repository locked by %(user)s"
8563 8813 msgstr ""
8564 8814
8565 8815 #: rhodecode/templates/base/base.mako:337
8566 8816 msgid "Repository not locked. Pull repository to lock it."
8567 8817 msgstr ""
8568 8818
8569 8819 #: rhodecode/templates/base/base.mako:353
8570 8820 msgid "This repository has been archived. It is now read-only."
8571 8821 msgstr ""
8572 8822
8573 8823 #: rhodecode/templates/base/base.mako:366
8574 8824 #: rhodecode/templates/data_table/_dt_elements.mako:58
8575 8825 #: rhodecode/templates/data_table/_dt_elements.mako:59
8576 #: rhodecode/templates/data_table/_dt_elements.mako:205
8826 #: rhodecode/templates/data_table/_dt_elements.mako:207
8577 8827 msgid "Summary"
8578 8828 msgstr ""
8579 8829
8580 8830 #: rhodecode/templates/base/base.mako:367
8581 8831 #: rhodecode/templates/data_table/_dt_elements.mako:63
8582 8832 #: rhodecode/templates/data_table/_dt_elements.mako:64
8583 8833 #: rhodecode/templates/files/file_authors_box.mako:30
8584 8834 #: rhodecode/templates/search/search.mako:99
8585 8835 #: rhodecode/templates/summary/components.mako:119
8586 8836 #: rhodecode/templates/summary/components.mako:127
8587 8837 msgid "Commits"
8588 8838 msgstr ""
8589 8839
8590 8840 #: rhodecode/templates/base/base.mako:368
8591 8841 #: rhodecode/templates/data_table/_dt_elements.mako:68
8592 8842 #: rhodecode/templates/data_table/_dt_elements.mako:69
8593 8843 #: rhodecode/templates/files/files.mako:15
8594 8844 #: rhodecode/templates/search/search.mako:99
8595 8845 msgid "Files"
8596 8846 msgstr ""
8597 8847
8598 8848 #: rhodecode/templates/base/base.mako:369
8599 8849 #: rhodecode/templates/bookmarks/bookmarks.mako:66
8600 8850 #: rhodecode/templates/branches/branches.mako:65
8601 8851 #: rhodecode/templates/tags/tags.mako:66
8602 8852 msgid "Compare"
8603 8853 msgstr ""
8604 8854
8605 8855 #: rhodecode/templates/base/base.mako:374
8606 8856 #, python-format
8607 8857 msgid "Show Pull Requests for %s"
8608 8858 msgstr ""
8609 8859
8610 8860 #: rhodecode/templates/base/base.mako:385
8611 8861 msgid "Artifacts"
8612 8862 msgstr ""
8613 8863
8614 8864 #: rhodecode/templates/base/base.mako:391
8615 8865 msgid "Repository Settings"
8616 8866 msgstr ""
8617 8867
8618 8868 #: rhodecode/templates/base/base.mako:397
8619 #: rhodecode/templates/base/base.mako:410
8620 8869 msgid "Options"
8621 8870 msgstr ""
8622 8871
8623 8872 #: rhodecode/templates/base/base.mako:402
8624 8873 msgid "Unlock Repository"
8625 8874 msgstr ""
8626 8875
8627 8876 #: rhodecode/templates/base/base.mako:404
8628 8877 msgid "Lock Repository"
8629 8878 msgstr ""
8630 8879
8631 #: rhodecode/templates/base/base.mako:461
8880 #: rhodecode/templates/base/base.mako:457
8632 8881 msgid "Group Home"
8633 8882 msgstr ""
8634 8883
8635 #: rhodecode/templates/base/base.mako:465
8884 #: rhodecode/templates/base/base.mako:461
8636 8885 msgid "You have admin right to this group, and can edit it"
8637 8886 msgstr ""
8638 8887
8639 #: rhodecode/templates/base/base.mako:465
8888 #: rhodecode/templates/base/base.mako:461
8640 8889 msgid "Group Settings"
8641 8890 msgstr ""
8642 8891
8643 #: rhodecode/templates/base/base.mako:508
8892 #: rhodecode/templates/base/base.mako:504
8644 8893 msgid "Create"
8645 8894 msgstr ""
8646 8895
8647 #: rhodecode/templates/base/base.mako:516
8896 #: rhodecode/templates/base/base.mako:512
8648 8897 msgid "This Repository"
8649 8898 msgstr ""
8650 8899
8900 #: rhodecode/templates/base/base.mako:514
8901 msgid "Create Pull Request"
8902 msgstr ""
8903
8651 8904 #: rhodecode/templates/base/base.mako:518
8652 msgid "Create Pull Request"
8653 msgstr ""
8654
8655 #: rhodecode/templates/base/base.mako:522
8656 8905 msgid "Fork this repository"
8657 8906 msgstr ""
8658 8907
8908 #: rhodecode/templates/base/base.mako:525
8909 msgid "This Repository Group"
8910 msgstr ""
8911
8659 8912 #: rhodecode/templates/base/base.mako:529
8660 msgid "This Repository Group"
8661 msgstr ""
8662
8663 #: rhodecode/templates/base/base.mako:533
8664 #: rhodecode/templates/base/base.mako:549
8665 #: rhodecode/templates/base/base.mako:561
8913 #: rhodecode/templates/base/base.mako:545
8914 #: rhodecode/templates/base/base.mako:557
8666 8915 msgid "New Repository"
8667 8916 msgstr ""
8668 8917
8669 #: rhodecode/templates/base/base.mako:539
8670 #: rhodecode/templates/base/base.mako:553
8671 #: rhodecode/templates/base/base.mako:567
8918 #: rhodecode/templates/base/base.mako:535
8919 #: rhodecode/templates/base/base.mako:549
8920 #: rhodecode/templates/base/base.mako:563
8672 8921 msgid "New Repository Group"
8673 8922 msgstr ""
8674 8923
8675 #: rhodecode/templates/base/base.mako:594
8924 #: rhodecode/templates/base/base.mako:590
8676 8925 msgid "Sign in"
8677 8926 msgstr ""
8678 8927
8679 #: rhodecode/templates/base/base.mako:619
8928 #: rhodecode/templates/base/base.mako:615
8680 8929 msgid "My personal group"
8681 8930 msgstr ""
8682 8931
8683 #: rhodecode/templates/base/base.mako:625
8932 #: rhodecode/templates/base/base.mako:621
8684 8933 #: rhodecode/templates/debug_style/alerts.html:5
8685 8934 #: rhodecode/templates/debug_style/buttons.html:5
8686 8935 #: rhodecode/templates/debug_style/code-block.html:6
8687 8936 #: rhodecode/templates/debug_style/collapsable-content.html:5
8688 8937 #: rhodecode/templates/debug_style/emails.html:5
8689 8938 #: rhodecode/templates/debug_style/form-elements-small.html:5
8690 8939 #: rhodecode/templates/debug_style/form-elements.html:5
8691 8940 #: rhodecode/templates/debug_style/form-inline.html:5
8692 8941 #: rhodecode/templates/debug_style/form-vertical.html:5
8693 8942 #: rhodecode/templates/debug_style/forms.html:5
8694 8943 #: rhodecode/templates/debug_style/icons.html:5
8695 8944 #: rhodecode/templates/debug_style/index.html:12
8696 8945 #: rhodecode/templates/debug_style/labels.html:5
8697 8946 #: rhodecode/templates/debug_style/layout-form-sidebar.html:5
8698 8947 #: rhodecode/templates/debug_style/login.html:6
8699 8948 #: rhodecode/templates/debug_style/panels.html:5
8700 8949 #: rhodecode/templates/debug_style/tables-wide.html:5
8701 8950 #: rhodecode/templates/debug_style/tables.html:5
8702 8951 #: rhodecode/templates/debug_style/typography.html:5
8703 8952 msgid "Style"
8704 8953 msgstr ""
8705 8954
8706 #: rhodecode/templates/base/base.mako:626
8955 #: rhodecode/templates/base/base.mako:622
8707 8956 msgid "[Style]"
8708 8957 msgstr ""
8709 8958
8710 #: rhodecode/templates/base/base.mako:643
8959 #: rhodecode/templates/base/base.mako:639
8711 8960 msgid "No Bookmarks yet."
8712 8961 msgstr ""
8713 8962
8714 #: rhodecode/templates/base/base.mako:681
8963 #: rhodecode/templates/base/base.mako:677
8715 8964 msgid "Sign Out"
8716 8965 msgstr ""
8717 8966
8718 #: rhodecode/templates/base/base.mako:737
8967 #: rhodecode/templates/base/base.mako:725
8968 msgid "dismiss"
8969 msgstr ""
8970
8971 #: rhodecode/templates/base/base.mako:766
8719 8972 msgid "search / go to..."
8720 8973 msgstr ""
8721 8974
8722 #: rhodecode/templates/base/base.mako:780
8975 #: rhodecode/templates/base/base.mako:811
8723 8976 msgid "Show activity journal"
8724 8977 msgstr ""
8725 8978
8726 #: rhodecode/templates/base/base.mako:781
8979 #: rhodecode/templates/base/base.mako:812
8727 8980 #: rhodecode/templates/journal/journal.mako:4
8728 8981 #: rhodecode/templates/journal/journal.mako:14
8729 8982 msgid "Journal"
8730 8983 msgstr ""
8731 8984
8732 #: rhodecode/templates/base/base.mako:786
8985 #: rhodecode/templates/base/base.mako:817
8733 8986 msgid "Show Public activity journal"
8734 8987 msgstr ""
8735 8988
8736 #: rhodecode/templates/base/base.mako:787
8989 #: rhodecode/templates/base/base.mako:818
8737 8990 msgid "Public journal"
8738 8991 msgstr ""
8739 8992
8740 #: rhodecode/templates/base/base.mako:793
8993 #: rhodecode/templates/base/base.mako:824
8741 8994 msgid "Show Gists"
8742 8995 msgstr ""
8743 8996
8744 #: rhodecode/templates/base/base.mako:794
8997 #: rhodecode/templates/base/base.mako:825
8745 8998 msgid "Gists"
8746 8999 msgstr ""
8747 9000
8748 #: rhodecode/templates/base/base.mako:800
9001 #: rhodecode/templates/base/base.mako:831
8749 9002 msgid "Admin settings"
8750 9003 msgstr ""
8751 9004
8752 #: rhodecode/templates/base/base.mako:1074
9005 #: rhodecode/templates/base/base.mako:1135
8753 9006 msgid "Keyboard shortcuts"
8754 9007 msgstr ""
8755 9008
8756 #: rhodecode/templates/base/base.mako:1082
9009 #: rhodecode/templates/base/base.mako:1143
8757 9010 msgid "Site-wide shortcuts"
8758 9011 msgstr ""
8759 9012
8760 9013 #: rhodecode/templates/base/default_perms_box.mako:14
8761 9014 msgid "Inherited Permissions"
8762 9015 msgstr ""
8763 9016
8764 9017 #: rhodecode/templates/base/default_perms_box.mako:15
8765 9018 msgid "Custom Permissions"
8766 9019 msgstr ""
8767 9020
8768 9021 #: rhodecode/templates/base/default_perms_box.mako:17
8769 9022 msgid "Default Global Permissions"
8770 9023 msgstr ""
8771 9024
8772 9025 #: rhodecode/templates/base/default_perms_box.mako:23
8773 9026 msgid "The following options configure the default permissions each user or group will inherit. You can override these permissions for each individual user or user group using individual permissions settings."
8774 9027 msgstr ""
8775 9028
8776 9029 #: rhodecode/templates/base/default_perms_box.mako:27
8777 9030 msgid "Repository Creation"
8778 9031 msgstr ""
8779 9032
8780 9033 #: rhodecode/templates/base/default_perms_box.mako:32
8781 9034 msgid "Permission to create root level repositories. When disabled, users can still create repositories inside their own repository groups."
8782 9035 msgstr ""
8783 9036
8784 9037 #: rhodecode/templates/base/default_perms_box.mako:37
8785 9038 msgid "Repository Creation With Group Write Access"
8786 9039 msgstr ""
8787 9040
8788 9041 #: rhodecode/templates/base/default_perms_box.mako:42
8789 9042 msgid "Write permission given on a repository group will allow creating repositories inside that group."
8790 9043 msgstr ""
8791 9044
8792 9045 #: rhodecode/templates/base/default_perms_box.mako:47
8793 9046 msgid "Repository Forking"
8794 9047 msgstr ""
8795 9048
8796 9049 #: rhodecode/templates/base/default_perms_box.mako:52
8797 9050 msgid "Permission to create root level repository forks. When disabled, users can still fork repositories inside their own repository groups."
8798 9051 msgstr ""
8799 9052
8800 9053 #: rhodecode/templates/base/default_perms_box.mako:57
8801 9054 msgid "Repository Group Creation"
8802 9055 msgstr ""
8803 9056
8804 9057 #: rhodecode/templates/base/default_perms_box.mako:62
8805 9058 msgid "Permission to create root level repository groups. When disabled, repository group admins can still create repository subgroups within their repository groups."
8806 9059 msgstr ""
8807 9060
8808 9061 #: rhodecode/templates/base/default_perms_box.mako:67
8809 9062 msgid "User Group Creation"
8810 9063 msgstr ""
8811 9064
8812 9065 #: rhodecode/templates/base/default_perms_box.mako:72
8813 9066 msgid "Permission to allow user group creation."
8814 9067 msgstr ""
8815 9068
8816 9069 #: rhodecode/templates/base/default_perms_box.mako:78
8817 9070 msgid "Inherit Permissions From The Default User"
8818 9071 msgstr ""
8819 9072
8820 9073 #: rhodecode/templates/base/default_perms_box.mako:83
8821 9074 msgid "Inherit default permissions from the default user. Turn off this option to force explicit permissions for users, even if they are more restrictive than the default user permissions."
8822 9075 msgstr ""
8823 9076
8824 9077 #: rhodecode/templates/base/default_perms_box.mako:102
8825 9078 msgid "Inherit from default settings"
8826 9079 msgstr ""
8827 9080
8828 9081 #: rhodecode/templates/base/default_perms_box.mako:107
8829 9082 #, python-format
8830 9083 msgid ""
8831 9084 "Select to inherit permissions from %s permissions settings, including default IP address whitelist and inheritance of \n"
8832 9085 "permission by members of user groups."
8833 9086 msgstr ""
8834 9087
8835 9088 #: rhodecode/templates/base/issue_tracker_settings.mako:81
8836 9089 msgid "Extra Prefix"
8837 9090 msgstr ""
8838 9091
8839 9092 #: rhodecode/templates/base/issue_tracker_settings.mako:92
8840 9093 msgid "show examples"
8841 9094 msgstr ""
8842 9095
8843 9096 #: rhodecode/templates/base/issue_tracker_settings.mako:160
8844 9097 msgid "Add new"
8845 9098 msgstr ""
8846 9099
8847 9100 #: rhodecode/templates/base/issue_tracker_settings.mako:168
8848 9101 msgid "New Entry"
8849 9102 msgstr ""
8850 9103
8851 9104 #: rhodecode/templates/base/issue_tracker_settings.mako:172
8852 9105 msgid "Confirm to remove this pattern:"
8853 9106 msgstr ""
8854 9107
8855 9108 #: rhodecode/templates/base/issue_tracker_settings.mako:293
8856 #: rhodecode/templates/changeset/changeset_file_comment.mako:271
8857 #: rhodecode/templates/changeset/changeset_file_comment.mako:322
8858 #: rhodecode/templates/data_table/_dt_elements.mako:443
8859 #: rhodecode/templates/files/files_add.mako:61
9109 #: rhodecode/templates/changeset/changeset_file_comment.mako:275
9110 #: rhodecode/templates/changeset/changeset_file_comment.mako:326
9111 #: rhodecode/templates/data_table/_dt_elements.mako:453
9112 #: rhodecode/templates/files/files_add.mako:60
8860 9113 #: rhodecode/templates/files/files_edit.mako:62
8861 9114 msgid "Preview"
8862 9115 msgstr ""
8863 9116
8864 9117 #: rhodecode/templates/base/issue_tracker_settings.mako:294
8865 9118 msgid "Test Pattern Preview"
8866 9119 msgstr ""
8867 9120
8868 9121 #: rhodecode/templates/base/perms_summary.mako:26
8869 9122 msgid "in JSON format"
8870 9123 msgstr ""
8871 9124
8872 9125 #: rhodecode/templates/base/perms_summary.mako:35
8873 9126 #: rhodecode/templates/base/perms_summary.mako:43
8874 9127 msgid "show"
8875 9128 msgstr ""
8876 9129
8877 9130 #: rhodecode/templates/base/perms_summary.mako:36
8878 9131 #: rhodecode/templates/base/perms_summary.mako:44
8879 9132 msgid "none"
8880 9133 msgstr ""
8881 9134
8882 9135 #: rhodecode/templates/base/perms_summary.mako:37
8883 9136 #: rhodecode/templates/commits/changelog_elements.mako:102
8884 #: rhodecode/templates/files/base.mako:11
9137 #: rhodecode/templates/files/base.mako:26
8885 9138 msgid "merge"
8886 9139 msgstr ""
8887 9140
8888 9141 #: rhodecode/templates/base/perms_summary.mako:38
8889 9142 msgid "push"
8890 9143 msgstr ""
8891 9144
8892 9145 #: rhodecode/templates/base/perms_summary.mako:39
8893 9146 msgid "push force"
8894 9147 msgstr ""
8895 9148
8896 9149 #: rhodecode/templates/base/perms_summary.mako:45
8897 9150 msgid "read"
8898 9151 msgstr ""
8899 9152
8900 9153 #: rhodecode/templates/base/perms_summary.mako:46
8901 9154 msgid "write"
8902 9155 msgstr ""
8903 9156
8904 9157 #: rhodecode/templates/base/perms_summary.mako:47
8905 9158 msgid "admin"
8906 9159 msgstr ""
8907 9160
8908 9161 #: rhodecode/templates/base/perms_summary.mako:55
8909 9162 msgid "No permissions defined"
8910 9163 msgstr ""
8911 9164
8912 9165 #: rhodecode/templates/base/perms_summary.mako:63
8913 9166 #: rhodecode/templates/base/perms_summary.mako:170
8914 9167 #: rhodecode/templates/base/perms_summary.mako:243
8915 9168 msgid "Permission"
8916 9169 msgstr ""
8917 9170
8918 9171 #: rhodecode/templates/base/perms_summary.mako:65
8919 9172 #: rhodecode/templates/base/perms_summary.mako:245
8920 9173 msgid "Edit Permission"
8921 9174 msgstr ""
8922 9175
8923 9176 #: rhodecode/templates/base/perms_summary.mako:119
8924 9177 #: rhodecode/templates/base/perms_summary.mako:128
8925 9178 msgid "edit global"
8926 9179 msgstr ""
8927 9180
8928 9181 #: rhodecode/templates/base/perms_summary.mako:136
8929 9182 msgid "Repository default permission"
8930 9183 msgstr ""
8931 9184
8932 9185 #: rhodecode/templates/base/perms_summary.mako:139
8933 9186 msgid "Repository group default permission"
8934 9187 msgstr ""
8935 9188
8936 9189 #: rhodecode/templates/base/perms_summary.mako:142
8937 9190 msgid "User group default permission"
8938 9191 msgstr ""
8939 9192
8940 9193 #: rhodecode/templates/base/perms_summary.mako:148
8941 9194 msgid "Inherit permissions"
8942 9195 msgstr ""
8943 9196
8944 9197 #: rhodecode/templates/base/perms_summary.mako:151
8945 9198 msgid "Create repositories"
8946 9199 msgstr ""
8947 9200
8948 9201 #: rhodecode/templates/base/perms_summary.mako:154
8949 9202 msgid "Fork repositories"
8950 9203 msgstr ""
8951 9204
8952 9205 #: rhodecode/templates/base/perms_summary.mako:157
8953 9206 msgid "Create repository groups"
8954 9207 msgstr ""
8955 9208
8956 9209 #: rhodecode/templates/base/perms_summary.mako:160
8957 9210 msgid "Create user groups"
8958 9211 msgstr ""
8959 9212
8960 9213 #: rhodecode/templates/base/perms_summary.mako:172
8961 9214 msgid "Edit Branch Permission"
8962 9215 msgstr ""
8963 9216
8964 9217 #: rhodecode/templates/base/perms_summary.mako:286
8965 9218 msgid "overridden by"
8966 9219 msgstr ""
8967 9220
8968 9221 #: rhodecode/templates/base/perms_summary.mako:321
8969 9222 msgid "No matching permission defined"
8970 9223 msgstr ""
8971 9224
8972 #: rhodecode/templates/base/root.mako:155
9225 #: rhodecode/templates/base/root.mako:156
8973 9226 msgid "Please enable JavaScript to use RhodeCode Enterprise"
8974 9227 msgstr ""
8975 9228
8976 9229 #: rhodecode/templates/base/vcs_settings.mako:16
8977 9230 msgid "Require SSL for vcs operations"
8978 9231 msgstr ""
8979 9232
8980 9233 #: rhodecode/templates/base/vcs_settings.mako:19
8981 9234 msgid "Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable."
8982 9235 msgstr ""
8983 9236
8984 9237 #: rhodecode/templates/base/vcs_settings.mako:29
8985 9238 msgid "Main Storage Location"
8986 9239 msgstr ""
8987 9240
8988 9241 #: rhodecode/templates/base/vcs_settings.mako:37
8989 9242 msgid "Click to unlock. You must restart RhodeCode in order to make this setting take effect."
8990 9243 msgstr ""
8991 9244
8992 9245 #: rhodecode/templates/base/vcs_settings.mako:41
8993 9246 msgid "Repository location change is disabled. You can enable this by changing the `allow_repo_location_change` inside .ini file."
8994 9247 msgstr ""
8995 9248
8996 9249 #: rhodecode/templates/base/vcs_settings.mako:48
8997 9250 msgid "Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required."
8998 9251 msgstr ""
8999 9252
9000 9253 #: rhodecode/templates/base/vcs_settings.mako:57
9001 9254 msgid "Internal Hooks"
9002 9255 msgstr ""
9003 9256
9004 9257 #: rhodecode/templates/base/vcs_settings.mako:63
9005 9258 msgid "Show repository size after push"
9006 9259 msgstr ""
9007 9260
9008 9261 #: rhodecode/templates/base/vcs_settings.mako:67
9009 9262 msgid "Trigger a hook that calculates repository size after each push."
9010 9263 msgstr ""
9011 9264
9012 9265 #: rhodecode/templates/base/vcs_settings.mako:71
9013 9266 msgid "Execute pre/post push hooks"
9014 9267 msgstr ""
9015 9268
9016 9269 #: rhodecode/templates/base/vcs_settings.mako:74
9017 9270 msgid "Execute Built in pre/post push hooks. This also executes rcextensions hooks."
9018 9271 msgstr ""
9019 9272
9020 9273 #: rhodecode/templates/base/vcs_settings.mako:78
9021 9274 msgid "Execute pre/post pull hooks"
9022 9275 msgstr ""
9023 9276
9024 9277 #: rhodecode/templates/base/vcs_settings.mako:81
9025 9278 msgid "Execute Built in pre/post pull hooks. This also executes rcextensions hooks."
9026 9279 msgstr ""
9027 9280
9028 9281 #: rhodecode/templates/base/vcs_settings.mako:91
9029 9282 msgid "Mercurial Settings"
9030 9283 msgstr ""
9031 9284
9032 9285 #: rhodecode/templates/base/vcs_settings.mako:96
9033 9286 msgid "Enable largefiles extension"
9034 9287 msgstr ""
9035 9288
9036 9289 #: rhodecode/templates/base/vcs_settings.mako:100
9037 9290 msgid "Enable Largefiles extensions for all repositories."
9038 9291 msgstr ""
9039 9292
9040 9293 #: rhodecode/templates/base/vcs_settings.mako:102
9041 9294 msgid "Enable Largefiles extensions for this repository."
9042 9295 msgstr ""
9043 9296
9044 9297 #: rhodecode/templates/base/vcs_settings.mako:113
9045 9298 msgid "Filesystem location where Mercurial largefile objects should be stored."
9046 9299 msgstr ""
9047 9300
9048 9301 #: rhodecode/templates/base/vcs_settings.mako:119
9049 9302 msgid "Set repositories as publishing"
9050 9303 msgstr ""
9051 9304
9052 9305 #: rhodecode/templates/base/vcs_settings.mako:119
9053 9306 msgid "Set repository as publishing"
9054 9307 msgstr ""
9055 9308
9056 9309 #: rhodecode/templates/base/vcs_settings.mako:122
9057 9310 msgid "When this is enabled all commits in the repository are seen as public commits by clients."
9058 9311 msgstr ""
9059 9312
9060 9313 #: rhodecode/templates/base/vcs_settings.mako:127
9061 9314 msgid "Enable hgsubversion extension"
9062 9315 msgstr ""
9063 9316
9064 9317 #: rhodecode/templates/base/vcs_settings.mako:130
9065 9318 msgid "Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type."
9066 9319 msgstr ""
9067 9320
9068 9321 #: rhodecode/templates/base/vcs_settings.mako:136
9069 9322 msgid "Enable Evolve and Topic extension"
9070 9323 msgstr ""
9071 9324
9072 9325 #: rhodecode/templates/base/vcs_settings.mako:140
9073 9326 msgid "Enable Evolve and Topic extensions for all repositories."
9074 9327 msgstr ""
9075 9328
9076 9329 #: rhodecode/templates/base/vcs_settings.mako:142
9077 9330 msgid "Enable Evolve and Topic extensions for this repository."
9078 9331 msgstr ""
9079 9332
9080 9333 #: rhodecode/templates/base/vcs_settings.mako:153
9081 9334 msgid "Git Settings"
9082 9335 msgstr ""
9083 9336
9084 9337 #: rhodecode/templates/base/vcs_settings.mako:158
9085 9338 msgid "Enable lfs extension"
9086 9339 msgstr ""
9087 9340
9088 9341 #: rhodecode/templates/base/vcs_settings.mako:162
9089 9342 msgid "Enable lfs extensions for all repositories."
9090 9343 msgstr ""
9091 9344
9092 9345 #: rhodecode/templates/base/vcs_settings.mako:164
9093 9346 msgid "Enable lfs extensions for this repository."
9094 9347 msgstr ""
9095 9348
9096 9349 #: rhodecode/templates/base/vcs_settings.mako:175
9097 9350 msgid "Filesystem location where Git lfs objects should be stored."
9098 9351 msgstr ""
9099 9352
9100 9353 #: rhodecode/templates/base/vcs_settings.mako:186
9101 9354 msgid "Global Subversion Settings"
9102 9355 msgstr ""
9103 9356
9104 9357 #: rhodecode/templates/base/vcs_settings.mako:192
9105 9358 msgid "Proxy subversion HTTP requests"
9106 9359 msgstr ""
9107 9360
9108 9361 #: rhodecode/templates/base/vcs_settings.mako:196
9109 9362 msgid "Subversion HTTP Support. Enables communication with SVN over HTTP protocol."
9110 9363 msgstr ""
9111 9364
9112 9365 #: rhodecode/templates/base/vcs_settings.mako:197
9113 9366 msgid "SVN Protocol setup Documentation"
9114 9367 msgstr ""
9115 9368
9116 9369 #: rhodecode/templates/base/vcs_settings.mako:203
9117 9370 msgid "Subversion HTTP Server URL"
9118 9371 msgstr ""
9119 9372
9120 9373 #: rhodecode/templates/base/vcs_settings.mako:209
9121 9374 msgid "Generate Apache Config"
9122 9375 msgstr ""
9123 9376
9124 9377 #: rhodecode/templates/base/vcs_settings.mako:221
9125 9378 msgid "Subversion Settings"
9126 9379 msgstr ""
9127 9380
9128 9381 #: rhodecode/templates/base/vcs_settings.mako:226
9129 9382 msgid "Repository patterns"
9130 9383 msgstr ""
9131 9384
9132 9385 #: rhodecode/templates/base/vcs_settings.mako:230
9133 9386 msgid "Patterns for identifying SVN branches and tags. For recursive search, use \"*\". Eg.: \"/branches/*\""
9134 9387 msgstr ""
9135 9388
9136 9389 #: rhodecode/templates/base/vcs_settings.mako:294
9137 9390 msgid "Pull Request Settings"
9138 9391 msgstr ""
9139 9392
9140 9393 #: rhodecode/templates/base/vcs_settings.mako:299
9141 9394 msgid "Enable server-side merge for pull requests"
9142 9395 msgstr ""
9143 9396
9144 9397 #: rhodecode/templates/base/vcs_settings.mako:302
9145 9398 msgid "Note: when this feature is enabled, it only runs hooks defined in the rcextension package. Custom hooks added on the Admin -> Settings -> Hooks page will not be run when pull requests are automatically merged from the web interface."
9146 9399 msgstr ""
9147 9400
9148 9401 #: rhodecode/templates/base/vcs_settings.mako:306
9149 9402 msgid "Invalidate and relocate inline comments during update"
9150 9403 msgstr ""
9151 9404
9152 9405 #: rhodecode/templates/base/vcs_settings.mako:309
9153 9406 msgid "During the update of a pull request, the position of inline comments will be updated and outdated inline comments will be hidden."
9154 9407 msgstr ""
9155 9408
9156 9409 #: rhodecode/templates/base/vcs_settings.mako:318
9157 9410 msgid "Diff cache"
9158 9411 msgstr ""
9159 9412
9160 9413 #: rhodecode/templates/base/vcs_settings.mako:323
9161 9414 msgid "Enable caching diffs for pull requests cache and commits"
9162 9415 msgstr ""
9163 9416
9164 9417 #: rhodecode/templates/base/vcs_settings.mako:332
9165 9418 msgid "Mercurial Pull Request Settings"
9166 9419 msgstr ""
9167 9420
9168 9421 #: rhodecode/templates/base/vcs_settings.mako:338
9169 9422 msgid "Use rebase as merge strategy"
9170 9423 msgstr ""
9171 9424
9172 9425 #: rhodecode/templates/base/vcs_settings.mako:341
9173 9426 msgid "Use rebase instead of creating a merge commit when merging via web interface."
9174 9427 msgstr ""
9175 9428
9176 9429 #: rhodecode/templates/base/vcs_settings.mako:346
9177 9430 msgid "Close branch before merging it"
9178 9431 msgstr ""
9179 9432
9180 9433 #: rhodecode/templates/base/vcs_settings.mako:349
9181 9434 msgid "Close branch before merging it into destination branch. No effect when rebase strategy is use."
9182 9435 msgstr ""
9183 9436
9184 9437 #: rhodecode/templates/bookmarks/bookmarks.mako:5
9185 9438 #, python-format
9186 9439 msgid "%s Bookmarks"
9187 9440 msgstr ""
9188 9441
9189 9442 #: rhodecode/templates/bookmarks/bookmarks.mako:28
9190 9443 msgid "Compare Selected Bookmarks"
9191 9444 msgstr ""
9192 9445
9193 9446 #: rhodecode/templates/bookmarks/bookmarks.mako:34
9194 9447 msgid "bookmarks"
9195 9448 msgstr ""
9196 9449
9197 9450 #: rhodecode/templates/branches/branches.mako:5
9198 9451 #, python-format
9199 9452 msgid "%s Branches"
9200 9453 msgstr ""
9201 9454
9202 9455 #: rhodecode/templates/branches/branches.mako:28
9203 9456 msgid "Compare Selected Branches"
9204 9457 msgstr ""
9205 9458
9206 9459 #: rhodecode/templates/branches/branches.mako:34
9207 9460 msgid "branches"
9208 9461 msgstr ""
9209 9462
9210 9463 #: rhodecode/templates/changeset/changeset.mako:9
9211 9464 msgid "{} Commit"
9212 9465 msgstr ""
9213 9466
9214 9467 #: rhodecode/templates/changeset/changeset.mako:78
9215 9468 #: rhodecode/templates/commits/changelog_elements.mako:56
9216 9469 #: rhodecode/templates/files/files_source_header.mako:48
9217 9470 #: rhodecode/templates/files/files_tree_header.mako:35
9218 9471 #: rhodecode/templates/summary/summary_commits.mako:43
9219 9472 msgid "Copy the full commit id"
9220 9473 msgstr ""
9221 9474
9222 9475 #: rhodecode/templates/changeset/changeset.mako:83
9223 9476 msgid "Commit phase"
9224 9477 msgstr ""
9225 9478
9226 9479 #: rhodecode/templates/changeset/changeset.mako:90
9227 9480 #: rhodecode/templates/changeset/changeset.mako:97
9228 9481 msgid "Evolve State"
9229 9482 msgstr ""
9230 9483
9231 9484 #: rhodecode/templates/changeset/changeset.mako:91
9232 9485 msgid "obsolete"
9233 9486 msgstr ""
9234 9487
9235 9488 #: rhodecode/templates/changeset/changeset.mako:98
9236 9489 msgid "hidden"
9237 9490 msgstr ""
9238 9491
9239 9492 #: rhodecode/templates/changeset/changeset.mako:117
9240 9493 msgid "Commit navigation"
9241 9494 msgstr ""
9242 9495
9243 9496 #: rhodecode/templates/changeset/changeset.mako:120
9244 9497 msgid "Parent Commit"
9245 9498 msgstr ""
9246 9499
9247 9500 #: rhodecode/templates/changeset/changeset.mako:120
9248 9501 msgid "parent"
9249 9502 msgstr ""
9250 9503
9251 9504 #: rhodecode/templates/changeset/changeset.mako:124
9252 9505 msgid "Child Commit"
9253 9506 msgstr ""
9254 9507
9255 9508 #: rhodecode/templates/changeset/changeset.mako:124
9256 9509 msgid "child"
9257 9510 msgstr ""
9258 9511
9259 9512 #: rhodecode/templates/changeset/changeset.mako:132
9260 9513 msgid "Diff options"
9261 9514 msgstr ""
9262 9515
9263 9516 #: rhodecode/templates/changeset/changeset.mako:136
9264 9517 msgid "Raw Diff"
9265 9518 msgstr ""
9266 9519
9267 9520 #: rhodecode/templates/changeset/changeset.mako:140
9268 9521 msgid "Patch Diff"
9269 9522 msgstr ""
9270 9523
9271 9524 #: rhodecode/templates/changeset/changeset.mako:144
9272 9525 msgid "Download Diff"
9273 9526 msgstr ""
9274 9527
9275 9528 #: rhodecode/templates/changeset/changeset.mako:224
9276 9529 msgid "No Child Commits"
9277 9530 msgstr ""
9278 9531
9279 9532 #: rhodecode/templates/changeset/changeset.mako:263
9280 9533 msgid "No Parent Commits"
9281 9534 msgstr ""
9282 9535
9283 9536 #: rhodecode/templates/changeset/changeset_file_comment.mako:33
9284 9537 #: rhodecode/templates/pullrequests/pullrequest_show.mako:401
9285 9538 msgid "Resolved by comment #{}"
9286 9539 msgstr ""
9287 9540
9288 9541 #: rhodecode/templates/changeset/changeset_file_comment.mako:40
9289 9542 msgid "Click to resolve this comment"
9290 9543 msgstr ""
9291 9544
9292 9545 #: rhodecode/templates/changeset/changeset_file_comment.mako:70
9293 9546 #: rhodecode/templates/changeset/changeset_file_comment.mako:72
9294 9547 msgid "pull request !{}"
9295 9548 msgstr ""
9296 9549
9297 9550 #: rhodecode/templates/changeset/changeset_file_comment.mako:77
9298 9551 msgid "Status change on commit"
9299 9552 msgstr ""
9300 9553
9301 9554 #: rhodecode/templates/changeset/changeset_file_comment.mako:85
9302 9555 #: rhodecode/templates/compare/compare_diff.mako:139
9303 9556 #: rhodecode/templates/email_templates/commit_comment.mako:53
9304 9557 msgid "Commit status"
9305 9558 msgstr ""
9306 9559
9307 9560 #: rhodecode/templates/changeset/changeset_file_comment.mako:94
9308 9561 msgid "Pull request author"
9309 9562 msgstr ""
9310 9563
9311 9564 #: rhodecode/templates/changeset/changeset_file_comment.mako:95
9312 9565 msgid "author"
9313 9566 msgstr ""
9314 9567
9315 9568 #: rhodecode/templates/changeset/changeset_file_comment.mako:103
9316 9569 #: rhodecode/templates/changeset/changeset_file_comment.mako:119
9317 9570 msgid "Outdated comment from pull request version v{0}, latest v{1}"
9318 9571 msgstr ""
9319 9572
9320 9573 #: rhodecode/templates/changeset/changeset_file_comment.mako:107
9321 9574 #: rhodecode/templates/changeset/changeset_file_comment.mako:122
9322 9575 msgid "Comment from pull request version v{0}, latest v{1}"
9323 9576 msgstr ""
9324 9577
9325 9578 #: rhodecode/templates/changeset/changeset_file_comment.mako:149
9326 9579 #: rhodecode/templates/changeset/changeset_file_comment.mako:152
9327 9580 msgid "Prev"
9328 9581 msgstr ""
9329 9582
9330 9583 #: rhodecode/templates/changeset/changeset_file_comment.mako:150
9331 9584 #: rhodecode/templates/changeset/changeset_file_comment.mako:153
9332 9585 msgid "Next"
9333 9586 msgstr ""
9334 9587
9335 #: rhodecode/templates/changeset/changeset_file_comment.mako:188
9588 #: rhodecode/templates/changeset/changeset_file_comment.mako:192
9336 9589 msgid "Leave a comment on this Pull Request."
9337 9590 msgstr ""
9338 9591
9339 #: rhodecode/templates/changeset/changeset_file_comment.mako:190
9592 #: rhodecode/templates/changeset/changeset_file_comment.mako:194
9340 9593 msgid "Leave a comment on {} commits in this range."
9341 9594 msgstr ""
9342 9595
9343 #: rhodecode/templates/changeset/changeset_file_comment.mako:192
9596 #: rhodecode/templates/changeset/changeset_file_comment.mako:196
9344 9597 msgid "Leave a comment on this Commit."
9345 9598 msgstr ""
9346 9599
9347 #: rhodecode/templates/changeset/changeset_file_comment.mako:279
9348 #: rhodecode/templates/codeblocks/diffs.mako:79
9600 #: rhodecode/templates/changeset/changeset_file_comment.mako:283
9601 #: rhodecode/templates/codeblocks/diffs.mako:83
9349 9602 msgid "You need to be logged in to leave comments."
9350 9603 msgstr ""
9351 9604
9352 #: rhodecode/templates/changeset/changeset_file_comment.mako:280
9353 #: rhodecode/templates/codeblocks/diffs.mako:79
9605 #: rhodecode/templates/changeset/changeset_file_comment.mako:284
9606 #: rhodecode/templates/codeblocks/diffs.mako:83
9354 9607 msgid "Login now"
9355 9608 msgstr ""
9356 9609
9357 #: rhodecode/templates/changeset/changeset_file_comment.mako:327
9610 #: rhodecode/templates/changeset/changeset_file_comment.mako:331
9358 9611 msgid "Mark as"
9359 9612 msgstr ""
9360 9613
9361 #: rhodecode/templates/changeset/changeset_file_comment.mako:350
9614 #: rhodecode/templates/changeset/changeset_file_comment.mako:354
9362 9615 #: rhodecode/templates/files/files_upload.mako:86
9363 9616 msgid "Drag'n Drop files here or"
9364 9617 msgstr ""
9365 9618
9366 #: rhodecode/templates/changeset/changeset_file_comment.mako:350
9619 #: rhodecode/templates/changeset/changeset_file_comment.mako:354
9367 9620 #: rhodecode/templates/files/files_upload.mako:86
9368 9621 msgid "Choose your files"
9369 9622 msgstr ""
9370 9623
9371 #: rhodecode/templates/changeset/changeset_file_comment.mako:353
9624 #: rhodecode/templates/changeset/changeset_file_comment.mako:357
9372 9625 msgid "uploading..."
9373 9626 msgstr ""
9374 9627
9375 #: rhodecode/templates/changeset/changeset_file_comment.mako:384
9628 #: rhodecode/templates/changeset/changeset_file_comment.mako:388
9376 9629 #: rhodecode/templates/compare/compare_diff.mako:108
9377 9630 #: rhodecode/templates/compare/compare_diff.mako:116
9378 9631 #: rhodecode/templates/compare/compare_diff.mako:124
9379 9632 #: rhodecode/templates/compare/compare_diff.mako:126
9380 9633 msgid "Comment"
9381 9634 msgstr ""
9382 9635
9383 #: rhodecode/templates/changeset/changeset_file_comment.mako:403
9384 #: rhodecode/templates/pullrequests/pullrequest_show.mako:16
9636 #: rhodecode/templates/changeset/changeset_file_comment.mako:407
9637 #: rhodecode/templates/pullrequests/pullrequest_show.mako:39
9385 9638 #: rhodecode/templates/pullrequests/pullrequest_show.mako:103
9386 9639 #: rhodecode/templates/pullrequests/pullrequests.mako:31
9387 9640 msgid "Closed"
9388 9641 msgstr ""
9389 9642
9390 #: rhodecode/templates/changeset/changeset_file_comment.mako:412
9643 #: rhodecode/templates/changeset/changeset_file_comment.mako:416
9391 9644 msgid "Comments parsed using {} syntax."
9392 9645 msgstr ""
9393 9646
9394 #: rhodecode/templates/changeset/changeset_file_comment.mako:413
9647 #: rhodecode/templates/changeset/changeset_file_comment.mako:417
9395 9648 msgid "Use @username inside this text to send notification to this RhodeCode user"
9396 9649 msgstr ""
9397 9650
9398 #: rhodecode/templates/changeset/changeset_file_comment.mako:414
9651 #: rhodecode/templates/changeset/changeset_file_comment.mako:418
9399 9652 msgid "and"
9400 9653 msgstr ""
9401 9654
9402 #: rhodecode/templates/changeset/changeset_file_comment.mako:415
9655 #: rhodecode/templates/changeset/changeset_file_comment.mako:419
9403 9656 msgid "Start typing with / for certain actions to be triggered via text box."
9404 9657 msgstr ""
9405 9658
9406 #: rhodecode/templates/changeset/changeset_file_comment.mako:416
9659 #: rhodecode/templates/changeset/changeset_file_comment.mako:420
9407 9660 msgid "actions supported."
9408 9661 msgstr ""
9409 9662
9410 9663 #: rhodecode/templates/changeset/changeset_range.mako:5
9411 9664 #, python-format
9412 9665 msgid "%s Commits"
9413 9666 msgstr ""
9414 9667
9415 9668 #: rhodecode/templates/changeset/changeset_range.mako:33
9416 9669 msgid "Commit Range"
9417 9670 msgstr ""
9418 9671
9419 9672 #: rhodecode/templates/changeset/changeset_range.mako:42
9420 9673 msgid "Range"
9421 9674 msgstr ""
9422 9675
9423 9676 #: rhodecode/templates/changeset/changeset_range.mako:60
9424 9677 msgid "Diff Option"
9425 9678 msgstr ""
9426 9679
9427 9680 #: rhodecode/templates/changeset/changeset_range.mako:71
9428 9681 msgid "Show combined diff"
9429 9682 msgstr ""
9430 9683
9431 9684 #: rhodecode/templates/changeset/diff_block.mako:7
9432 9685 msgid "The requested commit is too big and content was truncated."
9433 9686 msgstr ""
9434 9687
9435 9688 #: rhodecode/templates/changeset/diff_block.mako:7
9436 9689 #: rhodecode/templates/changeset/diff_block.mako:10
9437 9690 #: rhodecode/templates/changeset/diff_block.mako:25
9438 9691 #: rhodecode/templates/changeset/diff_block.mako:46
9439 #: rhodecode/templates/codeblocks/diffs.mako:204
9440 #: rhodecode/templates/codeblocks/diffs.mako:268
9692 #: rhodecode/templates/codeblocks/diffs.mako:208
9693 #: rhodecode/templates/codeblocks/diffs.mako:272
9441 9694 msgid "Showing a big diff might take some time and resources, continue?"
9442 9695 msgstr ""
9443 9696
9444 9697 #: rhodecode/templates/changeset/diff_block.mako:7
9445 9698 #: rhodecode/templates/changeset/diff_block.mako:10
9446 9699 #: rhodecode/templates/changeset/diff_block.mako:25
9447 9700 #: rhodecode/templates/changeset/diff_block.mako:46
9448 #: rhodecode/templates/codeblocks/diffs.mako:204
9449 #: rhodecode/templates/codeblocks/diffs.mako:268
9701 #: rhodecode/templates/codeblocks/diffs.mako:208
9702 #: rhodecode/templates/codeblocks/diffs.mako:272
9450 9703 msgid "Show full diff"
9451 9704 msgstr ""
9452 9705
9453 9706 #: rhodecode/templates/changeset/diff_block.mako:10
9454 9707 msgid "The requested file is too big and its content is not shown."
9455 9708 msgstr ""
9456 9709
9457 9710 #: rhodecode/templates/changeset/diff_block.mako:25
9458 9711 #: rhodecode/templates/changeset/diff_block.mako:46
9459 9712 msgid "Diff was truncated. File content available only in full diff."
9460 9713 msgstr ""
9461 9714
9462 #: rhodecode/templates/codeblocks/diffs.mako:125
9463 msgid "Expand all files"
9464 msgstr ""
9465
9466 #: rhodecode/templates/codeblocks/diffs.mako:127
9467 msgid "Collapse all files"
9468 msgstr ""
9469
9470 #: rhodecode/templates/codeblocks/diffs.mako:137
9715 #: rhodecode/templates/codeblocks/diffs.mako:141
9471 9716 msgid "not available in this view"
9472 9717 msgstr ""
9473 9718
9474 #: rhodecode/templates/codeblocks/diffs.mako:146
9719 #: rhodecode/templates/codeblocks/diffs.mako:150
9475 9720 msgid "{} unresolved"
9476 9721 msgstr ""
9477 9722
9478 #: rhodecode/templates/codeblocks/diffs.mako:149
9723 #: rhodecode/templates/codeblocks/diffs.mako:153
9479 9724 msgid "0 unresolved"
9480 9725 msgstr ""
9481 9726
9482 #: rhodecode/templates/codeblocks/diffs.mako:152
9727 #: rhodecode/templates/codeblocks/diffs.mako:156
9483 9728 msgid "{} Resolved"
9484 9729 msgstr ""
9485 9730
9486 #: rhodecode/templates/codeblocks/diffs.mako:166
9731 #: rhodecode/templates/codeblocks/diffs.mako:170
9487 9732 msgid "0 General"
9488 9733 msgstr ""
9489 9734
9490 #: rhodecode/templates/codeblocks/diffs.mako:174
9735 #: rhodecode/templates/codeblocks/diffs.mako:178
9491 9736 msgid "0 Inline"
9492 9737 msgstr ""
9493 9738
9494 #: rhodecode/templates/codeblocks/diffs.mako:185
9495 #: rhodecode/templates/codeblocks/diffs.mako:190
9739 #: rhodecode/templates/codeblocks/diffs.mako:189
9740 #: rhodecode/templates/codeblocks/diffs.mako:194
9496 9741 msgid "{} Outdated"
9497 9742 msgstr ""
9498 9743
9499 #: rhodecode/templates/codeblocks/diffs.mako:187
9744 #: rhodecode/templates/codeblocks/diffs.mako:191
9500 9745 msgid "show outdated"
9501 9746 msgstr ""
9502 9747
9503 #: rhodecode/templates/codeblocks/diffs.mako:188
9748 #: rhodecode/templates/codeblocks/diffs.mako:192
9504 9749 msgid "hide outdated"
9505 9750 msgstr ""
9506 9751
9507 #: rhodecode/templates/codeblocks/diffs.mako:203
9752 #: rhodecode/templates/codeblocks/diffs.mako:207
9508 9753 msgid "The requested changes are too big and content was truncated."
9509 9754 msgstr ""
9510 9755
9511 #: rhodecode/templates/codeblocks/diffs.mako:227
9756 #: rhodecode/templates/codeblocks/diffs.mako:231
9512 9757 msgid "Some changes may be hidden"
9513 9758 msgstr ""
9514 9759
9515 #: rhodecode/templates/codeblocks/diffs.mako:229
9760 #: rhodecode/templates/codeblocks/diffs.mako:233
9516 9761 msgid "No files"
9517 9762 msgstr ""
9518 9763
9519 #: rhodecode/templates/codeblocks/diffs.mako:268
9764 #: rhodecode/templates/codeblocks/diffs.mako:272
9520 9765 msgid "The requested commit or file is too big and content was truncated."
9521 9766 msgstr ""
9522 9767
9523 #: rhodecode/templates/codeblocks/diffs.mako:275
9768 #: rhodecode/templates/codeblocks/diffs.mako:279
9524 9769 #, python-format
9525 9770 msgid "This diff has been collapsed as it changes many lines, (%i lines changed)"
9526 9771 msgstr ""
9527 9772
9528 #: rhodecode/templates/codeblocks/diffs.mako:277
9773 #: rhodecode/templates/codeblocks/diffs.mako:281
9529 9774 msgid "Show them"
9530 9775 msgstr ""
9531 9776
9532 #: rhodecode/templates/codeblocks/diffs.mako:280
9777 #: rhodecode/templates/codeblocks/diffs.mako:284
9533 9778 msgid "Hide them"
9534 9779 msgstr ""
9535 9780
9536 #: rhodecode/templates/codeblocks/diffs.mako:316
9537 #: rhodecode/templates/codeblocks/diffs.mako:335
9781 #: rhodecode/templates/codeblocks/diffs.mako:320
9782 #: rhodecode/templates/codeblocks/diffs.mako:339
9538 9783 msgid "Unmatched/outdated inline comments below"
9539 9784 msgstr ""
9540 9785
9541 #: rhodecode/templates/codeblocks/diffs.mako:341
9786 #: rhodecode/templates/codeblocks/diffs.mako:345
9542 9787 msgid "Unmatched/outdated comments below"
9543 9788 msgstr ""
9544 9789
9545 #: rhodecode/templates/codeblocks/diffs.mako:409
9546 msgid "File was deleted in this version. There are still outdated/unresolved comments attached to it."
9547 msgstr ""
9548
9549 #: rhodecode/templates/codeblocks/diffs.mako:476
9550 msgid "Copy the full path"
9551 msgstr ""
9552
9553 #: rhodecode/templates/codeblocks/diffs.mako:543
9554 #: rhodecode/templates/codeblocks/diffs.mako:561
9790 #: rhodecode/templates/codeblocks/diffs.mako:419
9791 msgid "This file was removed from diff during updates to this pull-request."
9792 msgstr ""
9793
9794 #: rhodecode/templates/codeblocks/diffs.mako:420
9795 msgid "There are still outdated/unresolved comments attached to it."
9796 msgstr ""
9797
9798 #: rhodecode/templates/codeblocks/diffs.mako:487
9799 msgid "Copy file path"
9800 msgstr ""
9801
9802 #: rhodecode/templates/codeblocks/diffs.mako:554
9803 #: rhodecode/templates/codeblocks/diffs.mako:572
9555 9804 #, python-format
9556 9805 msgid "Show file at commit: %(commit_id)s"
9557 9806 msgstr ""
9558 9807
9559 #: rhodecode/templates/codeblocks/diffs.mako:545
9560 #: rhodecode/templates/codeblocks/diffs.mako:552
9808 #: rhodecode/templates/codeblocks/diffs.mako:556
9809 #: rhodecode/templates/codeblocks/diffs.mako:563
9561 9810 msgid "Show file before"
9562 9811 msgstr ""
9563 9812
9564 #: rhodecode/templates/codeblocks/diffs.mako:550
9565 #: rhodecode/templates/codeblocks/diffs.mako:568
9813 #: rhodecode/templates/codeblocks/diffs.mako:561
9814 #: rhodecode/templates/codeblocks/diffs.mako:579
9566 9815 #, python-format
9567 9816 msgid "File not present at commit: %(commit_id)s"
9568 9817 msgstr ""
9569 9818
9570 #: rhodecode/templates/codeblocks/diffs.mako:563
9571 #: rhodecode/templates/codeblocks/diffs.mako:570
9819 #: rhodecode/templates/codeblocks/diffs.mako:574
9820 #: rhodecode/templates/codeblocks/diffs.mako:581
9572 9821 msgid "Show file after"
9573 9822 msgstr ""
9574 9823
9575 #: rhodecode/templates/codeblocks/diffs.mako:577
9824 #: rhodecode/templates/codeblocks/diffs.mako:588
9576 9825 msgid "Show comments"
9577 9826 msgstr ""
9578 9827
9579 #: rhodecode/templates/codeblocks/diffs.mako:577
9828 #: rhodecode/templates/codeblocks/diffs.mako:588
9580 9829 msgid "Hide comments"
9581 9830 msgstr ""
9582 9831
9583 #: rhodecode/templates/codeblocks/diffs.mako:646
9584 #: rhodecode/templates/codeblocks/diffs.mako:689
9585 #: rhodecode/templates/codeblocks/diffs.mako:745
9832 #: rhodecode/templates/codeblocks/diffs.mako:658
9833 #: rhodecode/templates/codeblocks/diffs.mako:701
9834 #: rhodecode/templates/codeblocks/diffs.mako:757
9586 9835 msgid "comments including outdated"
9587 9836 msgstr ""
9588 9837
9589 #: rhodecode/templates/codeblocks/diffs.mako:648
9590 #: rhodecode/templates/codeblocks/diffs.mako:691
9591 #: rhodecode/templates/codeblocks/diffs.mako:747
9838 #: rhodecode/templates/codeblocks/diffs.mako:660
9839 #: rhodecode/templates/codeblocks/diffs.mako:703
9840 #: rhodecode/templates/codeblocks/diffs.mako:759
9592 9841 msgid "comments"
9593 9842 msgstr ""
9594 9843
9595 #: rhodecode/templates/codeblocks/diffs.mako:816
9844 #: rhodecode/templates/codeblocks/diffs.mako:828
9596 9845 msgid "Toggle wide diff"
9597 9846 msgstr ""
9598 9847
9599 #: rhodecode/templates/codeblocks/diffs.mako:824
9848 #: rhodecode/templates/codeblocks/diffs.mako:836
9600 9849 msgid "View diff as side by side"
9601 9850 msgstr ""
9602 9851
9603 #: rhodecode/templates/codeblocks/diffs.mako:826
9852 #: rhodecode/templates/codeblocks/diffs.mako:838
9604 9853 msgid "Side by Side"
9605 9854 msgstr ""
9606 9855
9607 #: rhodecode/templates/codeblocks/diffs.mako:831
9856 #: rhodecode/templates/codeblocks/diffs.mako:843
9608 9857 msgid "View diff as unified"
9609 9858 msgstr ""
9610 9859
9611 #: rhodecode/templates/codeblocks/diffs.mako:832
9612 msgid "Unified"
9613 msgstr ""
9614
9615 #: rhodecode/templates/codeblocks/diffs.mako:837
9616 msgid "Turn off: Show the diff as commit range"
9617 msgstr ""
9618
9619 #: rhodecode/templates/codeblocks/diffs.mako:840
9620 #: rhodecode/templates/codeblocks/diffs.mako:847
9621 msgid "Range Diff"
9622 msgstr ""
9623
9624 9860 #: rhodecode/templates/codeblocks/diffs.mako:844
9861 msgid "Unified"
9862 msgstr ""
9863
9864 #: rhodecode/templates/codeblocks/diffs.mako:849
9865 msgid "Turn off: Show the diff as commit range"
9866 msgstr ""
9867
9868 #: rhodecode/templates/codeblocks/diffs.mako:852
9869 #: rhodecode/templates/codeblocks/diffs.mako:859
9870 msgid "Range Diff"
9871 msgstr ""
9872
9873 #: rhodecode/templates/codeblocks/diffs.mako:856
9625 9874 msgid "Show the diff as commit range"
9626 9875 msgstr ""
9627 9876
9628 #: rhodecode/templates/codeblocks/diffs.mako:888
9877 #: rhodecode/templates/codeblocks/diffs.mako:900
9629 9878 msgid "Disabled on range diff"
9630 9879 msgstr ""
9631 9880
9632 #: rhodecode/templates/codeblocks/diffs.mako:1119
9881 #: rhodecode/templates/codeblocks/diffs.mako:1131
9633 9882 msgid "..."
9634 9883 msgstr ""
9635 9884
9636 9885 #: rhodecode/templates/codeblocks/source.mako:22
9637 9886 msgid "view annotation from before this change"
9638 9887 msgstr ""
9639 9888
9640 9889 #: rhodecode/templates/commits/changelog.mako:6
9641 9890 #, python-format
9642 9891 msgid "%s Changelog"
9643 9892 msgstr ""
9644 9893
9645 9894 #: rhodecode/templates/commits/changelog.mako:38
9646 9895 msgid "Clear filter"
9647 9896 msgstr ""
9648 9897
9649 9898 #: rhodecode/templates/commits/changelog.mako:45
9650 9899 msgid "Hide obsolete/hidden"
9651 9900 msgstr ""
9652 9901
9653 9902 #: rhodecode/templates/commits/changelog.mako:47
9654 9903 msgid "Show obsolete/hidden"
9655 9904 msgstr ""
9656 9905
9657 9906 #: rhodecode/templates/commits/changelog.mako:50
9658 9907 msgid "Show hidden"
9659 9908 msgstr ""
9660 9909
9661 9910 #: rhodecode/templates/commits/changelog.mako:59
9662 9911 #: rhodecode/templates/compare/compare_diff.mako:93
9663 9912 #, python-format
9664 9913 msgid "Compare fork with %s"
9665 9914 msgstr ""
9666 9915
9667 9916 #: rhodecode/templates/commits/changelog.mako:69
9668 9917 #, python-format
9669 9918 msgid "Compare fork with Parent (%s)"
9670 9919 msgstr ""
9671 9920
9672 9921 #: rhodecode/templates/commits/changelog.mako:107
9673 9922 msgid "Clear selection"
9674 9923 msgstr ""
9675 9924
9676 9925 #: rhodecode/templates/commits/changelog.mako:110
9677 9926 msgid "Select second commit"
9678 9927 msgstr ""
9679 9928
9680 9929 #: rhodecode/templates/commits/changelog.mako:116
9681 9930 msgid "Commit Message"
9682 9931 msgstr ""
9683 9932
9684 9933 #: rhodecode/templates/commits/changelog.mako:118
9685 9934 #: rhodecode/templates/summary/summary_commits.mako:10
9686 9935 msgid "Age"
9687 9936 msgstr ""
9688 9937
9689 9938 #: rhodecode/templates/commits/changelog.mako:121
9690 9939 #: rhodecode/templates/summary/summary_commits.mako:12
9691 9940 msgid "Refs"
9692 9941 msgstr ""
9693 9942
9694 9943 #: rhodecode/templates/commits/changelog.mako:262
9695 9944 msgid "Branch filter"
9696 9945 msgstr ""
9697 9946
9698 9947 #: rhodecode/templates/commits/changelog.mako:323
9699 9948 msgid "There are no changes yet"
9700 9949 msgstr ""
9701 9950
9702 9951 #: rhodecode/templates/commits/changelog_elements.mako:8
9703 9952 msgid "load previous"
9704 9953 msgstr ""
9705 9954
9706 9955 #: rhodecode/templates/commits/changelog_elements.mako:35
9707 9956 #: rhodecode/templates/summary/summary_commits.mako:27
9708 9957 #, python-format
9709 9958 msgid ""
9710 9959 "Commit status: %s\n"
9711 9960 "Click to open associated pull request #%s"
9712 9961 msgstr ""
9713 9962
9714 9963 #: rhodecode/templates/commits/changelog_elements.mako:39
9715 9964 #: rhodecode/templates/summary/summary_commits.mako:31
9716 9965 msgid "Commit status: {}"
9717 9966 msgstr ""
9718 9967
9719 9968 #: rhodecode/templates/commits/changelog_elements.mako:45
9720 9969 #: rhodecode/templates/summary/summary_commits.mako:37
9721 9970 msgid "Commit status: Not Reviewed"
9722 9971 msgstr ""
9723 9972
9724 9973 #: rhodecode/templates/commits/changelog_elements.mako:63
9725 9974 msgid "{} commit phase"
9726 9975 msgstr ""
9727 9976
9728 9977 #: rhodecode/templates/commits/changelog_elements.mako:69
9729 9978 msgid "Obsolete Evolve State"
9730 9979 msgstr ""
9731 9980
9732 9981 #: rhodecode/templates/commits/changelog_elements.mako:74
9733 9982 msgid "Hidden Evolve State"
9734 9983 msgstr ""
9735 9984
9736 9985 #: rhodecode/templates/commits/changelog_elements.mako:80
9737 #: rhodecode/templates/compare/compare_commits.mako:48
9738 #: rhodecode/templates/pullrequests/pullrequest_show.mako:582
9986 #: rhodecode/templates/compare/compare_commits.mako:46
9987 #: rhodecode/templates/pullrequests/pullrequest_show.mako:597
9739 9988 #: rhodecode/templates/search/search_commit.mako:34
9740 9989 msgid "Expand commit message"
9741 9990 msgstr ""
9742 9991
9743 9992 #: rhodecode/templates/commits/changelog_elements.mako:108
9744 #: rhodecode/templates/files/base.mako:36
9993 #: rhodecode/templates/files/base.mako:51
9745 9994 #: rhodecode/templates/summary/summary_commits.mako:78
9746 9995 #, python-format
9747 9996 msgid "Branch %s"
9748 9997 msgstr ""
9749 9998
9750 9999 #: rhodecode/templates/commits/changelog_elements.mako:116
9751 #: rhodecode/templates/files/base.mako:17
10000 #: rhodecode/templates/files/base.mako:32
9752 10001 #: rhodecode/templates/summary/summary_commits.mako:64
9753 10002 #, python-format
9754 10003 msgid "Bookmark %s"
9755 10004 msgstr ""
9756 10005
9757 10006 #: rhodecode/templates/commits/changelog_elements.mako:124
9758 #: rhodecode/templates/files/base.mako:27
10007 #: rhodecode/templates/files/base.mako:42
9759 10008 #: rhodecode/templates/summary/summary_commits.mako:71
9760 10009 #, python-format
9761 10010 msgid "Tag %s"
9762 10011 msgstr ""
9763 10012
9764 10013 #: rhodecode/templates/commits/changelog_elements.mako:135
9765 10014 #: rhodecode/templates/summary/summary_commits.mako:87
9766 10015 msgid "Commit has comments"
9767 10016 msgstr ""
9768 10017
9769 10018 #: rhodecode/templates/commits/changelog_elements.mako:150
9770 10019 msgid "load next"
9771 10020 msgstr ""
9772 10021
9773 10022 #: rhodecode/templates/commits/changelog_file_history.mako:33
9774 10023 msgid "Show File"
9775 10024 msgstr ""
9776 10025
9777 10026 #: rhodecode/templates/commits/changelog_file_history.mako:38
9778 10027 msgid "Diff File"
9779 10028 msgstr ""
9780 10029
9781 10030 #: rhodecode/templates/commits/changelog_file_history.mako:46
9782 10031 msgid "Show Full History"
9783 10032 msgstr ""
9784 10033
9785 10034 #: rhodecode/templates/compare/compare_commits.mako:5
9786 msgid "Common Ancestor Commit"
9787 msgstr ""
9788
9789 #: rhodecode/templates/compare/compare_commits.mako:8
9790 msgid "Compare was calculated based on this shared commit."
9791 msgstr ""
9792
9793 #: rhodecode/templates/compare/compare_commits.mako:17
9794 #: rhodecode/templates/pullrequests/pullrequest_show.mako:543
10035 msgid "Compare was calculated based on this common ancestor commit"
10036 msgstr ""
10037
10038 #: rhodecode/templates/compare/compare_commits.mako:15
10039 #: rhodecode/templates/pullrequests/pullrequest_show.mako:558
9795 10040 msgid "Time"
9796 10041 msgstr ""
9797 10042
9798 #: rhodecode/templates/compare/compare_commits.mako:66
10043 #: rhodecode/templates/compare/compare_commits.mako:64
9799 10044 msgid "No commits in this compare"
9800 10045 msgstr ""
9801 10046
9802 10047 #: rhodecode/templates/compare/compare_diff.mako:7
9803 10048 #: rhodecode/templates/compare/compare_diff.mako:9
9804 10049 #, python-format
9805 10050 msgid "%s Compare"
9806 10051 msgstr ""
9807 10052
9808 10053 #: rhodecode/templates/compare/compare_diff.mako:38
9809 10054 #: rhodecode/templates/compare/compare_diff.mako:90
9810 10055 #: rhodecode/templates/compare/compare_diff.mako:114
9811 10056 #: rhodecode/templates/compare/compare_diff.mako:119
9812 10057 msgid "Compare Commits"
9813 10058 msgstr ""
9814 10059
9815 10060 #: rhodecode/templates/compare/compare_diff.mako:40
9816 10061 msgid "for file"
9817 10062 msgstr ""
9818 10063
9819 10064 #: rhodecode/templates/compare/compare_diff.mako:56
9820 10065 msgid "Target"
9821 10066 msgstr ""
9822 10067
9823 10068 #: rhodecode/templates/compare/compare_diff.mako:70
9824 10069 #: rhodecode/templates/files/files_source.mako:100
9825 10070 msgid "Source"
9826 10071 msgstr ""
9827 10072
9828 10073 #: rhodecode/templates/compare/compare_diff.mako:102
9829 10074 msgid "Compare with origin"
9830 10075 msgstr ""
9831 10076
9832 10077 #: rhodecode/templates/compare/compare_diff.mako:107
9833 10078 #: rhodecode/templates/compare/compare_diff.mako:108
9834 10079 #: rhodecode/templates/compare/compare_diff.mako:114
9835 10080 #: rhodecode/templates/compare/compare_diff.mako:115
9836 10081 #: rhodecode/templates/compare/compare_diff.mako:116
9837 10082 #: rhodecode/templates/compare/compare_diff.mako:126
9838 10083 msgid "Action unavailable in current view"
9839 10084 msgstr ""
9840 10085
9841 10086 #: rhodecode/templates/compare/compare_diff.mako:107
9842 10087 #: rhodecode/templates/compare/compare_diff.mako:115
9843 10088 #: rhodecode/templates/compare/compare_diff.mako:120
9844 10089 msgid "Swap"
9845 10090 msgstr ""
9846 10091
9847 10092 #: rhodecode/templates/compare/compare_diff.mako:110
9848 10093 msgid "Compare commits, branches, bookmarks or tags."
9849 10094 msgstr ""
9850 10095
9851 10096 #: rhodecode/templates/data_table/_dt_elements.mako:73
9852 10097 #: rhodecode/templates/data_table/_dt_elements.mako:74
9853 10098 msgid "Fork"
9854 10099 msgstr ""
9855 10100
9856 10101 #: rhodecode/templates/data_table/_dt_elements.mako:95
9857 10102 msgid "Mercurial repository"
9858 10103 msgstr ""
9859 10104
9860 10105 #: rhodecode/templates/data_table/_dt_elements.mako:97
9861 10106 msgid "Git repository"
9862 10107 msgstr ""
9863 10108
9864 10109 #: rhodecode/templates/data_table/_dt_elements.mako:99
9865 10110 msgid "Subversion repository"
9866 10111 msgstr ""
9867 10112
9868 10113 #: rhodecode/templates/data_table/_dt_elements.mako:106
9869 10114 msgid "Public repository"
9870 10115 msgstr ""
9871 10116
9872 10117 #: rhodecode/templates/data_table/_dt_elements.mako:116
9873 10118 msgid "This repository is being created in a background task"
9874 10119 msgstr ""
9875 10120
9876 10121 #: rhodecode/templates/data_table/_dt_elements.mako:117
9877 10122 msgid "creating..."
9878 10123 msgstr ""
9879 10124
9880 10125 #: rhodecode/templates/data_table/_dt_elements.mako:149
9881 10126 msgid "No commits yet"
9882 10127 msgstr ""
9883 10128
9884 10129 #: rhodecode/templates/data_table/_dt_elements.mako:156
9885 10130 #: rhodecode/templates/data_table/_dt_elements.mako:158
9886 10131 #, python-format
9887 10132 msgid "Subscribe to %s rss feed"
9888 10133 msgstr ""
9889 10134
9890 10135 #: rhodecode/templates/data_table/_dt_elements.mako:164
9891 10136 #: rhodecode/templates/data_table/_dt_elements.mako:166
9892 10137 #, python-format
9893 10138 msgid "Subscribe to %s atom feed"
9894 10139 msgstr ""
9895 10140
9896 #: rhodecode/templates/data_table/_dt_elements.mako:189
10141 #: rhodecode/templates/data_table/_dt_elements.mako:191
9897 10142 msgid "Creating"
9898 10143 msgstr ""
9899 10144
9900 #: rhodecode/templates/data_table/_dt_elements.mako:191
10145 #: rhodecode/templates/data_table/_dt_elements.mako:193
9901 10146 #: rhodecode/templates/hovercards/hovercard_pull_request.mako:10
9902 10147 msgid "Created"
9903 10148 msgstr ""
9904 10149
9905 #: rhodecode/templates/data_table/_dt_elements.mako:234
10150 #: rhodecode/templates/data_table/_dt_elements.mako:236
9906 10151 msgid "personal"
9907 10152 msgstr ""
9908 10153
9909 #: rhodecode/templates/data_table/_dt_elements.mako:281
9910 #, python-format
9911 msgid "Confirm to delete this user group: %s"
9912 msgstr ""
9913
9914 #: rhodecode/templates/data_table/_dt_elements.mako:297
9915 #: rhodecode/templates/user_group/user_group.mako:4
9916 msgid "User group"
9917 msgstr ""
9918
9919 #: rhodecode/templates/data_table/_dt_elements.mako:379
9920 #: rhodecode/templates/pullrequests/pullrequest_show.mako:51
9921 msgid "Pull request !{}"
9922 msgstr ""
9923
9924 10154 #: rhodecode/templates/data_table/_dt_elements.mako:387
10155 #: rhodecode/templates/pullrequests/pullrequest_show.mako:50
10156 msgid "Pull request !{}"
10157 msgstr ""
10158
10159 #: rhodecode/templates/data_table/_dt_elements.mako:395
9925 10160 msgid "Work in progress"
9926 10161 msgstr ""
9927 10162
9928 #: rhodecode/templates/data_table/_dt_elements.mako:421
10163 #: rhodecode/templates/data_table/_dt_elements.mako:429
9929 10164 msgid "Info"
9930 10165 msgstr ""
9931 10166
9932 #: rhodecode/templates/data_table/_dt_elements.mako:427
9933 #, python-format
9934 msgid "Confirm to delete this artifact: %s"
9935 msgstr ""
9936
9937 #: rhodecode/templates/data_table/_dt_elements.mako:460
10167 #: rhodecode/templates/data_table/_dt_elements.mako:470
9938 10168 #, python-format
9939 10169 msgid "Parsed using %s syntax"
9940 10170 msgstr ""
9941 10171
9942 10172 #: rhodecode/templates/debug_style/buttons.html:131
9943 10173 msgid "Confirm to remove this field: Field"
9944 10174 msgstr ""
9945 10175
9946 10176 #: rhodecode/templates/debug_style/form-elements.html:107
9947 10177 msgid "Default"
9948 10178 msgstr ""
9949 10179
9950 10180 #: rhodecode/templates/debug_style/form-elements.html:513
9951 10181 #: rhodecode/templates/debug_style/form-elements.html:565
9952 10182 #: rhodecode/templates/debug_style/forms.html:236
9953 10183 msgid "Chosen group members"
9954 10184 msgstr ""
9955 10185
9956 10186 #: rhodecode/templates/debug_style/form-elements.html:525
9957 10187 #: rhodecode/templates/debug_style/form-elements.html:569
9958 10188 #: rhodecode/templates/debug_style/forms.html:240
9959 10189 msgid "Remove all elements"
9960 10190 msgstr ""
9961 10191
9962 10192 #: rhodecode/templates/debug_style/form-elements.html:535
9963 10193 #: rhodecode/templates/debug_style/form-elements.html:579
9964 10194 #: rhodecode/templates/debug_style/forms.html:250
9965 10195 msgid "Available members"
9966 10196 msgstr ""
9967 10197
9968 10198 #: rhodecode/templates/debug_style/form-elements.html:543
9969 10199 #: rhodecode/templates/debug_style/form-elements.html:587
9970 10200 #: rhodecode/templates/debug_style/forms.html:258
9971 10201 msgid "Add all elements"
9972 10202 msgstr ""
9973 10203
9974 10204 #: rhodecode/templates/debug_style/forms.html:119
9975 10205 msgid "Some text..."
9976 10206 msgstr ""
9977 10207
9978 10208 #: rhodecode/templates/debug_style/forms.html:122
9979 10209 #: rhodecode/templates/debug_style/forms.html:255
9980 10210 msgid "Variable Item"
9981 10211 msgstr ""
9982 10212
9983 10213 #: rhodecode/templates/debug_style/forms.html:252
9984 10214 msgid "Some example text..."
9985 10215 msgstr ""
9986 10216
9987 10217 #: rhodecode/templates/debug_style/index.html:5
9988 10218 msgid "Debug Style"
9989 10219 msgstr ""
9990 10220
9991 10221 #: rhodecode/templates/debug_style/index.html:54
9992 10222 msgid "Index"
9993 10223 msgstr ""
9994 10224
9995 10225 #: rhodecode/templates/debug_style/index.html:56
9996 10226 msgid "Typography"
9997 10227 msgstr ""
9998 10228
9999 10229 #: rhodecode/templates/debug_style/index.html:57
10000 10230 msgid "Forms"
10001 10231 msgstr ""
10002 10232
10003 10233 #: rhodecode/templates/debug_style/index.html:58
10004 10234 msgid "Buttons"
10005 10235 msgstr ""
10006 10236
10007 10237 #: rhodecode/templates/debug_style/index.html:59
10008 10238 msgid "Labels"
10009 10239 msgstr ""
10010 10240
10011 10241 #: rhodecode/templates/debug_style/index.html:60
10012 10242 msgid "Alerts"
10013 10243 msgstr ""
10014 10244
10015 10245 #: rhodecode/templates/debug_style/index.html:61
10016 10246 msgid "Tables"
10017 10247 msgstr ""
10018 10248
10019 10249 #: rhodecode/templates/debug_style/index.html:62
10020 10250 msgid "Tables wide"
10021 10251 msgstr ""
10022 10252
10023 10253 #: rhodecode/templates/debug_style/index.html:63
10024 10254 msgid "Collapsable Content"
10025 10255 msgstr ""
10026 10256
10027 10257 #: rhodecode/templates/debug_style/index.html:65
10028 10258 msgid "Layout form with sidebar"
10029 10259 msgstr ""
10030 10260
10031 10261 #: rhodecode/templates/debug_style/index.html:66
10032 10262 msgid "Login"
10033 10263 msgstr ""
10034 10264
10035 10265 #: rhodecode/templates/debug_style/index.html:67
10036 10266 msgid "Login 2"
10037 10267 msgstr ""
10038 10268
10039 10269 #: rhodecode/templates/debug_style/index.html:68
10040 10270 msgid "Code blocks"
10041 10271 msgstr ""
10042 10272
10043 10273 #: rhodecode/templates/debug_style/index.html:71
10044 10274 msgid "Panels"
10045 10275 msgstr ""
10046 10276
10047 10277 #: rhodecode/templates/debug_style/index.html:74
10048 10278 msgid "Form elements"
10049 10279 msgstr ""
10050 10280
10051 10281 #: rhodecode/templates/debug_style/index.html:75
10052 10282 msgid "Form elements small"
10053 10283 msgstr ""
10054 10284
10055 10285 #: rhodecode/templates/debug_style/index.html:76
10056 10286 msgid "Form inline elements"
10057 10287 msgstr ""
10058 10288
10059 10289 #: rhodecode/templates/debug_style/index.html:77
10060 10290 msgid "Form vertical"
10061 10291 msgstr ""
10062 10292
10063 10293 #: rhodecode/templates/debug_style/login.html:28
10064 10294 msgid "Sign in to your account"
10065 10295 msgstr ""
10066 10296
10067 10297 #: rhodecode/templates/debug_style/login.html:46
10068 10298 msgid "(Forgot password?)"
10069 10299 msgstr ""
10070 10300
10071 10301 #: rhodecode/templates/debug_style/login.html:56
10072 10302 msgid "Don't have an account ?"
10073 10303 msgstr ""
10074 10304
10075 10305 #: rhodecode/templates/email_templates/base.mako:75
10076 #: rhodecode/templates/email_templates/base.mako:519
10306 #: rhodecode/templates/email_templates/base.mako:597
10077 10307 msgid "This is a notification from RhodeCode."
10078 10308 msgstr ""
10079 10309
10080 #: rhodecode/templates/email_templates/base.mako:501
10310 #: rhodecode/templates/email_templates/base.mako:577
10081 10311 msgid "RhodeCode"
10082 10312 msgstr ""
10083 10313
10084 10314 #: rhodecode/templates/email_templates/commit_comment.mako:23
10085 10315 #: rhodecode/templates/email_templates/commit_comment.mako:26
10086 10316 #: rhodecode/templates/email_templates/commit_comment.mako:28
10087 10317 #: rhodecode/templates/email_templates/pull_request_comment.mako:24
10088 10318 #: rhodecode/templates/email_templates/pull_request_comment.mako:27
10089 10319 #: rhodecode/templates/email_templates/pull_request_comment.mako:29
10090 10320 msgid "[mention]"
10091 10321 msgstr ""
10092 10322
10093 10323 #: rhodecode/templates/email_templates/commit_comment.mako:23
10094 10324 msgid "{user} left a {comment_type} on file `{comment_file}` in commit `{commit_id}`"
10095 10325 msgstr ""
10096 10326
10097 10327 #: rhodecode/templates/email_templates/commit_comment.mako:23
10098 10328 #: rhodecode/templates/email_templates/commit_comment.mako:26
10099 10329 #: rhodecode/templates/email_templates/commit_comment.mako:28
10100 10330 msgid "in the `{repo_name}` repository"
10101 10331 msgstr ""
10102 10332
10103 10333 #: rhodecode/templates/email_templates/commit_comment.mako:26
10104 10334 msgid "[status: {status}] {user} left a {comment_type} on commit `{commit_id}`"
10105 10335 msgstr ""
10106 10336
10107 10337 #: rhodecode/templates/email_templates/commit_comment.mako:28
10108 10338 msgid "{user} left a {comment_type} on commit `{commit_id}`"
10109 10339 msgstr ""
10110 10340
10111 10341 #: rhodecode/templates/email_templates/commit_comment.mako:50
10112 10342 #: rhodecode/templates/email_templates/pull_request_comment.mako:60
10113 10343 msgid "Comment link"
10114 10344 msgstr ""
10115 10345
10116 10346 #: rhodecode/templates/email_templates/commit_comment.mako:53
10117 10347 #: rhodecode/templates/email_templates/commit_comment.mako:129
10118 10348 msgid "Status was changed to"
10119 10349 msgstr ""
10120 10350
10121 10351 #: rhodecode/templates/email_templates/commit_comment.mako:58
10122 10352 #: rhodecode/templates/email_templates/commit_comment.mako:141
10123 10353 #: rhodecode/templates/search/search_commit.mako:12
10124 10354 #: rhodecode/templates/summary/summary_commits.mako:9
10125 10355 msgid "Commit message"
10126 10356 msgstr ""
10127 10357
10128 10358 #: rhodecode/templates/email_templates/commit_comment.mako:61
10129 10359 #: rhodecode/templates/email_templates/pull_request_comment.mako:74
10130 10360 msgid "File: {comment_file} on line {comment_line}"
10131 10361 msgstr ""
10132 10362
10133 10363 #: rhodecode/templates/email_templates/commit_comment.mako:65
10134 10364 #: rhodecode/templates/email_templates/commit_comment.mako:155
10135 10365 #: rhodecode/templates/email_templates/pull_request_comment.mako:78
10136 10366 #: rhodecode/templates/email_templates/pull_request_comment.mako:186
10137 10367 msgid "`TODO` number"
10138 10368 msgstr ""
10139 10369
10140 10370 #: rhodecode/templates/email_templates/commit_comment.mako:67
10141 10371 #: rhodecode/templates/email_templates/commit_comment.mako:157
10142 10372 #: rhodecode/templates/email_templates/pull_request_comment.mako:80
10143 10373 #: rhodecode/templates/email_templates/pull_request_comment.mako:188
10144 10374 msgid "`Note` number"
10145 10375 msgstr ""
10146 10376
10147 10377 #: rhodecode/templates/email_templates/commit_comment.mako:99
10148 10378 #: rhodecode/templates/email_templates/pull_request_comment.mako:120
10149 10379 msgid "left a"
10150 10380 msgstr ""
10151 10381
10152 10382 #: rhodecode/templates/email_templates/commit_comment.mako:102
10153 10383 msgid "{comment_type} on file `{comment_file}` in commit."
10154 10384 msgstr ""
10155 10385
10156 10386 #: rhodecode/templates/email_templates/commit_comment.mako:104
10157 10387 msgid "{comment_type} on commit."
10158 10388 msgstr ""
10159 10389
10160 10390 #: rhodecode/templates/email_templates/commit_comment.mako:109
10161 10391 msgid "of repository"
10162 10392 msgstr ""
10163 10393
10164 10394 #: rhodecode/templates/email_templates/commit_comment.mako:127
10165 10395 msgid "Commit Status"
10166 10396 msgstr ""
10167 10397
10168 10398 #: rhodecode/templates/email_templates/commit_comment.mako:147
10169 10399 #: rhodecode/templates/email_templates/pull_request_comment.mako:178
10170 10400 #: rhodecode/templates/search/search_path.mako:9
10171 10401 msgid "File"
10172 10402 msgstr ""
10173 10403
10174 10404 #: rhodecode/templates/email_templates/commit_comment.mako:148
10175 10405 #: rhodecode/templates/email_templates/pull_request_comment.mako:179
10176 10406 msgid "`{comment_file}` on line {comment_line}"
10177 10407 msgstr ""
10178 10408
10179 10409 #: rhodecode/templates/email_templates/commit_comment.mako:167
10180 10410 #: rhodecode/templates/email_templates/pull_request_comment.mako:198
10181 10411 msgid "Reply"
10182 10412 msgstr ""
10183 10413
10184 10414 #: rhodecode/templates/email_templates/pull_request_comment.mako:24
10185 10415 msgid "{user} left a {comment_type} on file `{comment_file}` in pull request !{pr_id}: \"{pr_title}\""
10186 10416 msgstr ""
10187 10417
10188 10418 #: rhodecode/templates/email_templates/pull_request_comment.mako:27
10189 10419 msgid "[status: {status}] {user} left a {comment_type} on pull request !{pr_id}: \"{pr_title}\""
10190 10420 msgstr ""
10191 10421
10192 10422 #: rhodecode/templates/email_templates/pull_request_comment.mako:29
10193 10423 msgid "{user} left a {comment_type} on pull request !{pr_id}: \"{pr_title}\""
10194 10424 msgstr ""
10195 10425
10196 10426 #: rhodecode/templates/email_templates/pull_request_comment.mako:62
10197 10427 #: rhodecode/templates/hovercards/hovercard_pull_request.mako:24
10198 10428 msgid "Pull Request"
10199 10429 msgstr ""
10200 10430
10201 10431 #: rhodecode/templates/email_templates/pull_request_comment.mako:64
10202 10432 #: rhodecode/templates/email_templates/pull_request_review.mako:39
10203 10433 #: rhodecode/templates/email_templates/pull_request_update.mako:39
10204 10434 msgid "Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}"
10205 10435 msgstr ""
10206 10436
10207 10437 #: rhodecode/templates/email_templates/pull_request_comment.mako:67
10208 10438 msgid "{user} submitted pull request !{pr_id} status: *{status}*"
10209 10439 msgstr ""
10210 10440
10211 10441 #: rhodecode/templates/email_templates/pull_request_comment.mako:70
10212 10442 msgid "{user} submitted pull request !{pr_id} status: *{status} and closed*"
10213 10443 msgstr ""
10214 10444
10215 10445 #: rhodecode/templates/email_templates/pull_request_comment.mako:123
10216 10446 msgid "{comment_type} on file `{comment_file}` in pull request."
10217 10447 msgstr ""
10218 10448
10219 10449 #: rhodecode/templates/email_templates/pull_request_comment.mako:125
10220 10450 msgid "{comment_type} on pull request."
10221 10451 msgstr ""
10222 10452
10223 10453 #: rhodecode/templates/email_templates/pull_request_comment.mako:130
10224 10454 #: rhodecode/templates/email_templates/pull_request_comment.mako:159
10225 10455 #: rhodecode/templates/email_templates/pull_request_review.mako:89
10226 10456 #: rhodecode/templates/email_templates/pull_request_review.mako:105
10227 10457 #: rhodecode/templates/email_templates/pull_request_update.mako:101
10228 10458 #: rhodecode/templates/email_templates/pull_request_update.mako:117
10229 10459 msgid "Pull request"
10230 10460 msgstr ""
10231 10461
10232 10462 #: rhodecode/templates/email_templates/pull_request_comment.mako:148
10233 10463 msgid "Review Status"
10234 10464 msgstr ""
10235 10465
10236 10466 #: rhodecode/templates/email_templates/pull_request_comment.mako:151
10237 10467 msgid "Closed pull request with status"
10238 10468 msgstr ""
10239 10469
10240 10470 #: rhodecode/templates/email_templates/pull_request_comment.mako:153
10241 10471 msgid "Submitted review status"
10242 10472 msgstr ""
10243 10473
10244 10474 #: rhodecode/templates/email_templates/pull_request_comment.mako:168
10245 10475 #: rhodecode/templates/email_templates/pull_request_review.mako:114
10246 10476 #: rhodecode/templates/email_templates/pull_request_update.mako:126
10247 10477 msgid "Commit Flow"
10248 10478 msgstr ""
10249 10479
10250 10480 #: rhodecode/templates/email_templates/pull_request_comment.mako:170
10251 10481 #: rhodecode/templates/email_templates/pull_request_comment.mako:172
10252 10482 #: rhodecode/templates/email_templates/pull_request_review.mako:116
10253 10483 #: rhodecode/templates/email_templates/pull_request_review.mako:118
10254 10484 #: rhodecode/templates/email_templates/pull_request_update.mako:128
10255 10485 #: rhodecode/templates/email_templates/pull_request_update.mako:130
10256 10486 #: rhodecode/templates/pullrequests/pullrequest_show.mako:128
10257 10487 #: rhodecode/templates/pullrequests/pullrequest_show.mako:137
10258 10488 msgid "of"
10259 10489 msgstr ""
10260 10490
10261 10491 #: rhodecode/templates/email_templates/pull_request_review.mako:15
10262 10492 msgid "{user} requested a pull request review. !{pr_id}: \"{pr_title}\""
10263 10493 msgstr ""
10264 10494
10265 10495 #: rhodecode/templates/email_templates/pull_request_review.mako:37
10266 10496 #: rhodecode/templates/email_templates/pull_request_update.mako:37
10267 10497 msgid "Pull Request link"
10268 10498 msgstr ""
10269 10499
10270 10500 #: rhodecode/templates/email_templates/pull_request_review.mako:83
10271 10501 msgid "requested a"
10272 10502 msgstr ""
10273 10503
10274 10504 #: rhodecode/templates/email_templates/pull_request_review.mako:85
10275 10505 msgid "pull request review."
10276 10506 msgstr ""
10277 10507
10278 10508 #: rhodecode/templates/email_templates/pull_request_update.mako:15
10279 10509 msgid "{updating_user} updated pull request. !{pr_id}: \"{pr_title}\""
10280 10510 msgstr ""
10281 10511
10282 10512 #: rhodecode/templates/email_templates/pull_request_update.mako:95
10283 10513 msgid "updated"
10284 10514 msgstr ""
10285 10515
10286 10516 #: rhodecode/templates/email_templates/pull_request_update.mako:97
10287 10517 msgid "pull request."
10288 10518 msgstr ""
10289 10519
10290 10520 #: rhodecode/templates/email_templates/pull_request_update.mako:139
10291 10521 msgid "Changes"
10292 10522 msgstr ""
10293 10523
10294 10524 #: rhodecode/templates/email_templates/test.mako:5
10295 10525 msgid "hello \"world\""
10296 10526 msgstr ""
10297 10527
10298 10528 #: rhodecode/templates/email_templates/test.mako:22
10299 10529 msgid "Translation String"
10300 10530 msgstr ""
10301 10531
10302 10532 #: rhodecode/templates/email_templates/user_registration.mako:28
10303 10533 msgid "New user {user} has registered on {date}"
10304 10534 msgstr ""
10305 10535
10306 10536 #: rhodecode/templates/email_templates/user_registration.mako:46
10307 10537 msgid "Full Name"
10308 10538 msgstr ""
10309 10539
10310 #: rhodecode/templates/errors/error_document.mako:47
10540 #: rhodecode/templates/errors/error_document.mako:48
10311 10541 #, python-format
10312 10542 msgid "You will be redirected to %s in %s seconds"
10313 10543 msgstr ""
10314 10544
10315 #: rhodecode/templates/errors/error_document.mako:65
10545 #: rhodecode/templates/errors/error_document.mako:66
10316 10546 msgid "Support Page"
10317 10547 msgstr ""
10318 10548
10319 10549 #: rhodecode/templates/feed/atom_feed_entry.mako:3
10320 10550 #, python-format
10321 10551 msgid "%(user)s commited on %(date)s UTC"
10322 10552 msgstr ""
10323 10553
10324 10554 #: rhodecode/templates/feed/atom_feed_entry.mako:30
10325 10555 msgid "Commit was too big and was cut off..."
10326 10556 msgstr ""
10327 10557
10328 10558 #: rhodecode/templates/files/file_authors_box.mako:18
10329 10559 msgid "Load All Authors"
10330 10560 msgstr ""
10331 10561
10332 10562 #: rhodecode/templates/files/file_authors_box.mako:20
10333 10563 msgid "last author"
10334 10564 msgstr ""
10335 10565
10336 10566 #: rhodecode/templates/files/files.mako:4
10337 10567 #: rhodecode/templates/files/files_pjax.mako:2
10338 10568 msgid "{} Files"
10339 10569 msgstr ""
10340 10570
10341 10571 #: rhodecode/templates/files/files_add.mako:4
10342 10572 msgid "{} Files Add"
10343 10573 msgstr ""
10344 10574
10345 10575 #: rhodecode/templates/files/files_add.mako:25
10346 10576 msgid "Add new file"
10347 10577 msgstr ""
10348 10578
10349 10579 #: rhodecode/templates/files/files_add.mako:44
10350 10580 #: rhodecode/templates/files/files_edit.mako:45
10351 10581 msgid "Filename e.g example.py, or docs/readme.md"
10352 10582 msgstr ""
10353 10583
10354 #: rhodecode/templates/files/files_add.mako:65
10584 #: rhodecode/templates/files/files_add.mako:64
10355 10585 #: rhodecode/templates/files/files_edit.mako:66
10356 10586 msgid "Line wraps on"
10357 10587 msgstr ""
10358 10588
10359 #: rhodecode/templates/files/files_add.mako:65
10589 #: rhodecode/templates/files/files_add.mako:64
10360 10590 #: rhodecode/templates/files/files_edit.mako:66
10361 10591 msgid "line wraps off"
10362 10592 msgstr ""
10363 10593
10364 #: rhodecode/templates/files/files_add.mako:88
10594 #: rhodecode/templates/files/files_add.mako:87
10365 10595 #: rhodecode/templates/files/files_delete.mako:72
10366 10596 #: rhodecode/templates/files/files_edit.mako:89
10367 10597 #: rhodecode/templates/files/files_upload.mako:102
10368 10598 msgid "Commit changes"
10369 10599 msgstr ""
10370 10600
10371 10601 #: rhodecode/templates/files/files_browser.mako:9
10372 10602 msgid "Previous commit"
10373 10603 msgstr ""
10374 10604
10375 10605 #: rhodecode/templates/files/files_browser.mako:15
10376 10606 msgid "Next commit"
10377 10607 msgstr ""
10378 10608
10379 10609 #: rhodecode/templates/files/files_browser.mako:22
10380 10610 msgid "Upload File"
10381 10611 msgstr ""
10382 10612
10383 10613 #: rhodecode/templates/files/files_browser.mako:25
10384 10614 msgid "Add File"
10385 10615 msgstr ""
10386 10616
10387 10617 #: rhodecode/templates/files/files_browser.mako:35
10388 10618 msgid "Download full tree ZIP"
10389 10619 msgstr ""
10390 10620
10391 10621 #: rhodecode/templates/files/files_browser.mako:39
10392 10622 msgid "Download this tree ZIP"
10393 10623 msgstr ""
10394 10624
10395 10625 #: rhodecode/templates/files/files_browser.mako:67
10396 10626 #: rhodecode/templates/summary/summary.mako:37
10397 10627 #, python-format
10398 10628 msgid "Readme file from commit %s:%s"
10399 10629 msgstr ""
10400 10630
10401 10631 #: rhodecode/templates/files/files_browser_tree.mako:14
10402 10632 #: rhodecode/templates/search/search_path.mako:12
10403 10633 msgid "Size"
10404 10634 msgstr ""
10405 10635
10406 10636 #: rhodecode/templates/files/files_browser_tree.mako:15
10407 10637 msgid "Modified"
10408 10638 msgstr ""
10409 10639
10410 10640 #: rhodecode/templates/files/files_browser_tree.mako:16
10411 10641 msgid "Last Commit"
10412 10642 msgstr ""
10413 10643
10414 10644 #: rhodecode/templates/files/files_delete.mako:4
10415 10645 msgid "{} Files Delete"
10416 10646 msgstr ""
10417 10647
10418 10648 #: rhodecode/templates/files/files_delete.mako:25
10419 10649 msgid "Delete file"
10420 10650 msgstr ""
10421 10651
10422 10652 #: rhodecode/templates/files/files_delete.mako:53
10423 10653 #, python-format
10424 10654 msgid "Binary file (%s)"
10425 10655 msgstr ""
10426 10656
10427 10657 #: rhodecode/templates/files/files_delete.mako:58
10428 #: rhodecode/templates/files/files_source.mako:125
10658 #: rhodecode/templates/files/files_source.mako:128
10429 10659 msgid "File size {} is bigger then allowed limit {}. "
10430 10660 msgstr ""
10431 10661
10432 10662 #: rhodecode/templates/files/files_edit.mako:4
10433 10663 msgid "{} Files Edit"
10434 10664 msgstr ""
10435 10665
10436 10666 #: rhodecode/templates/files/files_edit.mako:25
10437 10667 msgid "Edit file"
10438 10668 msgstr ""
10439 10669
10440 10670 #: rhodecode/templates/files/files_source.mako:16
10441 10671 msgid "Download largefile"
10442 10672 msgstr ""
10443 10673
10444 10674 #: rhodecode/templates/files/files_source.mako:20
10445 10675 msgid "Download file"
10446 10676 msgstr ""
10447 10677
10448 10678 #: rhodecode/templates/files/files_source.mako:29
10449 10679 msgid "Editing binary files not allowed"
10450 10680 msgstr ""
10451 10681
10452 10682 #: rhodecode/templates/files/files_source.mako:33
10453 10683 msgid "Edit on branch: "
10454 10684 msgstr ""
10455 10685
10456 10686 #: rhodecode/templates/files/files_source.mako:42
10457 10687 msgid "Editing files allowed only when on branch head commit"
10458 10688 msgstr ""
10459 10689
10460 10690 #: rhodecode/templates/files/files_source.mako:43
10461 10691 msgid "Deleting files allowed only when on branch head commit"
10462 10692 msgstr ""
10463 10693
10464 10694 #: rhodecode/templates/files/files_source.mako:65
10465 10695 msgid "lines"
10466 10696 msgstr ""
10467 10697
10468 10698 #: rhodecode/templates/files/files_source.mako:73
10469 10699 msgid "This file is a pointer to large binary file"
10470 10700 msgstr ""
10471 10701
10472 10702 #: rhodecode/templates/files/files_source.mako:73
10473 10703 msgid "LargeFile"
10474 10704 msgstr ""
10475 10705
10476 10706 #: rhodecode/templates/files/files_source.mako:96
10477 10707 msgid "History"
10478 10708 msgstr ""
10479 10709
10480 10710 #: rhodecode/templates/files/files_source.mako:102
10481 10711 msgid "Annotation"
10482 10712 msgstr ""
10483 10713
10484 10714 #: rhodecode/templates/files/files_source.mako:104
10485 10715 msgid "Raw"
10486 10716 msgstr ""
10487 10717
10488 #: rhodecode/templates/files/files_source.mako:120
10718 #: rhodecode/templates/files/files_source.mako:107
10719 msgid "Copy permalink"
10720 msgstr ""
10721
10722 #: rhodecode/templates/files/files_source.mako:123
10489 10723 msgid "Binary file ({})"
10490 10724 msgstr ""
10491 10725
10492 10726 #: rhodecode/templates/files/files_source_header.mako:33
10493 10727 msgid "File last commit"
10494 10728 msgstr ""
10495 10729
10496 10730 #: rhodecode/templates/files/files_upload.mako:4
10497 10731 msgid "{} Files Upload"
10498 10732 msgstr ""
10499 10733
10500 10734 #: rhodecode/templates/files/files_upload.mako:36
10501 10735 msgid "Uploading..."
10502 10736 msgstr ""
10503 10737
10504 10738 #: rhodecode/templates/files/files_upload.mako:38
10505 10739 msgid "Uploaded"
10506 10740 msgstr ""
10507 10741
10508 10742 #: rhodecode/templates/files/files_upload.mako:52
10509 10743 msgid "Upload new file"
10510 10744 msgstr ""
10511 10745
10512 10746 #: rhodecode/templates/files/files_upload.mako:109
10513 msgid "Commiting..."
10747 msgid "Committing..."
10514 10748 msgstr ""
10515 10749
10516 10750 #: rhodecode/templates/files/files_upload.mako:110
10517 10751 msgid "Please wait while the files are being uploaded"
10518 10752 msgstr ""
10519 10753
10520 10754 #: rhodecode/templates/forks/fork.mako:5
10521 10755 #, python-format
10522 10756 msgid "Fork repository %s"
10523 10757 msgstr ""
10524 10758
10525 10759 #: rhodecode/templates/forks/fork.mako:30
10526 10760 #: rhodecode/templates/forks/forks.mako:60
10527 10761 msgid "Fork name"
10528 10762 msgstr ""
10529 10763
10530 #: rhodecode/templates/forks/fork.mako:71
10764 #: rhodecode/templates/forks/fork.mako:78
10531 10765 msgid "Copy permissions"
10532 10766 msgstr ""
10533 10767
10534 #: rhodecode/templates/forks/fork.mako:75
10768 #: rhodecode/templates/forks/fork.mako:82
10535 10769 msgid "Copy permissions from parent repository."
10536 10770 msgstr ""
10537 10771
10538 #: rhodecode/templates/forks/fork.mako:81
10772 #: rhodecode/templates/forks/fork.mako:88
10539 10773 msgid "Private"
10540 10774 msgstr ""
10541 10775
10542 #: rhodecode/templates/forks/fork.mako:90
10776 #: rhodecode/templates/forks/fork.mako:97
10543 10777 msgid "Fork this Repository"
10544 10778 msgstr ""
10545 10779
10546 10780 #: rhodecode/templates/forks/forks.mako:5
10547 10781 #, python-format
10548 10782 msgid "%s Forks"
10549 10783 msgstr ""
10550 10784
10551 10785 #: rhodecode/templates/forks/forks.mako:28
10552 10786 msgid "Create new fork"
10553 10787 msgstr ""
10554 10788
10555 10789 #: rhodecode/templates/forks/forks.mako:64
10556 10790 msgid "Forked"
10557 10791 msgstr ""
10558 10792
10559 10793 #: rhodecode/templates/journal/journal.mako:25
10560 10794 msgid "ATOM journal feed"
10561 10795 msgstr ""
10562 10796
10563 10797 #: rhodecode/templates/journal/journal.mako:26
10564 10798 msgid "RSS journal feed"
10565 10799 msgstr ""
10566 10800
10567 10801 #: rhodecode/templates/journal/journal_data.mako:45
10568 10802 msgid "No entries yet"
10569 10803 msgstr ""
10570 10804
10571 10805 #: rhodecode/templates/journal/public_journal.mako:4
10572 10806 #: rhodecode/templates/journal/public_journal.mako:12
10573 10807 msgid "Public Journal"
10574 10808 msgstr ""
10575 10809
10576 10810 #: rhodecode/templates/journal/public_journal.mako:21
10577 10811 msgid "ATOM public journal feed"
10578 10812 msgstr ""
10579 10813
10580 10814 #: rhodecode/templates/journal/public_journal.mako:22
10581 10815 msgid "RSS public journal feed"
10582 10816 msgstr ""
10583 10817
10584 10818 #: rhodecode/templates/pullrequests/pullrequest.mako:5
10585 10819 #: rhodecode/templates/pullrequests/pullrequest.mako:28
10586 10820 msgid "New pull request"
10587 10821 msgstr ""
10588 10822
10589 10823 #: rhodecode/templates/pullrequests/pullrequest.mako:60
10590 10824 #: rhodecode/templates/pullrequests/pullrequest_show.mako:118
10591 10825 msgid "Commit flow"
10592 10826 msgstr ""
10593 10827
10594 10828 #: rhodecode/templates/pullrequests/pullrequest.mako:68
10595 10829 msgid "Source repository"
10596 10830 msgstr ""
10597 10831
10598 10832 #: rhodecode/templates/pullrequests/pullrequest.mako:86
10599 10833 msgid "Loading refs..."
10600 10834 msgstr ""
10601 10835
10602 10836 #: rhodecode/templates/pullrequests/pullrequest.mako:97
10603 10837 msgid "Submit Pull Request"
10604 10838 msgstr ""
10605 10839
10606 10840 #: rhodecode/templates/pullrequests/pullrequest.mako:111
10607 10841 msgid "Author of this pull request"
10608 10842 msgstr ""
10609 10843
10610 10844 #: rhodecode/templates/pullrequests/pullrequest.mako:125
10611 10845 #: rhodecode/templates/pullrequests/pullrequest_show.mako:286
10612 10846 msgid "Reviewer rules"
10613 10847 msgstr ""
10614 10848
10615 10849 #: rhodecode/templates/pullrequests/pullrequest.mako:135
10616 10850 #: rhodecode/templates/pullrequests/pullrequest_show.mako:300
10617 10851 msgid "Pull request reviewers"
10618 10852 msgstr ""
10619 10853
10620 10854 #: rhodecode/templates/pullrequests/pullrequest.mako:146
10621 10855 #: rhodecode/templates/pullrequests/pullrequest_show.mako:344
10622 10856 msgid "Add reviewer or reviewer group"
10623 10857 msgstr ""
10624 10858
10625 #: rhodecode/templates/pullrequests/pullrequest.mako:302
10626 #: rhodecode/templates/pullrequests/pullrequest.mako:519
10627 msgid "Please select source and target"
10628 msgstr ""
10629
10630 #: rhodecode/templates/pullrequests/pullrequest.mako:308
10631 msgid "Loading compare ..."
10632 msgstr ""
10633
10634 #: rhodecode/templates/pullrequests/pullrequest.mako:367
10859 #: rhodecode/templates/pullrequests/pullrequest.mako:317
10635 10860 msgid "Show detailed compare."
10636 10861 msgstr ""
10637 10862
10638 #: rhodecode/templates/pullrequests/pullrequest.mako:374
10863 #: rhodecode/templates/pullrequests/pullrequest.mako:324
10639 10864 msgid "There are no commits to merge."
10640 10865 msgstr ""
10641 10866
10642 #: rhodecode/templates/pullrequests/pullrequest.mako:424
10643 #: rhodecode/templates/pullrequests/pullrequest.mako:450
10867 #: rhodecode/templates/pullrequests/pullrequest.mako:418
10868 #: rhodecode/templates/pullrequests/pullrequest.mako:444
10644 10869 msgid "Select commit reference"
10645 10870 msgstr ""
10646 10871
10647 #: rhodecode/templates/pullrequests/pullrequest.mako:440
10872 #: rhodecode/templates/pullrequests/pullrequest.mako:434
10648 10873 msgid "Target repository"
10649 10874 msgstr ""
10650 10875
10876 #: rhodecode/templates/pullrequests/pullrequest.mako:513
10877 msgid "Please select source and target"
10878 msgstr ""
10879
10651 10880 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:7
10652 10881 msgid "This pull request can be merged automatically."
10653 10882 msgstr ""
10654 10883
10655 10884 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:12
10656 10885 msgid "Merge is not currently possible because of below failed checks."
10657 10886 msgstr ""
10658 10887
10659 10888 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:57
10660 10889 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:61
10661 10890 msgid "Close with status {}"
10662 10891 msgstr ""
10663 10892
10664 10893 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:66
10665 10894 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:76
10666 10895 msgid "Merge and close Pull Request"
10667 10896 msgstr ""
10668 10897
10669 10898 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:70
10670 10899 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:75
10671 10900 msgid "refresh checks"
10672 10901 msgstr ""
10673 10902
10674 10903 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:76
10675 10904 msgid "You are not allowed to merge this pull request."
10676 10905 msgstr ""
10677 10906
10678 10907 #: rhodecode/templates/pullrequests/pullrequest_merge_checks.mako:78
10679 10908 msgid "Login to Merge this Pull Request"
10680 10909 msgstr ""
10681 10910
10682 10911 #: rhodecode/templates/pullrequests/pullrequest_show.mako:6
10683 10912 msgid "{} Pull Request !{}"
10684 10913 msgstr ""
10685 10914
10686 #: rhodecode/templates/pullrequests/pullrequest_show.mako:53
10915 #: rhodecode/templates/pullrequests/pullrequest_show.mako:52
10687 10916 msgid "Last updated on"
10688 10917 msgstr ""
10689 10918
10690 #: rhodecode/templates/pullrequests/pullrequest_show.mako:54
10919 #: rhodecode/templates/pullrequests/pullrequest_show.mako:53
10691 10920 msgid "by"
10692 10921 msgstr ""
10693 10922
10694 #: rhodecode/templates/pullrequests/pullrequest_show.mako:63
10923 #: rhodecode/templates/pullrequests/pullrequest_show.mako:62
10695 10924 msgid "Update title & description"
10696 10925 msgstr ""
10697 10926
10698 #: rhodecode/templates/pullrequests/pullrequest_show.mako:67
10699 #: rhodecode/templates/pullrequests/pullrequest_show.mako:71
10700 msgid "Delete pull request"
10701 msgstr ""
10702
10703 10927 #: rhodecode/templates/pullrequests/pullrequest_show.mako:68
10704 msgid "Confirm to delete this pull request"
10928 #: rhodecode/templates/pullrequests/pullrequest_show.mako:71
10929 msgid "Delete pull request"
10705 10930 msgstr ""
10706 10931
10707 10932 #: rhodecode/templates/pullrequests/pullrequest_show.mako:71
10708 10933 msgid "Not allowed to delete this pull request"
10709 10934 msgstr ""
10710 10935
10711 10936 #: rhodecode/templates/pullrequests/pullrequest_show.mako:81
10712 10937 msgid "Rendered using {} renderer"
10713 10938 msgstr ""
10714 10939
10715 10940 #: rhodecode/templates/pullrequests/pullrequest_show.mako:95
10716 10941 msgid "Review status"
10717 10942 msgstr ""
10718 10943
10719 10944 #: rhodecode/templates/pullrequests/pullrequest_show.mako:151
10720 10945 msgid "Common ancestor"
10721 10946 msgstr ""
10722 10947
10723 10948 #: rhodecode/templates/pullrequests/pullrequest_show.mako:155
10724 10949 msgid "not available"
10725 10950 msgstr ""
10726 10951
10727 10952 #: rhodecode/templates/pullrequests/pullrequest_show.mako:167
10728 10953 msgid "Pull changes from source"
10729 10954 msgstr ""
10730 10955
10731 10956 #: rhodecode/templates/pullrequests/pullrequest_show.mako:168
10732 10957 msgid "Copy the pull url"
10733 10958 msgstr ""
10734 10959
10735 10960 #: rhodecode/templates/pullrequests/pullrequest_show.mako:180
10736 10961 msgid "Clone repository in its merged state using shadow repository"
10737 10962 msgstr ""
10738 10963
10739 10964 #: rhodecode/templates/pullrequests/pullrequest_show.mako:180
10740 10965 msgid "Clone from shadow repository"
10741 10966 msgstr ""
10742 10967
10743 10968 #: rhodecode/templates/pullrequests/pullrequest_show.mako:181
10744 10969 #: rhodecode/templates/summary/components.mako:78
10745 10970 msgid "Copy the clone url"
10746 10971 msgstr ""
10747 10972
10748 10973 #: rhodecode/templates/pullrequests/pullrequest_show.mako:185
10749 10974 msgid "Shadow repository data not available"
10750 10975 msgstr ""
10751 10976
10752 10977 #: rhodecode/templates/pullrequests/pullrequest_show.mako:201
10753 10978 msgid "Versions"
10754 10979 msgstr ""
10755 10980
10756 10981 #: rhodecode/templates/pullrequests/pullrequest_show.mako:213
10757 10982 #: rhodecode/templates/pullrequests/pullrequest_show.mako:215
10758 10983 msgid "show versions"
10759 10984 msgstr ""
10760 10985
10761 10986 #: rhodecode/templates/pullrequests/pullrequest_show.mako:214
10762 10987 msgid "hide versions"
10763 10988 msgstr ""
10764 10989
10765 10990 #: rhodecode/templates/pullrequests/pullrequest_show.mako:239
10766 10991 msgid "Your review status at this version"
10767 10992 msgstr ""
10768 10993
10769 10994 #: rhodecode/templates/pullrequests/pullrequest_show.mako:244
10770 10995 msgid "Comments from pull request version v{0}"
10771 10996 msgstr ""
10772 10997
10773 10998 #: rhodecode/templates/pullrequests/pullrequest_show.mako:262
10774 10999 #: rhodecode/templates/pullrequests/pullrequest_show.mako:266
10775 11000 msgid "select versions to show changes"
10776 11001 msgstr ""
10777 11002
10778 11003 #: rhodecode/templates/pullrequests/pullrequest_show.mako:263
10779 11004 msgid "show changes between versions"
10780 11005 msgstr ""
10781 11006
10782 11007 #: rhodecode/templates/pullrequests/pullrequest_show.mako:264
10783 11008 msgid "show pull request for this version"
10784 11009 msgstr ""
10785 11010
10786 11011 #: rhodecode/templates/pullrequests/pullrequest_show.mako:273
10787 11012 msgid "Pull request versions not available"
10788 11013 msgstr ""
10789 11014
10790 11015 #: rhodecode/templates/pullrequests/pullrequest_show.mako:349
10791 11016 msgid "Save Changes"
10792 11017 msgstr ""
10793 11018
10794 11019 #: rhodecode/templates/pullrequests/pullrequest_show.mako:386
10795 11020 msgid "unresolved TODOs unavailable in this view"
10796 11021 msgstr ""
10797 11022
10798 11023 #: rhodecode/templates/pullrequests/pullrequest_show.mako:422
10799 11024 msgid "No unresolved TODOs"
10800 11025 msgstr ""
10801 11026
10802 11027 #: rhodecode/templates/pullrequests/pullrequest_show.mako:440
10803 11028 msgid "Cannot show diff when pull request state is changing. Current progress state"
10804 11029 msgstr ""
10805 11030
10806 #: rhodecode/templates/pullrequests/pullrequest_show.mako:453
11031 #: rhodecode/templates/pullrequests/pullrequest_show.mako:458
10807 11032 msgid "Missing requirements:"
10808 11033 msgstr ""
10809 11034
10810 #: rhodecode/templates/pullrequests/pullrequest_show.mako:454
11035 #: rhodecode/templates/pullrequests/pullrequest_show.mako:459
10811 11036 msgid "These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled."
10812 11037 msgstr ""
10813 11038
10814 #: rhodecode/templates/pullrequests/pullrequest_show.mako:462
11039 #: rhodecode/templates/pullrequests/pullrequest_show.mako:467
10815 11040 msgid "Missing commits"
10816 11041 msgstr ""
10817 11042
10818 #: rhodecode/templates/pullrequests/pullrequest_show.mako:463
11043 #: rhodecode/templates/pullrequests/pullrequest_show.mako:468
10819 11044 msgid "This pull request cannot be displayed, because one or more commits no longer exist in the source repository."
10820 11045 msgstr ""
10821 11046
10822 #: rhodecode/templates/pullrequests/pullrequest_show.mako:464
11047 #: rhodecode/templates/pullrequests/pullrequest_show.mako:469
10823 11048 msgid "Please update this pull request, push the commits back into the source repository, or consider closing this pull request."
10824 11049 msgstr ""
10825 11050
10826 #: rhodecode/templates/pullrequests/pullrequest_show.mako:465
11051 #: rhodecode/templates/pullrequests/pullrequest_show.mako:470
10827 11052 msgid "Consider doing a {force_refresh_url} in case you think this is an error."
10828 11053 msgstr ""
10829 11054
10830 #: rhodecode/templates/pullrequests/pullrequest_show.mako:476
11055 #: rhodecode/templates/pullrequests/pullrequest_show.mako:479
11056 msgid "There are new changes for {}:{} in source repository, please consider updating this pull request."
11057 msgstr ""
11058
11059 #: rhodecode/templates/pullrequests/pullrequest_show.mako:491
10831 11060 #, python-format
10832 11061 msgid "Showing changes at v%d, commenting is disabled."
10833 11062 msgstr ""
10834 11063
10835 #: rhodecode/templates/pullrequests/pullrequest_show.mako:499
10836 #: rhodecode/templates/pullrequests/pullrequest_show.mako:521
11064 #: rhodecode/templates/pullrequests/pullrequest_show.mako:514
11065 #: rhodecode/templates/pullrequests/pullrequest_show.mako:536
10837 11066 msgid "Update commits"
10838 11067 msgstr ""
10839 11068
10840 #: rhodecode/templates/pullrequests/pullrequest_show.mako:502
11069 #: rhodecode/templates/pullrequests/pullrequest_show.mako:517
10841 11070 msgid "more update options"
10842 11071 msgstr ""
10843 11072
10844 #: rhodecode/templates/pullrequests/pullrequest_show.mako:510
11073 #: rhodecode/templates/pullrequests/pullrequest_show.mako:525
10845 11074 msgid "Force update commits"
10846 11075 msgstr ""
10847 11076
10848 #: rhodecode/templates/pullrequests/pullrequest_show.mako:513
11077 #: rhodecode/templates/pullrequests/pullrequest_show.mako:528
10849 11078 msgid "Update commits and force refresh this pull request."
10850 11079 msgstr ""
10851 11080
10852 #: rhodecode/templates/pullrequests/pullrequest_show.mako:521
10853 msgid "Update is disabled for current view"
10854 msgstr ""
10855
10856 #: rhodecode/templates/pullrequests/pullrequest_show.mako:532
10857 msgid "Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled"
10858 msgstr ""
10859
10860 11081 #: rhodecode/templates/pullrequests/pullrequest_show.mako:536
11082 msgid "Update is disabled for current view"
11083 msgstr ""
11084
11085 #: rhodecode/templates/pullrequests/pullrequest_show.mako:547
11086 msgid "Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled"
11087 msgstr ""
11088
11089 #: rhodecode/templates/pullrequests/pullrequest_show.mako:551
10861 11090 msgid "commits added: {}, removed: {}"
10862 11091 msgstr ""
10863 11092
10864 #: rhodecode/templates/pullrequests/pullrequest_show.mako:554
11093 #: rhodecode/templates/pullrequests/pullrequest_show.mako:569
10865 11094 msgid "Commit added in displayed changes"
10866 11095 msgstr ""
10867 11096
10868 #: rhodecode/templates/pullrequests/pullrequest_show.mako:556
11097 #: rhodecode/templates/pullrequests/pullrequest_show.mako:571
10869 11098 msgid "Commit removed in displayed changes"
10870 11099 msgstr ""
10871 11100
10872 #: rhodecode/templates/pullrequests/pullrequest_show.mako:664
11101 #: rhodecode/templates/pullrequests/pullrequest_show.mako:679
10873 11102 msgid "there is {num} general comment from older versions"
10874 11103 msgstr ""
10875 11104
10876 #: rhodecode/templates/pullrequests/pullrequest_show.mako:665
11105 #: rhodecode/templates/pullrequests/pullrequest_show.mako:680
10877 11106 msgid "show it"
10878 11107 msgstr ""
10879 11108
10880 #: rhodecode/templates/pullrequests/pullrequest_show.mako:667
11109 #: rhodecode/templates/pullrequests/pullrequest_show.mako:682
10881 11110 msgid "there are {num} general comments from older versions"
10882 11111 msgstr ""
10883 11112
10884 #: rhodecode/templates/pullrequests/pullrequest_show.mako:668
11113 #: rhodecode/templates/pullrequests/pullrequest_show.mako:683
10885 11114 msgid "show them"
10886 11115 msgstr ""
10887 11116
10888 11117 #: rhodecode/templates/pullrequests/pullrequests.mako:4
10889 11118 msgid "{} Pull Requests"
10890 11119 msgstr ""
10891 11120
10892 11121 #: rhodecode/templates/pullrequests/pullrequests.mako:27
10893 11122 msgid "Opened"
10894 11123 msgstr ""
10895 11124
10896 11125 #: rhodecode/templates/pullrequests/pullrequests.mako:28
10897 11126 msgid "Opened by me"
10898 11127 msgstr ""
10899 11128
10900 11129 #: rhodecode/templates/pullrequests/pullrequests.mako:29
10901 11130 msgid "Awaiting review"
10902 11131 msgstr ""
10903 11132
10904 11133 #: rhodecode/templates/pullrequests/pullrequests.mako:30
10905 11134 msgid "Awaiting my review"
10906 11135 msgstr ""
10907 11136
10908 11137 #: rhodecode/templates/pullrequests/pullrequests.mako:32
10909 11138 msgid "From this repo"
10910 11139 msgstr ""
10911 11140
10912 11141 #: rhodecode/templates/pullrequests/pullrequests.mako:40
10913 11142 msgid "Open new Pull Request"
10914 11143 msgstr ""
10915 11144
10916 11145 #: rhodecode/templates/search/search.mako:6
10917 11146 #: rhodecode/templates/search/search.mako:19
10918 11147 msgid "Search inside repository {repo_name}"
10919 11148 msgstr ""
10920 11149
10921 11150 #: rhodecode/templates/search/search.mako:8
10922 11151 #: rhodecode/templates/search/search.mako:21
10923 11152 msgid "Search inside repository group {repo_group_name}"
10924 11153 msgstr ""
10925 11154
10926 11155 #: rhodecode/templates/search/search.mako:10
10927 11156 #: rhodecode/templates/search/search.mako:23
10928 11157 msgid "Search inside all accessible repositories"
10929 11158 msgstr ""
10930 11159
10931 11160 #: rhodecode/templates/search/search.mako:99
10932 11161 msgid "File path"
10933 11162 msgstr ""
10934 11163
10935 11164 #: rhodecode/templates/search/search.mako:102
10936 11165 msgid "Search"
10937 11166 msgstr ""
10938 11167
10939 11168 #: rhodecode/templates/search/search.mako:108
10940 11169 #: rhodecode/templates/search/search.mako:110
10941 11170 #: rhodecode/templates/search/search.mako:112
10942 11171 msgid "Global Search"
10943 11172 msgstr ""
10944 11173
10945 11174 #: rhodecode/templates/search/search.mako:138
10946 11175 msgid "sort"
10947 11176 msgstr ""
10948 11177
10949 11178 #: rhodecode/templates/search/search.mako:157
10950 11179 msgid "Query Language examples"
10951 11180 msgstr ""
10952 11181
10953 11182 #: rhodecode/templates/search/search_commit.mako:15
10954 11183 msgid "Commit date"
10955 11184 msgstr ""
10956 11185
10957 11186 #: rhodecode/templates/search/search_content.mako:7
10958 11187 msgid "No content matched"
10959 11188 msgstr ""
10960 11189
10961 11190 #: rhodecode/templates/search/search_content.mako:12
10962 11191 msgid "more matches in this file"
10963 11192 msgstr ""
10964 11193
10965 11194 #: rhodecode/templates/search/search_content.mako:112
10966 11195 msgid "Narrow to this repository group"
10967 11196 msgstr ""
10968 11197
10969 11198 #: rhodecode/templates/search/search_content.mako:119
10970 11199 msgid "Narrow to this repository"
10971 11200 msgstr ""
10972 11201
10973 11202 #: rhodecode/templates/search/search_path.mako:15
10974 11203 msgid "Lines"
10975 11204 msgstr ""
10976 11205
10977 11206 #: rhodecode/templates/summary/components.mako:20
10978 11207 msgid "Closed Branch"
10979 11208 msgstr ""
10980 11209
10981 11210 #: rhodecode/templates/summary/components.mako:83
10982 11211 msgid "Copy the clone by id url"
10983 11212 msgstr ""
10984 11213
10985 11214 #: rhodecode/templates/summary/components.mako:88
10986 11215 msgid "Copy the clone by ssh url"
10987 11216 msgstr ""
10988 11217
10989 11218 #: rhodecode/templates/summary/components.mako:92
10990 11219 msgid "SVN Protocol is disabled. To enable it, see the"
10991 11220 msgstr ""
10992 11221
10993 11222 #: rhodecode/templates/summary/components.mako:92
10994 11223 msgid "documentation here"
10995 11224 msgstr ""
10996 11225
10997 11226 #: rhodecode/templates/summary/components.mako:135
10998 11227 msgid "Number of Repository Forks"
10999 11228 msgstr ""
11000 11229
11001 11230 #: rhodecode/templates/summary/components.mako:172
11002 11231 msgid "Downloads"
11003 11232 msgstr ""
11004 11233
11005 11234 #: rhodecode/templates/summary/components.mako:177
11006 11235 msgid "There are no downloads yet"
11007 11236 msgstr ""
11008 11237
11009 11238 #: rhodecode/templates/summary/components.mako:181
11010 11239 msgid "Downloads are disabled for this repository"
11011 11240 msgstr ""
11012 11241
11013 11242 #: rhodecode/templates/summary/components.mako:203
11014 11243 msgid "Repository size"
11015 11244 msgstr ""
11016 11245
11017 11246 #: rhodecode/templates/summary/components.mako:215
11018 11247 msgid "Calculating Repository Size..."
11019 11248 msgstr ""
11020 11249
11021 11250 #: rhodecode/templates/summary/components.mako:226
11022 11251 msgid "Code Statistics"
11023 11252 msgstr ""
11024 11253
11025 11254 #: rhodecode/templates/summary/components.mako:235
11026 11255 msgid "Statistics are disabled for this repository"
11027 11256 msgstr ""
11028 11257
11029 11258 #: rhodecode/templates/summary/summary.mako:21
11030 11259 msgid "Quick start"
11031 11260 msgstr ""
11032 11261
11033 11262 #: rhodecode/templates/summary/summary_base.mako:5
11034 11263 msgid "{} Summary"
11035 11264 msgstr ""
11036 11265
11037 11266 #: rhodecode/templates/summary/summary_base.mako:13
11038 11267 #, python-format
11039 11268 msgid "%s ATOM feed"
11040 11269 msgstr ""
11041 11270
11042 11271 #: rhodecode/templates/summary/summary_base.mako:14
11043 11272 #, python-format
11044 11273 msgid "%s RSS feed"
11045 11274 msgstr ""
11046 11275
11047 11276 #: rhodecode/templates/summary/summary_commits.mako:117
11048 11277 msgid "Add or upload files directly via RhodeCode:"
11049 11278 msgstr ""
11050 11279
11051 11280 #: rhodecode/templates/summary/summary_commits.mako:119
11052 11281 msgid "Add New File"
11053 11282 msgstr ""
11054 11283
11055 11284 #: rhodecode/templates/summary/summary_commits.mako:122
11056 11285 msgid "Upload New File"
11057 11286 msgstr ""
11058 11287
11059 11288 #: rhodecode/templates/summary/summary_commits.mako:128
11060 11289 msgid "Push new repo:"
11061 11290 msgstr ""
11062 11291
11063 11292 #: rhodecode/templates/summary/summary_commits.mako:151
11064 11293 msgid "Existing repository?"
11065 11294 msgstr ""
11066 11295
11067 11296 #: rhodecode/templates/tags/tags.mako:5
11068 11297 #, python-format
11069 11298 msgid "%s Tags"
11070 11299 msgstr ""
11071 11300
11072 11301 #: rhodecode/templates/tags/tags.mako:28
11073 11302 msgid "Compare Selected Tags"
11074 11303 msgstr ""
11075 11304
11076 11305 #: rhodecode/templates/tags/tags.mako:34
11077 11306 msgid "tags"
11078 11307 msgstr ""
11079 11308
11080 11309 #: rhodecode/templates/user_group/profile.mako:6
11081 11310 msgid "User Group Profile"
11082 11311 msgstr ""
11083 11312
11084 11313 #: rhodecode/templates/user_group/profile.mako:15
11085 11314 msgid "Group Name"
11086 11315 msgstr ""
11087 11316
11088 11317 #: rhodecode/templates/users/user_profile.mako:39
11089 11318 msgid "First name"
11090 11319 msgstr ""
11091 11320
11092 11321 #: rhodecode/templates/users/user_profile.mako:49
11093 11322 msgid "Last name"
11094 11323 msgstr ""
11095 11324
11096 11325 #: rhodecode/tests/lib/test_ext_json.py:162
11097 11326 msgid "hello"
11098 11327 msgstr ""
11099 11328
@@ -1,1960 +1,2029 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 """
22 22 Helper functions
23 23
24 24 Consists of functions to typically be used within templates, but also
25 25 available to Controllers. This module is available to both as 'h'.
26 26 """
27 27
28 28 import os
29 29 import random
30 30 import hashlib
31 31 import StringIO
32 32 import textwrap
33 33 import urllib
34 34 import math
35 35 import logging
36 36 import re
37 37 import time
38 38 import string
39 39 import hashlib
40 40 from collections import OrderedDict
41 41
42 42 import pygments
43 43 import itertools
44 44 import fnmatch
45 45 import bleach
46 46
47 47 from pyramid import compat
48 48 from datetime import datetime
49 49 from functools import partial
50 50 from pygments.formatters.html import HtmlFormatter
51 51 from pygments.lexers import (
52 52 get_lexer_by_name, get_lexer_for_filename, get_lexer_for_mimetype)
53 53
54 54 from pyramid.threadlocal import get_current_request
55 55
56 56 from webhelpers2.html import literal, HTML, escape
57 57 from webhelpers2.html._autolink import _auto_link_urls
58 58 from webhelpers2.html.tools import (
59 59 button_to, highlight, js_obfuscate, strip_links, strip_tags)
60 60
61 61 from webhelpers2.text import (
62 62 chop_at, collapse, convert_accented_entities,
63 63 convert_misc_entities, lchop, plural, rchop, remove_formatting,
64 64 replace_whitespace, urlify, truncate, wrap_paragraphs)
65 65 from webhelpers2.date import time_ago_in_words
66 66
67 67 from webhelpers2.html.tags import (
68 68 _input, NotGiven, _make_safe_id_component as safeid,
69 69 form as insecure_form,
70 70 auto_discovery_link, checkbox, end_form, file,
71 71 hidden, image, javascript_link, link_to, link_to_if, link_to_unless, ol,
72 72 select as raw_select, stylesheet_link, submit, text, password, textarea,
73 73 ul, radio, Options)
74 74
75 75 from webhelpers2.number import format_byte_size
76 76
77 77 from rhodecode.lib.action_parser import action_parser
78 78 from rhodecode.lib.pagination import Page, RepoPage, SqlPage
79 79 from rhodecode.lib.ext_json import json
80 80 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
81 81 from rhodecode.lib.utils2 import (
82 82 str2bool, safe_unicode, safe_str,
83 83 get_commit_safe, datetime_to_time, time_to_datetime, time_to_utcdatetime,
84 84 AttributeDict, safe_int, md5, md5_safe, get_host_info)
85 85 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
86 86 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
87 87 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyCommit
88 88 from rhodecode.lib.index.search_utils import get_matching_line_offsets
89 89 from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
90 90 from rhodecode.model.changeset_status import ChangesetStatusModel
91 91 from rhodecode.model.db import Permission, User, Repository
92 92 from rhodecode.model.repo_group import RepoGroupModel
93 93 from rhodecode.model.settings import IssueTrackerSettingsModel
94 94
95 95
96 96 log = logging.getLogger(__name__)
97 97
98 98
99 99 DEFAULT_USER = User.DEFAULT_USER
100 100 DEFAULT_USER_EMAIL = User.DEFAULT_USER_EMAIL
101 101
102 102
103 103 def asset(path, ver=None, **kwargs):
104 104 """
105 105 Helper to generate a static asset file path for rhodecode assets
106 106
107 107 eg. h.asset('images/image.png', ver='3923')
108 108
109 109 :param path: path of asset
110 110 :param ver: optional version query param to append as ?ver=
111 111 """
112 112 request = get_current_request()
113 113 query = {}
114 114 query.update(kwargs)
115 115 if ver:
116 116 query = {'ver': ver}
117 117 return request.static_path(
118 118 'rhodecode:public/{}'.format(path), _query=query)
119 119
120 120
121 121 default_html_escape_table = {
122 122 ord('&'): u'&amp;',
123 123 ord('<'): u'&lt;',
124 124 ord('>'): u'&gt;',
125 125 ord('"'): u'&quot;',
126 126 ord("'"): u'&#39;',
127 127 }
128 128
129 129
130 130 def html_escape(text, html_escape_table=default_html_escape_table):
131 131 """Produce entities within text."""
132 132 return text.translate(html_escape_table)
133 133
134 134
135 135 def chop_at_smart(s, sub, inclusive=False, suffix_if_chopped=None):
136 136 """
137 137 Truncate string ``s`` at the first occurrence of ``sub``.
138 138
139 139 If ``inclusive`` is true, truncate just after ``sub`` rather than at it.
140 140 """
141 141 suffix_if_chopped = suffix_if_chopped or ''
142 142 pos = s.find(sub)
143 143 if pos == -1:
144 144 return s
145 145
146 146 if inclusive:
147 147 pos += len(sub)
148 148
149 149 chopped = s[:pos]
150 150 left = s[pos:].strip()
151 151
152 152 if left and suffix_if_chopped:
153 153 chopped += suffix_if_chopped
154 154
155 155 return chopped
156 156
157 157
158 158 def shorter(text, size=20, prefix=False):
159 159 postfix = '...'
160 160 if len(text) > size:
161 161 if prefix:
162 162 # shorten in front
163 163 return postfix + text[-(size - len(postfix)):]
164 164 else:
165 165 return text[:size - len(postfix)] + postfix
166 166 return text
167 167
168 168
169 169 def reset(name, value=None, id=NotGiven, type="reset", **attrs):
170 170 """
171 171 Reset button
172 172 """
173 173 return _input(type, name, value, id, attrs)
174 174
175 175
176 176 def select(name, selected_values, options, id=NotGiven, **attrs):
177 177
178 178 if isinstance(options, (list, tuple)):
179 179 options_iter = options
180 180 # Handle old value,label lists ... where value also can be value,label lists
181 181 options = Options()
182 182 for opt in options_iter:
183 183 if isinstance(opt, tuple) and len(opt) == 2:
184 184 value, label = opt
185 185 elif isinstance(opt, basestring):
186 186 value = label = opt
187 187 else:
188 188 raise ValueError('invalid select option type %r' % type(opt))
189 189
190 190 if isinstance(value, (list, tuple)):
191 191 option_group = options.add_optgroup(label)
192 192 for opt2 in value:
193 193 if isinstance(opt2, tuple) and len(opt2) == 2:
194 194 group_value, group_label = opt2
195 195 elif isinstance(opt2, basestring):
196 196 group_value = group_label = opt2
197 197 else:
198 198 raise ValueError('invalid select option type %r' % type(opt2))
199 199
200 200 option_group.add_option(group_label, group_value)
201 201 else:
202 202 options.add_option(label, value)
203 203
204 204 return raw_select(name, selected_values, options, id=id, **attrs)
205 205
206 206
207 207 def branding(name, length=40):
208 208 return truncate(name, length, indicator="")
209 209
210 210
211 211 def FID(raw_id, path):
212 212 """
213 213 Creates a unique ID for filenode based on it's hash of path and commit
214 214 it's safe to use in urls
215 215
216 216 :param raw_id:
217 217 :param path:
218 218 """
219 219
220 220 return 'c-%s-%s' % (short_id(raw_id), md5_safe(path)[:12])
221 221
222 222
223 223 class _GetError(object):
224 224 """Get error from form_errors, and represent it as span wrapped error
225 225 message
226 226
227 227 :param field_name: field to fetch errors for
228 228 :param form_errors: form errors dict
229 229 """
230 230
231 231 def __call__(self, field_name, form_errors):
232 232 tmpl = """<span class="error_msg">%s</span>"""
233 233 if form_errors and field_name in form_errors:
234 234 return literal(tmpl % form_errors.get(field_name))
235 235
236 236
237 237 get_error = _GetError()
238 238
239 239
240 240 class _ToolTip(object):
241 241
242 242 def __call__(self, tooltip_title, trim_at=50):
243 243 """
244 244 Special function just to wrap our text into nice formatted
245 245 autowrapped text
246 246
247 247 :param tooltip_title:
248 248 """
249 249 tooltip_title = escape(tooltip_title)
250 250 tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
251 251 return tooltip_title
252 252
253 253
254 254 tooltip = _ToolTip()
255 255
256 256 files_icon = u'<i class="file-breadcrumb-copy tooltip icon-clipboard clipboard-action" data-clipboard-text="{}" title="Copy file path"></i>'
257 257
258 258
259 def files_breadcrumbs(repo_name, commit_id, file_path, at_ref=None, limit_items=False, linkify_last_item=False):
259 def files_breadcrumbs(repo_name, repo_type, commit_id, file_path, landing_ref_name=None, at_ref=None,
260 limit_items=False, linkify_last_item=False, hide_last_item=False,
261 copy_path_icon=True):
260 262 if isinstance(file_path, str):
261 263 file_path = safe_unicode(file_path)
262 264
263 route_qry = {'at': at_ref} if at_ref else None
265 if at_ref:
266 route_qry = {'at': at_ref}
267 default_landing_ref = at_ref or landing_ref_name or commit_id
268 else:
269 route_qry = None
270 default_landing_ref = commit_id
264 271
265 # first segment is a `..` link to repo files
272 # first segment is a `HOME` link to repo files root location
266 273 root_name = literal(u'<i class="icon-home"></i>')
274
267 275 url_segments = [
268 276 link_to(
269 277 root_name,
270 route_path(
271 'repo_files',
272 repo_name=repo_name,
278 repo_files_by_ref_url(
279 repo_name,
280 repo_type,
281 f_path=None, # None here is a special case for SVN repos,
282 # that won't prefix with a ref
283 ref_name=default_landing_ref,
273 284 commit_id=commit_id,
274 f_path='',
275 _query=route_qry),
285 query=route_qry
286 )
276 287 )]
277 288
278 289 path_segments = file_path.split('/')
279 290 last_cnt = len(path_segments) - 1
280 291 for cnt, segment in enumerate(path_segments):
281 292 if not segment:
282 293 continue
283 294 segment_html = escape(segment)
284 295
285 296 last_item = cnt == last_cnt
286 297
298 if last_item and hide_last_item:
299 # iterate over and hide last element
300 continue
301
287 302 if last_item and linkify_last_item is False:
288 303 # plain version
289 304 url_segments.append(segment_html)
290 305 else:
291 306 url_segments.append(
292 307 link_to(
293 308 segment_html,
294 route_path(
295 'repo_files',
296 repo_name=repo_name,
309 repo_files_by_ref_url(
310 repo_name,
311 repo_type,
312 f_path='/'.join(path_segments[:cnt + 1]),
313 ref_name=default_landing_ref,
297 314 commit_id=commit_id,
298 f_path='/'.join(path_segments[:cnt + 1]),
299 _query=route_qry),
315 query=route_qry
316 ),
300 317 ))
301 318
302 319 limited_url_segments = url_segments[:1] + ['...'] + url_segments[-5:]
303 320 if limit_items and len(limited_url_segments) < len(url_segments):
304 321 url_segments = limited_url_segments
305 322
306 323 full_path = file_path
307 icon = files_icon.format(escape(full_path))
324 if copy_path_icon:
325 icon = files_icon.format(escape(full_path))
326 else:
327 icon = ''
328
308 329 if file_path == '':
309 330 return root_name
310 331 else:
311 332 return literal(' / '.join(url_segments) + icon)
312 333
313 334
314 335 def files_url_data(request):
315 336 matchdict = request.matchdict
316 337
317 338 if 'f_path' not in matchdict:
318 339 matchdict['f_path'] = ''
319 340
320 341 if 'commit_id' not in matchdict:
321 342 matchdict['commit_id'] = 'tip'
322 343
323 344 return json.dumps(matchdict)
324 345
325 346
347 def repo_files_by_ref_url(db_repo_name, db_repo_type, f_path, ref_name, commit_id, query=None, ):
348 _is_svn = is_svn(db_repo_type)
349 final_f_path = f_path
350
351 if _is_svn:
352 """
353 For SVN the ref_name cannot be used as a commit_id, it needs to be prefixed with
354 actually commit_id followed by the ref_name. This should be done only in case
355 This is a initial landing url, without additional paths.
356
357 like: /1000/tags/1.0.0/?at=tags/1.0.0
358 """
359
360 if ref_name and ref_name != 'tip':
361 # NOTE(marcink): for svn the ref_name is actually the stored path, so we prefix it
362 # for SVN we only do this magic prefix if it's root, .eg landing revision
363 # of files link. If we are in the tree we don't need this since we traverse the url
364 # that has everything stored
365 if f_path in ['', '/']:
366 final_f_path = '/'.join([ref_name, f_path])
367
368 # SVN always needs a commit_id explicitly, without a named REF
369 default_commit_id = commit_id
370 else:
371 """
372 For git and mercurial we construct a new URL using the names instead of commit_id
373 like: /master/some_path?at=master
374 """
375 # We currently do not support branches with slashes
376 if '/' in ref_name:
377 default_commit_id = commit_id
378 else:
379 default_commit_id = ref_name
380
381 # sometimes we pass f_path as None, to indicate explicit no prefix,
382 # we translate it to string to not have None
383 final_f_path = final_f_path or ''
384
385 files_url = route_path(
386 'repo_files',
387 repo_name=db_repo_name,
388 commit_id=default_commit_id,
389 f_path=final_f_path,
390 _query=query
391 )
392 return files_url
393
394
326 395 def code_highlight(code, lexer, formatter, use_hl_filter=False):
327 396 """
328 397 Lex ``code`` with ``lexer`` and format it with the formatter ``formatter``.
329 398
330 399 If ``outfile`` is given and a valid file object (an object
331 400 with a ``write`` method), the result will be written to it, otherwise
332 401 it is returned as a string.
333 402 """
334 403 if use_hl_filter:
335 404 # add HL filter
336 405 from rhodecode.lib.index import search_utils
337 406 lexer.add_filter(search_utils.ElasticSearchHLFilter())
338 407 return pygments.format(pygments.lex(code, lexer), formatter)
339 408
340 409
341 410 class CodeHtmlFormatter(HtmlFormatter):
342 411 """
343 412 My code Html Formatter for source codes
344 413 """
345 414
346 415 def wrap(self, source, outfile):
347 416 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
348 417
349 418 def _wrap_code(self, source):
350 419 for cnt, it in enumerate(source):
351 420 i, t = it
352 421 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
353 422 yield i, t
354 423
355 424 def _wrap_tablelinenos(self, inner):
356 425 dummyoutfile = StringIO.StringIO()
357 426 lncount = 0
358 427 for t, line in inner:
359 428 if t:
360 429 lncount += 1
361 430 dummyoutfile.write(line)
362 431
363 432 fl = self.linenostart
364 433 mw = len(str(lncount + fl - 1))
365 434 sp = self.linenospecial
366 435 st = self.linenostep
367 436 la = self.lineanchors
368 437 aln = self.anchorlinenos
369 438 nocls = self.noclasses
370 439 if sp:
371 440 lines = []
372 441
373 442 for i in range(fl, fl + lncount):
374 443 if i % st == 0:
375 444 if i % sp == 0:
376 445 if aln:
377 446 lines.append('<a href="#%s%d" class="special">%*d</a>' %
378 447 (la, i, mw, i))
379 448 else:
380 449 lines.append('<span class="special">%*d</span>' % (mw, i))
381 450 else:
382 451 if aln:
383 452 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
384 453 else:
385 454 lines.append('%*d' % (mw, i))
386 455 else:
387 456 lines.append('')
388 457 ls = '\n'.join(lines)
389 458 else:
390 459 lines = []
391 460 for i in range(fl, fl + lncount):
392 461 if i % st == 0:
393 462 if aln:
394 463 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
395 464 else:
396 465 lines.append('%*d' % (mw, i))
397 466 else:
398 467 lines.append('')
399 468 ls = '\n'.join(lines)
400 469
401 470 # in case you wonder about the seemingly redundant <div> here: since the
402 471 # content in the other cell also is wrapped in a div, some browsers in
403 472 # some configurations seem to mess up the formatting...
404 473 if nocls:
405 474 yield 0, ('<table class="%stable">' % self.cssclass +
406 475 '<tr><td><div class="linenodiv" '
407 476 'style="background-color: #f0f0f0; padding-right: 10px">'
408 477 '<pre style="line-height: 125%">' +
409 478 ls + '</pre></div></td><td id="hlcode" class="code">')
410 479 else:
411 480 yield 0, ('<table class="%stable">' % self.cssclass +
412 481 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
413 482 ls + '</pre></div></td><td id="hlcode" class="code">')
414 483 yield 0, dummyoutfile.getvalue()
415 484 yield 0, '</td></tr></table>'
416 485
417 486
418 487 class SearchContentCodeHtmlFormatter(CodeHtmlFormatter):
419 488 def __init__(self, **kw):
420 489 # only show these line numbers if set
421 490 self.only_lines = kw.pop('only_line_numbers', [])
422 491 self.query_terms = kw.pop('query_terms', [])
423 492 self.max_lines = kw.pop('max_lines', 5)
424 493 self.line_context = kw.pop('line_context', 3)
425 494 self.url = kw.pop('url', None)
426 495
427 496 super(CodeHtmlFormatter, self).__init__(**kw)
428 497
429 498 def _wrap_code(self, source):
430 499 for cnt, it in enumerate(source):
431 500 i, t = it
432 501 t = '<pre>%s</pre>' % t
433 502 yield i, t
434 503
435 504 def _wrap_tablelinenos(self, inner):
436 505 yield 0, '<table class="code-highlight %stable">' % self.cssclass
437 506
438 507 last_shown_line_number = 0
439 508 current_line_number = 1
440 509
441 510 for t, line in inner:
442 511 if not t:
443 512 yield t, line
444 513 continue
445 514
446 515 if current_line_number in self.only_lines:
447 516 if last_shown_line_number + 1 != current_line_number:
448 517 yield 0, '<tr>'
449 518 yield 0, '<td class="line">...</td>'
450 519 yield 0, '<td id="hlcode" class="code"></td>'
451 520 yield 0, '</tr>'
452 521
453 522 yield 0, '<tr>'
454 523 if self.url:
455 524 yield 0, '<td class="line"><a href="%s#L%i">%i</a></td>' % (
456 525 self.url, current_line_number, current_line_number)
457 526 else:
458 527 yield 0, '<td class="line"><a href="">%i</a></td>' % (
459 528 current_line_number)
460 529 yield 0, '<td id="hlcode" class="code">' + line + '</td>'
461 530 yield 0, '</tr>'
462 531
463 532 last_shown_line_number = current_line_number
464 533
465 534 current_line_number += 1
466 535
467 536 yield 0, '</table>'
468 537
469 538
470 539 def hsv_to_rgb(h, s, v):
471 540 """ Convert hsv color values to rgb """
472 541
473 542 if s == 0.0:
474 543 return v, v, v
475 544 i = int(h * 6.0) # XXX assume int() truncates!
476 545 f = (h * 6.0) - i
477 546 p = v * (1.0 - s)
478 547 q = v * (1.0 - s * f)
479 548 t = v * (1.0 - s * (1.0 - f))
480 549 i = i % 6
481 550 if i == 0:
482 551 return v, t, p
483 552 if i == 1:
484 553 return q, v, p
485 554 if i == 2:
486 555 return p, v, t
487 556 if i == 3:
488 557 return p, q, v
489 558 if i == 4:
490 559 return t, p, v
491 560 if i == 5:
492 561 return v, p, q
493 562
494 563
495 564 def unique_color_generator(n=10000, saturation=0.10, lightness=0.95):
496 565 """
497 566 Generator for getting n of evenly distributed colors using
498 567 hsv color and golden ratio. It always return same order of colors
499 568
500 569 :param n: number of colors to generate
501 570 :param saturation: saturation of returned colors
502 571 :param lightness: lightness of returned colors
503 572 :returns: RGB tuple
504 573 """
505 574
506 575 golden_ratio = 0.618033988749895
507 576 h = 0.22717784590367374
508 577
509 578 for _ in xrange(n):
510 579 h += golden_ratio
511 580 h %= 1
512 581 HSV_tuple = [h, saturation, lightness]
513 582 RGB_tuple = hsv_to_rgb(*HSV_tuple)
514 583 yield map(lambda x: str(int(x * 256)), RGB_tuple)
515 584
516 585
517 586 def color_hasher(n=10000, saturation=0.10, lightness=0.95):
518 587 """
519 588 Returns a function which when called with an argument returns a unique
520 589 color for that argument, eg.
521 590
522 591 :param n: number of colors to generate
523 592 :param saturation: saturation of returned colors
524 593 :param lightness: lightness of returned colors
525 594 :returns: css RGB string
526 595
527 596 >>> color_hash = color_hasher()
528 597 >>> color_hash('hello')
529 598 'rgb(34, 12, 59)'
530 599 >>> color_hash('hello')
531 600 'rgb(34, 12, 59)'
532 601 >>> color_hash('other')
533 602 'rgb(90, 224, 159)'
534 603 """
535 604
536 605 color_dict = {}
537 606 cgenerator = unique_color_generator(
538 607 saturation=saturation, lightness=lightness)
539 608
540 609 def get_color_string(thing):
541 610 if thing in color_dict:
542 611 col = color_dict[thing]
543 612 else:
544 613 col = color_dict[thing] = cgenerator.next()
545 614 return "rgb(%s)" % (', '.join(col))
546 615
547 616 return get_color_string
548 617
549 618
550 619 def get_lexer_safe(mimetype=None, filepath=None):
551 620 """
552 621 Tries to return a relevant pygments lexer using mimetype/filepath name,
553 622 defaulting to plain text if none could be found
554 623 """
555 624 lexer = None
556 625 try:
557 626 if mimetype:
558 627 lexer = get_lexer_for_mimetype(mimetype)
559 628 if not lexer:
560 629 lexer = get_lexer_for_filename(filepath)
561 630 except pygments.util.ClassNotFound:
562 631 pass
563 632
564 633 if not lexer:
565 634 lexer = get_lexer_by_name('text')
566 635
567 636 return lexer
568 637
569 638
570 639 def get_lexer_for_filenode(filenode):
571 640 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
572 641 return lexer
573 642
574 643
575 644 def pygmentize(filenode, **kwargs):
576 645 """
577 646 pygmentize function using pygments
578 647
579 648 :param filenode:
580 649 """
581 650 lexer = get_lexer_for_filenode(filenode)
582 651 return literal(code_highlight(filenode.content, lexer,
583 652 CodeHtmlFormatter(**kwargs)))
584 653
585 654
586 655 def is_following_repo(repo_name, user_id):
587 656 from rhodecode.model.scm import ScmModel
588 657 return ScmModel().is_following_repo(repo_name, user_id)
589 658
590 659
591 660 class _Message(object):
592 661 """A message returned by ``Flash.pop_messages()``.
593 662
594 663 Converting the message to a string returns the message text. Instances
595 664 also have the following attributes:
596 665
597 666 * ``message``: the message text.
598 667 * ``category``: the category specified when the message was created.
599 668 """
600 669
601 670 def __init__(self, category, message, sub_data=None):
602 671 self.category = category
603 672 self.message = message
604 673 self.sub_data = sub_data or {}
605 674
606 675 def __str__(self):
607 676 return self.message
608 677
609 678 __unicode__ = __str__
610 679
611 680 def __html__(self):
612 681 return escape(safe_unicode(self.message))
613 682
614 683
615 684 class Flash(object):
616 685 # List of allowed categories. If None, allow any category.
617 686 categories = ["warning", "notice", "error", "success"]
618 687
619 688 # Default category if none is specified.
620 689 default_category = "notice"
621 690
622 691 def __init__(self, session_key="flash", categories=None,
623 692 default_category=None):
624 693 """
625 694 Instantiate a ``Flash`` object.
626 695
627 696 ``session_key`` is the key to save the messages under in the user's
628 697 session.
629 698
630 699 ``categories`` is an optional list which overrides the default list
631 700 of categories.
632 701
633 702 ``default_category`` overrides the default category used for messages
634 703 when none is specified.
635 704 """
636 705 self.session_key = session_key
637 706 if categories is not None:
638 707 self.categories = categories
639 708 if default_category is not None:
640 709 self.default_category = default_category
641 710 if self.categories and self.default_category not in self.categories:
642 711 raise ValueError(
643 712 "unrecognized default category %r" % (self.default_category,))
644 713
645 714 def pop_messages(self, session=None, request=None):
646 715 """
647 716 Return all accumulated messages and delete them from the session.
648 717
649 718 The return value is a list of ``Message`` objects.
650 719 """
651 720 messages = []
652 721
653 722 if not session:
654 723 if not request:
655 724 request = get_current_request()
656 725 session = request.session
657 726
658 727 # Pop the 'old' pylons flash messages. They are tuples of the form
659 728 # (category, message)
660 729 for cat, msg in session.pop(self.session_key, []):
661 730 messages.append(_Message(cat, msg))
662 731
663 732 # Pop the 'new' pyramid flash messages for each category as list
664 733 # of strings.
665 734 for cat in self.categories:
666 735 for msg in session.pop_flash(queue=cat):
667 736 sub_data = {}
668 737 if hasattr(msg, 'rsplit'):
669 738 flash_data = msg.rsplit('|DELIM|', 1)
670 739 org_message = flash_data[0]
671 740 if len(flash_data) > 1:
672 741 sub_data = json.loads(flash_data[1])
673 742 else:
674 743 org_message = msg
675 744
676 745 messages.append(_Message(cat, org_message, sub_data=sub_data))
677 746
678 747 # Map messages from the default queue to the 'notice' category.
679 748 for msg in session.pop_flash():
680 749 messages.append(_Message('notice', msg))
681 750
682 751 session.save()
683 752 return messages
684 753
685 754 def json_alerts(self, session=None, request=None):
686 755 payloads = []
687 756 messages = flash.pop_messages(session=session, request=request) or []
688 757 for message in messages:
689 758 payloads.append({
690 759 'message': {
691 760 'message': u'{}'.format(message.message),
692 761 'level': message.category,
693 762 'force': True,
694 763 'subdata': message.sub_data
695 764 }
696 765 })
697 766 return json.dumps(payloads)
698 767
699 768 def __call__(self, message, category=None, ignore_duplicate=True,
700 769 session=None, request=None):
701 770
702 771 if not session:
703 772 if not request:
704 773 request = get_current_request()
705 774 session = request.session
706 775
707 776 session.flash(
708 777 message, queue=category, allow_duplicate=not ignore_duplicate)
709 778
710 779
711 780 flash = Flash()
712 781
713 782 #==============================================================================
714 783 # SCM FILTERS available via h.
715 784 #==============================================================================
716 785 from rhodecode.lib.vcs.utils import author_name, author_email
717 786 from rhodecode.lib.utils2 import credentials_filter, age, age_from_seconds
718 787 from rhodecode.model.db import User, ChangesetStatus
719 788
720 789 capitalize = lambda x: x.capitalize()
721 790 email = author_email
722 791 short_id = lambda x: x[:12]
723 792 hide_credentials = lambda x: ''.join(credentials_filter(x))
724 793
725 794
726 795 import pytz
727 796 import tzlocal
728 797 local_timezone = tzlocal.get_localzone()
729 798
730 799
731 800 def age_component(datetime_iso, value=None, time_is_local=False, tooltip=True):
732 801 title = value or format_date(datetime_iso)
733 802 tzinfo = '+00:00'
734 803
735 804 # detect if we have a timezone info, otherwise, add it
736 805 if time_is_local and isinstance(datetime_iso, datetime) and not datetime_iso.tzinfo:
737 806 force_timezone = os.environ.get('RC_TIMEZONE', '')
738 807 if force_timezone:
739 808 force_timezone = pytz.timezone(force_timezone)
740 809 timezone = force_timezone or local_timezone
741 810 offset = timezone.localize(datetime_iso).strftime('%z')
742 811 tzinfo = '{}:{}'.format(offset[:-2], offset[-2:])
743 812
744 813 return literal(
745 814 '<time class="timeago {cls}" title="{tt_title}" datetime="{dt}{tzinfo}">{title}</time>'.format(
746 815 cls='tooltip' if tooltip else '',
747 816 tt_title=('{title}{tzinfo}'.format(title=title, tzinfo=tzinfo)) if tooltip else '',
748 817 title=title, dt=datetime_iso, tzinfo=tzinfo
749 818 ))
750 819
751 820
752 821 def _shorten_commit_id(commit_id, commit_len=None):
753 822 if commit_len is None:
754 823 request = get_current_request()
755 824 commit_len = request.call_context.visual.show_sha_length
756 825 return commit_id[:commit_len]
757 826
758 827
759 828 def show_id(commit, show_idx=None, commit_len=None):
760 829 """
761 830 Configurable function that shows ID
762 831 by default it's r123:fffeeefffeee
763 832
764 833 :param commit: commit instance
765 834 """
766 835 if show_idx is None:
767 836 request = get_current_request()
768 837 show_idx = request.call_context.visual.show_revision_number
769 838
770 839 raw_id = _shorten_commit_id(commit.raw_id, commit_len=commit_len)
771 840 if show_idx:
772 841 return 'r%s:%s' % (commit.idx, raw_id)
773 842 else:
774 843 return '%s' % (raw_id, )
775 844
776 845
777 846 def format_date(date):
778 847 """
779 848 use a standardized formatting for dates used in RhodeCode
780 849
781 850 :param date: date/datetime object
782 851 :return: formatted date
783 852 """
784 853
785 854 if date:
786 855 _fmt = "%a, %d %b %Y %H:%M:%S"
787 856 return safe_unicode(date.strftime(_fmt))
788 857
789 858 return u""
790 859
791 860
792 861 class _RepoChecker(object):
793 862
794 863 def __init__(self, backend_alias):
795 864 self._backend_alias = backend_alias
796 865
797 866 def __call__(self, repository):
798 867 if hasattr(repository, 'alias'):
799 868 _type = repository.alias
800 869 elif hasattr(repository, 'repo_type'):
801 870 _type = repository.repo_type
802 871 else:
803 872 _type = repository
804 873 return _type == self._backend_alias
805 874
806 875
807 876 is_git = _RepoChecker('git')
808 877 is_hg = _RepoChecker('hg')
809 878 is_svn = _RepoChecker('svn')
810 879
811 880
812 881 def get_repo_type_by_name(repo_name):
813 882 repo = Repository.get_by_repo_name(repo_name)
814 883 if repo:
815 884 return repo.repo_type
816 885
817 886
818 887 def is_svn_without_proxy(repository):
819 888 if is_svn(repository):
820 889 from rhodecode.model.settings import VcsSettingsModel
821 890 conf = VcsSettingsModel().get_ui_settings_as_config_obj()
822 891 return not str2bool(conf.get('vcs_svn_proxy', 'http_requests_enabled'))
823 892 return False
824 893
825 894
826 895 def discover_user(author):
827 896 """
828 897 Tries to discover RhodeCode User based on the author string. Author string
829 898 is typically `FirstName LastName <email@address.com>`
830 899 """
831 900
832 901 # if author is already an instance use it for extraction
833 902 if isinstance(author, User):
834 903 return author
835 904
836 905 # Valid email in the attribute passed, see if they're in the system
837 906 _email = author_email(author)
838 907 if _email != '':
839 908 user = User.get_by_email(_email, case_insensitive=True, cache=True)
840 909 if user is not None:
841 910 return user
842 911
843 912 # Maybe it's a username, we try to extract it and fetch by username ?
844 913 _author = author_name(author)
845 914 user = User.get_by_username(_author, case_insensitive=True, cache=True)
846 915 if user is not None:
847 916 return user
848 917
849 918 return None
850 919
851 920
852 921 def email_or_none(author):
853 922 # extract email from the commit string
854 923 _email = author_email(author)
855 924
856 925 # If we have an email, use it, otherwise
857 926 # see if it contains a username we can get an email from
858 927 if _email != '':
859 928 return _email
860 929 else:
861 930 user = User.get_by_username(
862 931 author_name(author), case_insensitive=True, cache=True)
863 932
864 933 if user is not None:
865 934 return user.email
866 935
867 936 # No valid email, not a valid user in the system, none!
868 937 return None
869 938
870 939
871 940 def link_to_user(author, length=0, **kwargs):
872 941 user = discover_user(author)
873 942 # user can be None, but if we have it already it means we can re-use it
874 943 # in the person() function, so we save 1 intensive-query
875 944 if user:
876 945 author = user
877 946
878 947 display_person = person(author, 'username_or_name_or_email')
879 948 if length:
880 949 display_person = shorter(display_person, length)
881 950
882 951 if user:
883 952 return link_to(
884 953 escape(display_person),
885 954 route_path('user_profile', username=user.username),
886 955 **kwargs)
887 956 else:
888 957 return escape(display_person)
889 958
890 959
891 960 def link_to_group(users_group_name, **kwargs):
892 961 return link_to(
893 962 escape(users_group_name),
894 963 route_path('user_group_profile', user_group_name=users_group_name),
895 964 **kwargs)
896 965
897 966
898 967 def person(author, show_attr="username_and_name"):
899 968 user = discover_user(author)
900 969 if user:
901 970 return getattr(user, show_attr)
902 971 else:
903 972 _author = author_name(author)
904 973 _email = email(author)
905 974 return _author or _email
906 975
907 976
908 977 def author_string(email):
909 978 if email:
910 979 user = User.get_by_email(email, case_insensitive=True, cache=True)
911 980 if user:
912 981 if user.first_name or user.last_name:
913 982 return '%s %s &lt;%s&gt;' % (
914 983 user.first_name, user.last_name, email)
915 984 else:
916 985 return email
917 986 else:
918 987 return email
919 988 else:
920 989 return None
921 990
922 991
923 992 def person_by_id(id_, show_attr="username_and_name"):
924 993 # attr to return from fetched user
925 994 person_getter = lambda usr: getattr(usr, show_attr)
926 995
927 996 #maybe it's an ID ?
928 997 if str(id_).isdigit() or isinstance(id_, int):
929 998 id_ = int(id_)
930 999 user = User.get(id_)
931 1000 if user is not None:
932 1001 return person_getter(user)
933 1002 return id_
934 1003
935 1004
936 1005 def gravatar_with_user(request, author, show_disabled=False, tooltip=False):
937 1006 _render = request.get_partial_renderer('rhodecode:templates/base/base.mako')
938 1007 return _render('gravatar_with_user', author, show_disabled=show_disabled, tooltip=tooltip)
939 1008
940 1009
941 1010 tags_paterns = OrderedDict((
942 1011 ('lang', (re.compile(r'\[(lang|language)\ \=\&gt;\ *([a-zA-Z\-\/\#\+\.]*)\]'),
943 1012 '<div class="metatag" tag="lang">\\2</div>')),
944 1013
945 1014 ('see', (re.compile(r'\[see\ \=\&gt;\ *([a-zA-Z0-9\/\=\?\&amp;\ \:\/\.\-]*)\]'),
946 1015 '<div class="metatag" tag="see">see: \\1 </div>')),
947 1016
948 1017 ('url', (re.compile(r'\[url\ \=\&gt;\ \[([a-zA-Z0-9\ \.\-\_]+)\]\((http://|https://|/)(.*?)\)\]'),
949 1018 '<div class="metatag" tag="url"> <a href="\\2\\3">\\1</a> </div>')),
950 1019
951 1020 ('license', (re.compile(r'\[license\ \=\&gt;\ *([a-zA-Z0-9\/\=\?\&amp;\ \:\/\.\-]*)\]'),
952 1021 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>')),
953 1022
954 1023 ('ref', (re.compile(r'\[(requires|recommends|conflicts|base)\ \=\&gt;\ *([a-zA-Z0-9\-\/]*)\]'),
955 1024 '<div class="metatag" tag="ref \\1">\\1: <a href="/\\2">\\2</a></div>')),
956 1025
957 1026 ('state', (re.compile(r'\[(stable|featured|stale|dead|dev|deprecated)\]'),
958 1027 '<div class="metatag" tag="state \\1">\\1</div>')),
959 1028
960 1029 # label in grey
961 1030 ('label', (re.compile(r'\[([a-z]+)\]'),
962 1031 '<div class="metatag" tag="label">\\1</div>')),
963 1032
964 1033 # generic catch all in grey
965 1034 ('generic', (re.compile(r'\[([a-zA-Z0-9\.\-\_]+)\]'),
966 1035 '<div class="metatag" tag="generic">\\1</div>')),
967 1036 ))
968 1037
969 1038
970 1039 def extract_metatags(value):
971 1040 """
972 1041 Extract supported meta-tags from given text value
973 1042 """
974 1043 tags = []
975 1044 if not value:
976 1045 return tags, ''
977 1046
978 1047 for key, val in tags_paterns.items():
979 1048 pat, replace_html = val
980 1049 tags.extend([(key, x.group()) for x in pat.finditer(value)])
981 1050 value = pat.sub('', value)
982 1051
983 1052 return tags, value
984 1053
985 1054
986 1055 def style_metatag(tag_type, value):
987 1056 """
988 1057 converts tags from value into html equivalent
989 1058 """
990 1059 if not value:
991 1060 return ''
992 1061
993 1062 html_value = value
994 1063 tag_data = tags_paterns.get(tag_type)
995 1064 if tag_data:
996 1065 pat, replace_html = tag_data
997 1066 # convert to plain `unicode` instead of a markup tag to be used in
998 1067 # regex expressions. safe_unicode doesn't work here
999 1068 html_value = pat.sub(replace_html, unicode(value))
1000 1069
1001 1070 return html_value
1002 1071
1003 1072
1004 1073 def bool2icon(value, show_at_false=True):
1005 1074 """
1006 1075 Returns boolean value of a given value, represented as html element with
1007 1076 classes that will represent icons
1008 1077
1009 1078 :param value: given value to convert to html node
1010 1079 """
1011 1080
1012 1081 if value: # does bool conversion
1013 1082 return HTML.tag('i', class_="icon-true", title='True')
1014 1083 else: # not true as bool
1015 1084 if show_at_false:
1016 1085 return HTML.tag('i', class_="icon-false", title='False')
1017 1086 return HTML.tag('i')
1018 1087
1019 1088 #==============================================================================
1020 1089 # PERMS
1021 1090 #==============================================================================
1022 1091 from rhodecode.lib.auth import (
1023 1092 HasPermissionAny, HasPermissionAll,
1024 1093 HasRepoPermissionAny, HasRepoPermissionAll, HasRepoGroupPermissionAll,
1025 1094 HasRepoGroupPermissionAny, HasRepoPermissionAnyApi, get_csrf_token,
1026 1095 csrf_token_key, AuthUser)
1027 1096
1028 1097
1029 1098 #==============================================================================
1030 1099 # GRAVATAR URL
1031 1100 #==============================================================================
1032 1101 class InitialsGravatar(object):
1033 1102 def __init__(self, email_address, first_name, last_name, size=30,
1034 1103 background=None, text_color='#fff'):
1035 1104 self.size = size
1036 1105 self.first_name = first_name
1037 1106 self.last_name = last_name
1038 1107 self.email_address = email_address
1039 1108 self.background = background or self.str2color(email_address)
1040 1109 self.text_color = text_color
1041 1110
1042 1111 def get_color_bank(self):
1043 1112 """
1044 1113 returns a predefined list of colors that gravatars can use.
1045 1114 Those are randomized distinct colors that guarantee readability and
1046 1115 uniqueness.
1047 1116
1048 1117 generated with: http://phrogz.net/css/distinct-colors.html
1049 1118 """
1050 1119 return [
1051 1120 '#bf3030', '#a67f53', '#00ff00', '#5989b3', '#392040', '#d90000',
1052 1121 '#402910', '#204020', '#79baf2', '#a700b3', '#bf6060', '#7f5320',
1053 1122 '#008000', '#003059', '#ee00ff', '#ff0000', '#8c4b00', '#007300',
1054 1123 '#005fb3', '#de73e6', '#ff4040', '#ffaa00', '#3df255', '#203140',
1055 1124 '#47004d', '#591616', '#664400', '#59b365', '#0d2133', '#83008c',
1056 1125 '#592d2d', '#bf9f60', '#73e682', '#1d3f73', '#73006b', '#402020',
1057 1126 '#b2862d', '#397341', '#597db3', '#e600d6', '#a60000', '#736039',
1058 1127 '#00b318', '#79aaf2', '#330d30', '#ff8080', '#403010', '#16591f',
1059 1128 '#002459', '#8c4688', '#e50000', '#ffbf40', '#00732e', '#102340',
1060 1129 '#bf60ac', '#8c4646', '#cc8800', '#00a642', '#1d3473', '#b32d98',
1061 1130 '#660e00', '#ffd580', '#80ffb2', '#7391e6', '#733967', '#d97b6c',
1062 1131 '#8c5e00', '#59b389', '#3967e6', '#590047', '#73281d', '#665200',
1063 1132 '#00e67a', '#2d50b3', '#8c2377', '#734139', '#b2982d', '#16593a',
1064 1133 '#001859', '#ff00aa', '#a65e53', '#ffcc00', '#0d3321', '#2d3959',
1065 1134 '#731d56', '#401610', '#4c3d00', '#468c6c', '#002ca6', '#d936a3',
1066 1135 '#d94c36', '#403920', '#36d9a3', '#0d1733', '#592d4a', '#993626',
1067 1136 '#cca300', '#00734d', '#46598c', '#8c005e', '#7f1100', '#8c7000',
1068 1137 '#00a66f', '#7382e6', '#b32d74', '#d9896c', '#ffe680', '#1d7362',
1069 1138 '#364cd9', '#73003d', '#d93a00', '#998a4d', '#59b3a1', '#5965b3',
1070 1139 '#e5007a', '#73341d', '#665f00', '#00b38f', '#0018b3', '#59163a',
1071 1140 '#b2502d', '#bfb960', '#00ffcc', '#23318c', '#a6537f', '#734939',
1072 1141 '#b2a700', '#104036', '#3d3df2', '#402031', '#e56739', '#736f39',
1073 1142 '#79f2ea', '#000059', '#401029', '#4c1400', '#ffee00', '#005953',
1074 1143 '#101040', '#990052', '#402820', '#403d10', '#00ffee', '#0000d9',
1075 1144 '#ff80c4', '#a66953', '#eeff00', '#00ccbe', '#8080ff', '#e673a1',
1076 1145 '#a62c00', '#474d00', '#1a3331', '#46468c', '#733950', '#662900',
1077 1146 '#858c23', '#238c85', '#0f0073', '#b20047', '#d9986c', '#becc00',
1078 1147 '#396f73', '#281d73', '#ff0066', '#ff6600', '#dee673', '#59adb3',
1079 1148 '#6559b3', '#590024', '#b2622d', '#98b32d', '#36ced9', '#332d59',
1080 1149 '#40001a', '#733f1d', '#526600', '#005359', '#242040', '#bf6079',
1081 1150 '#735039', '#cef23d', '#007780', '#5630bf', '#66001b', '#b24700',
1082 1151 '#acbf60', '#1d6273', '#25008c', '#731d34', '#a67453', '#50592d',
1083 1152 '#00ccff', '#6600ff', '#ff0044', '#4c1f00', '#8a994d', '#79daf2',
1084 1153 '#a173e6', '#d93662', '#402310', '#aaff00', '#2d98b3', '#8c40ff',
1085 1154 '#592d39', '#ff8c40', '#354020', '#103640', '#1a0040', '#331a20',
1086 1155 '#331400', '#334d00', '#1d5673', '#583973', '#7f0022', '#4c3626',
1087 1156 '#88cc00', '#36a3d9', '#3d0073', '#d9364c', '#33241a', '#698c23',
1088 1157 '#5995b3', '#300059', '#e57382', '#7f3300', '#366600', '#00aaff',
1089 1158 '#3a1659', '#733941', '#663600', '#74b32d', '#003c59', '#7f53a6',
1090 1159 '#73000f', '#ff8800', '#baf279', '#79caf2', '#291040', '#a6293a',
1091 1160 '#b2742d', '#587339', '#0077b3', '#632699', '#400009', '#d9a66c',
1092 1161 '#294010', '#2d4a59', '#aa00ff', '#4c131b', '#b25f00', '#5ce600',
1093 1162 '#267399', '#a336d9', '#990014', '#664e33', '#86bf60', '#0088ff',
1094 1163 '#7700b3', '#593a16', '#073300', '#1d4b73', '#ac60bf', '#e59539',
1095 1164 '#4f8c46', '#368dd9', '#5c0073'
1096 1165 ]
1097 1166
1098 1167 def rgb_to_hex_color(self, rgb_tuple):
1099 1168 """
1100 1169 Converts an rgb_tuple passed to an hex color.
1101 1170
1102 1171 :param rgb_tuple: tuple with 3 ints represents rgb color space
1103 1172 """
1104 1173 return '#' + ("".join(map(chr, rgb_tuple)).encode('hex'))
1105 1174
1106 1175 def email_to_int_list(self, email_str):
1107 1176 """
1108 1177 Get every byte of the hex digest value of email and turn it to integer.
1109 1178 It's going to be always between 0-255
1110 1179 """
1111 1180 digest = md5_safe(email_str.lower())
1112 1181 return [int(digest[i * 2:i * 2 + 2], 16) for i in range(16)]
1113 1182
1114 1183 def pick_color_bank_index(self, email_str, color_bank):
1115 1184 return self.email_to_int_list(email_str)[0] % len(color_bank)
1116 1185
1117 1186 def str2color(self, email_str):
1118 1187 """
1119 1188 Tries to map in a stable algorithm an email to color
1120 1189
1121 1190 :param email_str:
1122 1191 """
1123 1192 color_bank = self.get_color_bank()
1124 1193 # pick position (module it's length so we always find it in the
1125 1194 # bank even if it's smaller than 256 values
1126 1195 pos = self.pick_color_bank_index(email_str, color_bank)
1127 1196 return color_bank[pos]
1128 1197
1129 1198 def normalize_email(self, email_address):
1130 1199 import unicodedata
1131 1200 # default host used to fill in the fake/missing email
1132 1201 default_host = u'localhost'
1133 1202
1134 1203 if not email_address:
1135 1204 email_address = u'%s@%s' % (User.DEFAULT_USER, default_host)
1136 1205
1137 1206 email_address = safe_unicode(email_address)
1138 1207
1139 1208 if u'@' not in email_address:
1140 1209 email_address = u'%s@%s' % (email_address, default_host)
1141 1210
1142 1211 if email_address.endswith(u'@'):
1143 1212 email_address = u'%s%s' % (email_address, default_host)
1144 1213
1145 1214 email_address = unicodedata.normalize('NFKD', email_address)\
1146 1215 .encode('ascii', 'ignore')
1147 1216 return email_address
1148 1217
1149 1218 def get_initials(self):
1150 1219 """
1151 1220 Returns 2 letter initials calculated based on the input.
1152 1221 The algorithm picks first given email address, and takes first letter
1153 1222 of part before @, and then the first letter of server name. In case
1154 1223 the part before @ is in a format of `somestring.somestring2` it replaces
1155 1224 the server letter with first letter of somestring2
1156 1225
1157 1226 In case function was initialized with both first and lastname, this
1158 1227 overrides the extraction from email by first letter of the first and
1159 1228 last name. We add special logic to that functionality, In case Full name
1160 1229 is compound, like Guido Von Rossum, we use last part of the last name
1161 1230 (Von Rossum) picking `R`.
1162 1231
1163 1232 Function also normalizes the non-ascii characters to they ascii
1164 1233 representation, eg Ą => A
1165 1234 """
1166 1235 import unicodedata
1167 1236 # replace non-ascii to ascii
1168 1237 first_name = unicodedata.normalize(
1169 1238 'NFKD', safe_unicode(self.first_name)).encode('ascii', 'ignore')
1170 1239 last_name = unicodedata.normalize(
1171 1240 'NFKD', safe_unicode(self.last_name)).encode('ascii', 'ignore')
1172 1241
1173 1242 # do NFKD encoding, and also make sure email has proper format
1174 1243 email_address = self.normalize_email(self.email_address)
1175 1244
1176 1245 # first push the email initials
1177 1246 prefix, server = email_address.split('@', 1)
1178 1247
1179 1248 # check if prefix is maybe a 'first_name.last_name' syntax
1180 1249 _dot_split = prefix.rsplit('.', 1)
1181 1250 if len(_dot_split) == 2 and _dot_split[1]:
1182 1251 initials = [_dot_split[0][0], _dot_split[1][0]]
1183 1252 else:
1184 1253 initials = [prefix[0], server[0]]
1185 1254
1186 1255 # then try to replace either first_name or last_name
1187 1256 fn_letter = (first_name or " ")[0].strip()
1188 1257 ln_letter = (last_name.split(' ', 1)[-1] or " ")[0].strip()
1189 1258
1190 1259 if fn_letter:
1191 1260 initials[0] = fn_letter
1192 1261
1193 1262 if ln_letter:
1194 1263 initials[1] = ln_letter
1195 1264
1196 1265 return ''.join(initials).upper()
1197 1266
1198 1267 def get_img_data_by_type(self, font_family, img_type):
1199 1268 default_user = """
1200 1269 <svg xmlns="http://www.w3.org/2000/svg"
1201 1270 version="1.1" x="0px" y="0px" width="{size}" height="{size}"
1202 1271 viewBox="-15 -10 439.165 429.164"
1203 1272
1204 1273 xml:space="preserve"
1205 1274 style="background:{background};" >
1206 1275
1207 1276 <path d="M204.583,216.671c50.664,0,91.74-48.075,
1208 1277 91.74-107.378c0-82.237-41.074-107.377-91.74-107.377
1209 1278 c-50.668,0-91.74,25.14-91.74,107.377C112.844,
1210 1279 168.596,153.916,216.671,
1211 1280 204.583,216.671z" fill="{text_color}"/>
1212 1281 <path d="M407.164,374.717L360.88,
1213 1282 270.454c-2.117-4.771-5.836-8.728-10.465-11.138l-71.83-37.392
1214 1283 c-1.584-0.823-3.502-0.663-4.926,0.415c-20.316,
1215 1284 15.366-44.203,23.488-69.076,23.488c-24.877,
1216 1285 0-48.762-8.122-69.078-23.488
1217 1286 c-1.428-1.078-3.346-1.238-4.93-0.415L58.75,
1218 1287 259.316c-4.631,2.41-8.346,6.365-10.465,11.138L2.001,374.717
1219 1288 c-3.191,7.188-2.537,15.412,1.75,22.005c4.285,
1220 1289 6.592,11.537,10.526,19.4,10.526h362.861c7.863,0,15.117-3.936,
1221 1290 19.402-10.527 C409.699,390.129,
1222 1291 410.355,381.902,407.164,374.717z" fill="{text_color}"/>
1223 1292 </svg>""".format(
1224 1293 size=self.size,
1225 1294 background='#979797', # @grey4
1226 1295 text_color=self.text_color,
1227 1296 font_family=font_family)
1228 1297
1229 1298 return {
1230 1299 "default_user": default_user
1231 1300 }[img_type]
1232 1301
1233 1302 def get_img_data(self, svg_type=None):
1234 1303 """
1235 1304 generates the svg metadata for image
1236 1305 """
1237 1306 fonts = [
1238 1307 '-apple-system',
1239 1308 'BlinkMacSystemFont',
1240 1309 'Segoe UI',
1241 1310 'Roboto',
1242 1311 'Oxygen-Sans',
1243 1312 'Ubuntu',
1244 1313 'Cantarell',
1245 1314 'Helvetica Neue',
1246 1315 'sans-serif'
1247 1316 ]
1248 1317 font_family = ','.join(fonts)
1249 1318 if svg_type:
1250 1319 return self.get_img_data_by_type(font_family, svg_type)
1251 1320
1252 1321 initials = self.get_initials()
1253 1322 img_data = """
1254 1323 <svg xmlns="http://www.w3.org/2000/svg" pointer-events="none"
1255 1324 width="{size}" height="{size}"
1256 1325 style="width: 100%; height: 100%; background-color: {background}"
1257 1326 viewBox="0 0 {size} {size}">
1258 1327 <text text-anchor="middle" y="50%" x="50%" dy="0.35em"
1259 1328 pointer-events="auto" fill="{text_color}"
1260 1329 font-family="{font_family}"
1261 1330 style="font-weight: 400; font-size: {f_size}px;">{text}
1262 1331 </text>
1263 1332 </svg>""".format(
1264 1333 size=self.size,
1265 1334 f_size=self.size/2.05, # scale the text inside the box nicely
1266 1335 background=self.background,
1267 1336 text_color=self.text_color,
1268 1337 text=initials.upper(),
1269 1338 font_family=font_family)
1270 1339
1271 1340 return img_data
1272 1341
1273 1342 def generate_svg(self, svg_type=None):
1274 1343 img_data = self.get_img_data(svg_type)
1275 1344 return "data:image/svg+xml;base64,%s" % img_data.encode('base64')
1276 1345
1277 1346
1278 1347 def initials_gravatar(email_address, first_name, last_name, size=30):
1279 1348 svg_type = None
1280 1349 if email_address == User.DEFAULT_USER_EMAIL:
1281 1350 svg_type = 'default_user'
1282 1351 klass = InitialsGravatar(email_address, first_name, last_name, size)
1283 1352 return klass.generate_svg(svg_type=svg_type)
1284 1353
1285 1354
1286 1355 def gravatar_url(email_address, size=30, request=None):
1287 1356 request = get_current_request()
1288 1357 _use_gravatar = request.call_context.visual.use_gravatar
1289 1358 _gravatar_url = request.call_context.visual.gravatar_url
1290 1359
1291 1360 _gravatar_url = _gravatar_url or User.DEFAULT_GRAVATAR_URL
1292 1361
1293 1362 email_address = email_address or User.DEFAULT_USER_EMAIL
1294 1363 if isinstance(email_address, unicode):
1295 1364 # hashlib crashes on unicode items
1296 1365 email_address = safe_str(email_address)
1297 1366
1298 1367 # empty email or default user
1299 1368 if not email_address or email_address == User.DEFAULT_USER_EMAIL:
1300 1369 return initials_gravatar(User.DEFAULT_USER_EMAIL, '', '', size=size)
1301 1370
1302 1371 if _use_gravatar:
1303 1372 # TODO: Disuse pyramid thread locals. Think about another solution to
1304 1373 # get the host and schema here.
1305 1374 request = get_current_request()
1306 1375 tmpl = safe_str(_gravatar_url)
1307 1376 tmpl = tmpl.replace('{email}', email_address)\
1308 1377 .replace('{md5email}', md5_safe(email_address.lower())) \
1309 1378 .replace('{netloc}', request.host)\
1310 1379 .replace('{scheme}', request.scheme)\
1311 1380 .replace('{size}', safe_str(size))
1312 1381 return tmpl
1313 1382 else:
1314 1383 return initials_gravatar(email_address, '', '', size=size)
1315 1384
1316 1385
1317 1386 def breadcrumb_repo_link(repo):
1318 1387 """
1319 1388 Makes a breadcrumbs path link to repo
1320 1389
1321 1390 ex::
1322 1391 group >> subgroup >> repo
1323 1392
1324 1393 :param repo: a Repository instance
1325 1394 """
1326 1395
1327 1396 path = [
1328 1397 link_to(group.name, route_path('repo_group_home', repo_group_name=group.group_name),
1329 1398 title='last change:{}'.format(format_date(group.last_commit_change)))
1330 1399 for group in repo.groups_with_parents
1331 1400 ] + [
1332 1401 link_to(repo.just_name, route_path('repo_summary', repo_name=repo.repo_name),
1333 1402 title='last change:{}'.format(format_date(repo.last_commit_change)))
1334 1403 ]
1335 1404
1336 1405 return literal(' &raquo; '.join(path))
1337 1406
1338 1407
1339 1408 def breadcrumb_repo_group_link(repo_group):
1340 1409 """
1341 1410 Makes a breadcrumbs path link to repo
1342 1411
1343 1412 ex::
1344 1413 group >> subgroup
1345 1414
1346 1415 :param repo_group: a Repository Group instance
1347 1416 """
1348 1417
1349 1418 path = [
1350 1419 link_to(group.name,
1351 1420 route_path('repo_group_home', repo_group_name=group.group_name),
1352 1421 title='last change:{}'.format(format_date(group.last_commit_change)))
1353 1422 for group in repo_group.parents
1354 1423 ] + [
1355 1424 link_to(repo_group.name,
1356 1425 route_path('repo_group_home', repo_group_name=repo_group.group_name),
1357 1426 title='last change:{}'.format(format_date(repo_group.last_commit_change)))
1358 1427 ]
1359 1428
1360 1429 return literal(' &raquo; '.join(path))
1361 1430
1362 1431
1363 1432 def format_byte_size_binary(file_size):
1364 1433 """
1365 1434 Formats file/folder sizes to standard.
1366 1435 """
1367 1436 if file_size is None:
1368 1437 file_size = 0
1369 1438
1370 1439 formatted_size = format_byte_size(file_size, binary=True)
1371 1440 return formatted_size
1372 1441
1373 1442
1374 1443 def urlify_text(text_, safe=True, **href_attrs):
1375 1444 """
1376 1445 Extract urls from text and make html links out of them
1377 1446 """
1378 1447
1379 1448 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@#.&+]'''
1380 1449 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
1381 1450
1382 1451 def url_func(match_obj):
1383 1452 url_full = match_obj.groups()[0]
1384 1453 a_options = dict(href_attrs)
1385 1454 a_options['href'] = url_full
1386 1455 a_text = url_full
1387 1456 return HTML.tag("a", a_text, **a_options)
1388 1457
1389 1458 _new_text = url_pat.sub(url_func, text_)
1390 1459
1391 1460 if safe:
1392 1461 return literal(_new_text)
1393 1462 return _new_text
1394 1463
1395 1464
1396 1465 def urlify_commits(text_, repo_name):
1397 1466 """
1398 1467 Extract commit ids from text and make link from them
1399 1468
1400 1469 :param text_:
1401 1470 :param repo_name: repo name to build the URL with
1402 1471 """
1403 1472
1404 1473 url_pat = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
1405 1474
1406 1475 def url_func(match_obj):
1407 1476 commit_id = match_obj.groups()[1]
1408 1477 pref = match_obj.groups()[0]
1409 1478 suf = match_obj.groups()[2]
1410 1479
1411 1480 tmpl = (
1412 1481 '%(pref)s<a class="tooltip-hovercard %(cls)s" href="%(url)s" data-hovercard-alt="%(hovercard_alt)s" data-hovercard-url="%(hovercard_url)s">'
1413 1482 '%(commit_id)s</a>%(suf)s'
1414 1483 )
1415 1484 return tmpl % {
1416 1485 'pref': pref,
1417 1486 'cls': 'revision-link',
1418 1487 'url': route_url(
1419 1488 'repo_commit', repo_name=repo_name, commit_id=commit_id),
1420 1489 'commit_id': commit_id,
1421 1490 'suf': suf,
1422 1491 'hovercard_alt': 'Commit: {}'.format(commit_id),
1423 1492 'hovercard_url': route_url(
1424 1493 'hovercard_repo_commit', repo_name=repo_name, commit_id=commit_id)
1425 1494 }
1426 1495
1427 1496 new_text = url_pat.sub(url_func, text_)
1428 1497
1429 1498 return new_text
1430 1499
1431 1500
1432 1501 def _process_url_func(match_obj, repo_name, uid, entry,
1433 1502 return_raw_data=False, link_format='html'):
1434 1503 pref = ''
1435 1504 if match_obj.group().startswith(' '):
1436 1505 pref = ' '
1437 1506
1438 1507 issue_id = ''.join(match_obj.groups())
1439 1508
1440 1509 if link_format == 'html':
1441 1510 tmpl = (
1442 1511 '%(pref)s<a class="tooltip %(cls)s" href="%(url)s" title="%(title)s">'
1443 1512 '%(issue-prefix)s%(id-repr)s'
1444 1513 '</a>')
1445 1514 elif link_format == 'html+hovercard':
1446 1515 tmpl = (
1447 1516 '%(pref)s<a class="tooltip-hovercard %(cls)s" href="%(url)s" data-hovercard-url="%(hovercard_url)s">'
1448 1517 '%(issue-prefix)s%(id-repr)s'
1449 1518 '</a>')
1450 1519 elif link_format in ['rst', 'rst+hovercard']:
1451 1520 tmpl = '`%(issue-prefix)s%(id-repr)s <%(url)s>`_'
1452 1521 elif link_format in ['markdown', 'markdown+hovercard']:
1453 1522 tmpl = '[%(pref)s%(issue-prefix)s%(id-repr)s](%(url)s)'
1454 1523 else:
1455 1524 raise ValueError('Bad link_format:{}'.format(link_format))
1456 1525
1457 1526 (repo_name_cleaned,
1458 1527 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(repo_name)
1459 1528
1460 1529 # variables replacement
1461 1530 named_vars = {
1462 1531 'id': issue_id,
1463 1532 'repo': repo_name,
1464 1533 'repo_name': repo_name_cleaned,
1465 1534 'group_name': parent_group_name,
1466 1535 # set dummy keys so we always have them
1467 1536 'hostname': '',
1468 1537 'netloc': '',
1469 1538 'scheme': ''
1470 1539 }
1471 1540
1472 1541 request = get_current_request()
1473 1542 if request:
1474 1543 # exposes, hostname, netloc, scheme
1475 1544 host_data = get_host_info(request)
1476 1545 named_vars.update(host_data)
1477 1546
1478 1547 # named regex variables
1479 1548 named_vars.update(match_obj.groupdict())
1480 1549 _url = string.Template(entry['url']).safe_substitute(**named_vars)
1481 1550 desc = string.Template(entry['desc']).safe_substitute(**named_vars)
1482 1551 hovercard_url = string.Template(entry.get('hovercard_url', '')).safe_substitute(**named_vars)
1483 1552
1484 1553 def quote_cleaner(input_str):
1485 1554 """Remove quotes as it's HTML"""
1486 1555 return input_str.replace('"', '')
1487 1556
1488 1557 data = {
1489 1558 'pref': pref,
1490 1559 'cls': quote_cleaner('issue-tracker-link'),
1491 1560 'url': quote_cleaner(_url),
1492 1561 'id-repr': issue_id,
1493 1562 'issue-prefix': entry['pref'],
1494 1563 'serv': entry['url'],
1495 'title': desc,
1564 'title': bleach.clean(desc, strip=True),
1496 1565 'hovercard_url': hovercard_url
1497 1566 }
1498 1567
1499 1568 if return_raw_data:
1500 1569 return {
1501 1570 'id': issue_id,
1502 1571 'url': _url
1503 1572 }
1504 1573 return tmpl % data
1505 1574
1506 1575
1507 1576 def get_active_pattern_entries(repo_name):
1508 1577 repo = None
1509 1578 if repo_name:
1510 1579 # Retrieving repo_name to avoid invalid repo_name to explode on
1511 1580 # IssueTrackerSettingsModel but still passing invalid name further down
1512 1581 repo = Repository.get_by_repo_name(repo_name, cache=True)
1513 1582
1514 1583 settings_model = IssueTrackerSettingsModel(repo=repo)
1515 1584 active_entries = settings_model.get_settings(cache=True)
1516 1585 return active_entries
1517 1586
1518 1587
1519 1588 pr_pattern_re = re.compile(r'(?:(?:^!)|(?: !))(\d+)')
1520 1589
1521 1590
1522 1591 def process_patterns(text_string, repo_name, link_format='html', active_entries=None):
1523 1592
1524 1593 allowed_formats = ['html', 'rst', 'markdown',
1525 1594 'html+hovercard', 'rst+hovercard', 'markdown+hovercard']
1526 1595 if link_format not in allowed_formats:
1527 1596 raise ValueError('Link format can be only one of:{} got {}'.format(
1528 1597 allowed_formats, link_format))
1529 1598
1530 1599 if active_entries is None:
1531 1600 log.debug('Fetch active patterns for repo: %s', repo_name)
1532 1601 active_entries = get_active_pattern_entries(repo_name)
1533 1602
1534 1603 issues_data = []
1535 1604 new_text = text_string
1536 1605
1537 1606 log.debug('Got %s entries to process', len(active_entries))
1538 1607 for uid, entry in active_entries.items():
1539 1608 log.debug('found issue tracker entry with uid %s', uid)
1540 1609
1541 1610 if not (entry['pat'] and entry['url']):
1542 1611 log.debug('skipping due to missing data')
1543 1612 continue
1544 1613
1545 1614 log.debug('issue tracker entry: uid: `%s` PAT:%s URL:%s PREFIX:%s',
1546 1615 uid, entry['pat'], entry['url'], entry['pref'])
1547 1616
1548 1617 if entry.get('pat_compiled'):
1549 1618 pattern = entry['pat_compiled']
1550 1619 else:
1551 1620 try:
1552 1621 pattern = re.compile(r'%s' % entry['pat'])
1553 1622 except re.error:
1554 1623 log.exception('issue tracker pattern: `%s` failed to compile', entry['pat'])
1555 1624 continue
1556 1625
1557 1626 data_func = partial(
1558 1627 _process_url_func, repo_name=repo_name, entry=entry, uid=uid,
1559 1628 return_raw_data=True)
1560 1629
1561 1630 for match_obj in pattern.finditer(text_string):
1562 1631 issues_data.append(data_func(match_obj))
1563 1632
1564 1633 url_func = partial(
1565 1634 _process_url_func, repo_name=repo_name, entry=entry, uid=uid,
1566 1635 link_format=link_format)
1567 1636
1568 1637 new_text = pattern.sub(url_func, new_text)
1569 1638 log.debug('processed prefix:uid `%s`', uid)
1570 1639
1571 1640 # finally use global replace, eg !123 -> pr-link, those will not catch
1572 1641 # if already similar pattern exists
1573 1642 server_url = '${scheme}://${netloc}'
1574 1643 pr_entry = {
1575 1644 'pref': '!',
1576 1645 'url': server_url + '/_admin/pull-requests/${id}',
1577 1646 'desc': 'Pull Request !${id}',
1578 1647 'hovercard_url': server_url + '/_hovercard/pull_request/${id}'
1579 1648 }
1580 1649 pr_url_func = partial(
1581 1650 _process_url_func, repo_name=repo_name, entry=pr_entry, uid=None,
1582 1651 link_format=link_format+'+hovercard')
1583 1652 new_text = pr_pattern_re.sub(pr_url_func, new_text)
1584 1653 log.debug('processed !pr pattern')
1585 1654
1586 1655 return new_text, issues_data
1587 1656
1588 1657
1589 1658 def urlify_commit_message(commit_text, repository=None, active_pattern_entries=None):
1590 1659 """
1591 1660 Parses given text message and makes proper links.
1592 1661 issues are linked to given issue-server, and rest is a commit link
1593 1662 """
1594 1663
1595 1664 def escaper(_text):
1596 1665 return _text.replace('<', '&lt;').replace('>', '&gt;')
1597 1666
1598 1667 new_text = escaper(commit_text)
1599 1668
1600 1669 # extract http/https links and make them real urls
1601 1670 new_text = urlify_text(new_text, safe=False)
1602 1671
1603 1672 # urlify commits - extract commit ids and make link out of them, if we have
1604 1673 # the scope of repository present.
1605 1674 if repository:
1606 1675 new_text = urlify_commits(new_text, repository)
1607 1676
1608 1677 # process issue tracker patterns
1609 1678 new_text, issues = process_patterns(new_text, repository or '',
1610 1679 active_entries=active_pattern_entries)
1611 1680
1612 1681 return literal(new_text)
1613 1682
1614 1683
1615 1684 def render_binary(repo_name, file_obj):
1616 1685 """
1617 1686 Choose how to render a binary file
1618 1687 """
1619 1688
1620 1689 # unicode
1621 1690 filename = file_obj.name
1622 1691
1623 1692 # images
1624 1693 for ext in ['*.png', '*.jpeg', '*.jpg', '*.ico', '*.gif']:
1625 1694 if fnmatch.fnmatch(filename, pat=ext):
1626 1695 src = route_path(
1627 1696 'repo_file_raw', repo_name=repo_name,
1628 1697 commit_id=file_obj.commit.raw_id,
1629 1698 f_path=file_obj.path)
1630 1699
1631 1700 return literal(
1632 1701 '<img class="rendered-binary" alt="rendered-image" src="{}">'.format(src))
1633 1702
1634 1703
1635 1704 def renderer_from_filename(filename, exclude=None):
1636 1705 """
1637 1706 choose a renderer based on filename, this works only for text based files
1638 1707 """
1639 1708
1640 1709 # ipython
1641 1710 for ext in ['*.ipynb']:
1642 1711 if fnmatch.fnmatch(filename, pat=ext):
1643 1712 return 'jupyter'
1644 1713
1645 1714 is_markup = MarkupRenderer.renderer_from_filename(filename, exclude=exclude)
1646 1715 if is_markup:
1647 1716 return is_markup
1648 1717 return None
1649 1718
1650 1719
1651 1720 def render(source, renderer='rst', mentions=False, relative_urls=None,
1652 1721 repo_name=None, active_pattern_entries=None):
1653 1722
1654 1723 def maybe_convert_relative_links(html_source):
1655 1724 if relative_urls:
1656 1725 return relative_links(html_source, relative_urls)
1657 1726 return html_source
1658 1727
1659 1728 if renderer == 'plain':
1660 1729 return literal(
1661 1730 MarkupRenderer.plain(source, leading_newline=False))
1662 1731
1663 1732 elif renderer == 'rst':
1664 1733 if repo_name:
1665 1734 # process patterns on comments if we pass in repo name
1666 1735 source, issues = process_patterns(
1667 1736 source, repo_name, link_format='rst',
1668 1737 active_entries=active_pattern_entries)
1669 1738
1670 1739 return literal(
1671 1740 '<div class="rst-block">%s</div>' %
1672 1741 maybe_convert_relative_links(
1673 1742 MarkupRenderer.rst(source, mentions=mentions)))
1674 1743
1675 1744 elif renderer == 'markdown':
1676 1745 if repo_name:
1677 1746 # process patterns on comments if we pass in repo name
1678 1747 source, issues = process_patterns(
1679 1748 source, repo_name, link_format='markdown',
1680 1749 active_entries=active_pattern_entries)
1681 1750
1682 1751 return literal(
1683 1752 '<div class="markdown-block">%s</div>' %
1684 1753 maybe_convert_relative_links(
1685 1754 MarkupRenderer.markdown(source, flavored=True,
1686 1755 mentions=mentions)))
1687 1756
1688 1757 elif renderer == 'jupyter':
1689 1758 return literal(
1690 1759 '<div class="ipynb">%s</div>' %
1691 1760 maybe_convert_relative_links(
1692 1761 MarkupRenderer.jupyter(source)))
1693 1762
1694 1763 # None means just show the file-source
1695 1764 return None
1696 1765
1697 1766
1698 1767 def commit_status(repo, commit_id):
1699 1768 return ChangesetStatusModel().get_status(repo, commit_id)
1700 1769
1701 1770
1702 1771 def commit_status_lbl(commit_status):
1703 1772 return dict(ChangesetStatus.STATUSES).get(commit_status)
1704 1773
1705 1774
1706 1775 def commit_time(repo_name, commit_id):
1707 1776 repo = Repository.get_by_repo_name(repo_name)
1708 1777 commit = repo.get_commit(commit_id=commit_id)
1709 1778 return commit.date
1710 1779
1711 1780
1712 1781 def get_permission_name(key):
1713 1782 return dict(Permission.PERMS).get(key)
1714 1783
1715 1784
1716 1785 def journal_filter_help(request):
1717 1786 _ = request.translate
1718 1787 from rhodecode.lib.audit_logger import ACTIONS
1719 1788 actions = '\n'.join(textwrap.wrap(', '.join(sorted(ACTIONS.keys())), 80))
1720 1789
1721 1790 return _(
1722 1791 'Example filter terms:\n' +
1723 1792 ' repository:vcs\n' +
1724 1793 ' username:marcin\n' +
1725 1794 ' username:(NOT marcin)\n' +
1726 1795 ' action:*push*\n' +
1727 1796 ' ip:127.0.0.1\n' +
1728 1797 ' date:20120101\n' +
1729 1798 ' date:[20120101100000 TO 20120102]\n' +
1730 1799 '\n' +
1731 1800 'Actions: {actions}\n' +
1732 1801 '\n' +
1733 1802 'Generate wildcards using \'*\' character:\n' +
1734 1803 ' "repository:vcs*" - search everything starting with \'vcs\'\n' +
1735 1804 ' "repository:*vcs*" - search for repository containing \'vcs\'\n' +
1736 1805 '\n' +
1737 1806 'Optional AND / OR operators in queries\n' +
1738 1807 ' "repository:vcs OR repository:test"\n' +
1739 1808 ' "username:test AND repository:test*"\n'
1740 1809 ).format(actions=actions)
1741 1810
1742 1811
1743 1812 def not_mapped_error(repo_name):
1744 1813 from rhodecode.translation import _
1745 1814 flash(_('%s repository is not mapped to db perhaps'
1746 1815 ' it was created or renamed from the filesystem'
1747 1816 ' please run the application again'
1748 1817 ' in order to rescan repositories') % repo_name, category='error')
1749 1818
1750 1819
1751 1820 def ip_range(ip_addr):
1752 1821 from rhodecode.model.db import UserIpMap
1753 1822 s, e = UserIpMap._get_ip_range(ip_addr)
1754 1823 return '%s - %s' % (s, e)
1755 1824
1756 1825
1757 1826 def form(url, method='post', needs_csrf_token=True, **attrs):
1758 1827 """Wrapper around webhelpers.tags.form to prevent CSRF attacks."""
1759 1828 if method.lower() != 'get' and needs_csrf_token:
1760 1829 raise Exception(
1761 1830 'Forms to POST/PUT/DELETE endpoints should have (in general) a ' +
1762 1831 'CSRF token. If the endpoint does not require such token you can ' +
1763 1832 'explicitly set the parameter needs_csrf_token to false.')
1764 1833
1765 1834 return insecure_form(url, method=method, **attrs)
1766 1835
1767 1836
1768 1837 def secure_form(form_url, method="POST", multipart=False, **attrs):
1769 1838 """Start a form tag that points the action to an url. This
1770 1839 form tag will also include the hidden field containing
1771 1840 the auth token.
1772 1841
1773 1842 The url options should be given either as a string, or as a
1774 1843 ``url()`` function. The method for the form defaults to POST.
1775 1844
1776 1845 Options:
1777 1846
1778 1847 ``multipart``
1779 1848 If set to True, the enctype is set to "multipart/form-data".
1780 1849 ``method``
1781 1850 The method to use when submitting the form, usually either
1782 1851 "GET" or "POST". If "PUT", "DELETE", or another verb is used, a
1783 1852 hidden input with name _method is added to simulate the verb
1784 1853 over POST.
1785 1854
1786 1855 """
1787 1856
1788 1857 if 'request' in attrs:
1789 1858 session = attrs['request'].session
1790 1859 del attrs['request']
1791 1860 else:
1792 1861 raise ValueError(
1793 1862 'Calling this form requires request= to be passed as argument')
1794 1863
1795 1864 _form = insecure_form(form_url, method, multipart, **attrs)
1796 1865 token = literal(
1797 1866 '<input type="hidden" name="{}" value="{}">'.format(
1798 1867 csrf_token_key, get_csrf_token(session)))
1799 1868
1800 1869 return literal("%s\n%s" % (_form, token))
1801 1870
1802 1871
1803 1872 def dropdownmenu(name, selected, options, enable_filter=False, **attrs):
1804 1873 select_html = select(name, selected, options, **attrs)
1805 1874
1806 1875 select2 = """
1807 1876 <script>
1808 1877 $(document).ready(function() {
1809 1878 $('#%s').select2({
1810 1879 containerCssClass: 'drop-menu %s',
1811 1880 dropdownCssClass: 'drop-menu-dropdown',
1812 1881 dropdownAutoWidth: true%s
1813 1882 });
1814 1883 });
1815 1884 </script>
1816 1885 """
1817 1886
1818 1887 filter_option = """,
1819 1888 minimumResultsForSearch: -1
1820 1889 """
1821 1890 input_id = attrs.get('id') or name
1822 1891 extra_classes = ' '.join(attrs.pop('extra_classes', []))
1823 1892 filter_enabled = "" if enable_filter else filter_option
1824 1893 select_script = literal(select2 % (input_id, extra_classes, filter_enabled))
1825 1894
1826 1895 return literal(select_html+select_script)
1827 1896
1828 1897
1829 1898 def get_visual_attr(tmpl_context_var, attr_name):
1830 1899 """
1831 1900 A safe way to get a variable from visual variable of template context
1832 1901
1833 1902 :param tmpl_context_var: instance of tmpl_context, usually present as `c`
1834 1903 :param attr_name: name of the attribute we fetch from the c.visual
1835 1904 """
1836 1905 visual = getattr(tmpl_context_var, 'visual', None)
1837 1906 if not visual:
1838 1907 return
1839 1908 else:
1840 1909 return getattr(visual, attr_name, None)
1841 1910
1842 1911
1843 1912 def get_last_path_part(file_node):
1844 1913 if not file_node.path:
1845 1914 return u'/'
1846 1915
1847 1916 path = safe_unicode(file_node.path.split('/')[-1])
1848 1917 return u'../' + path
1849 1918
1850 1919
1851 1920 def route_url(*args, **kwargs):
1852 1921 """
1853 1922 Wrapper around pyramids `route_url` (fully qualified url) function.
1854 1923 """
1855 1924 req = get_current_request()
1856 1925 return req.route_url(*args, **kwargs)
1857 1926
1858 1927
1859 1928 def route_path(*args, **kwargs):
1860 1929 """
1861 1930 Wrapper around pyramids `route_path` function.
1862 1931 """
1863 1932 req = get_current_request()
1864 1933 return req.route_path(*args, **kwargs)
1865 1934
1866 1935
1867 1936 def route_path_or_none(*args, **kwargs):
1868 1937 try:
1869 1938 return route_path(*args, **kwargs)
1870 1939 except KeyError:
1871 1940 return None
1872 1941
1873 1942
1874 1943 def current_route_path(request, **kw):
1875 1944 new_args = request.GET.mixed()
1876 1945 new_args.update(kw)
1877 1946 return request.current_route_path(_query=new_args)
1878 1947
1879 1948
1880 1949 def curl_api_example(method, args):
1881 1950 args_json = json.dumps(OrderedDict([
1882 1951 ('id', 1),
1883 1952 ('auth_token', 'SECRET'),
1884 1953 ('method', method),
1885 1954 ('args', args)
1886 1955 ]))
1887 1956
1888 1957 return "curl {api_url} -X POST -H 'content-type:text/plain' --data-binary '{args_json}'".format(
1889 1958 api_url=route_url('apiv2'),
1890 1959 args_json=args_json
1891 1960 )
1892 1961
1893 1962
1894 1963 def api_call_example(method, args):
1895 1964 """
1896 1965 Generates an API call example via CURL
1897 1966 """
1898 1967 curl_call = curl_api_example(method, args)
1899 1968
1900 1969 return literal(
1901 1970 curl_call +
1902 1971 "<br/><br/>SECRET can be found in <a href=\"{token_url}\">auth-tokens</a> page, "
1903 1972 "and needs to be of `api calls` role."
1904 1973 .format(token_url=route_url('my_account_auth_tokens')))
1905 1974
1906 1975
1907 1976 def notification_description(notification, request):
1908 1977 """
1909 1978 Generate notification human readable description based on notification type
1910 1979 """
1911 1980 from rhodecode.model.notification import NotificationModel
1912 1981 return NotificationModel().make_description(
1913 1982 notification, translate=request.translate)
1914 1983
1915 1984
1916 1985 def go_import_header(request, db_repo=None):
1917 1986 """
1918 1987 Creates a header for go-import functionality in Go Lang
1919 1988 """
1920 1989
1921 1990 if not db_repo:
1922 1991 return
1923 1992 if 'go-get' not in request.GET:
1924 1993 return
1925 1994
1926 1995 clone_url = db_repo.clone_url()
1927 1996 prefix = re.split(r'^https?:\/\/', clone_url)[-1]
1928 1997 # we have a repo and go-get flag,
1929 1998 return literal('<meta name="go-import" content="{} {} {}">'.format(
1930 1999 prefix, db_repo.repo_type, clone_url))
1931 2000
1932 2001
1933 2002 def reviewer_as_json(*args, **kwargs):
1934 2003 from rhodecode.apps.repository.utils import reviewer_as_json as _reviewer_as_json
1935 2004 return _reviewer_as_json(*args, **kwargs)
1936 2005
1937 2006
1938 2007 def get_repo_view_type(request):
1939 2008 route_name = request.matched_route.name
1940 2009 route_to_view_type = {
1941 2010 'repo_changelog': 'commits',
1942 2011 'repo_commits': 'commits',
1943 2012 'repo_files': 'files',
1944 2013 'repo_summary': 'summary',
1945 2014 'repo_commit': 'commit'
1946 2015 }
1947 2016
1948 2017 return route_to_view_type.get(route_name)
1949 2018
1950 2019
1951 2020 def is_active(menu_entry, selected):
1952 2021 """
1953 2022 Returns active class for selecting menus in templates
1954 2023 <li class=${h.is_active('settings', current_active)}></li>
1955 2024 """
1956 2025 if not isinstance(menu_entry, list):
1957 2026 menu_entry = [menu_entry]
1958 2027
1959 2028 if selected in menu_entry:
1960 2029 return "active"
@@ -1,189 +1,189 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2014-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 """
22 22 Implementation of the scm_app interface using raw HTTP communication.
23 23 """
24 24
25 25 import base64
26 26 import logging
27 27 import urlparse
28 28 import wsgiref.util
29 29
30 30 import msgpack
31 31 import requests
32 32 import webob.request
33 33
34 34 import rhodecode
35 35
36 36
37 37 log = logging.getLogger(__name__)
38 38
39 39
40 40 def create_git_wsgi_app(repo_path, repo_name, config):
41 41 url = _vcs_streaming_url() + 'git/'
42 42 return VcsHttpProxy(url, repo_path, repo_name, config)
43 43
44 44
45 45 def create_hg_wsgi_app(repo_path, repo_name, config):
46 46 url = _vcs_streaming_url() + 'hg/'
47 47 return VcsHttpProxy(url, repo_path, repo_name, config)
48 48
49 49
50 50 def _vcs_streaming_url():
51 51 template = 'http://{}/stream/'
52 52 return template.format(rhodecode.CONFIG['vcs.server'])
53 53
54 54
55 55 # TODO: johbo: Avoid the global.
56 56 session = requests.Session()
57 57 # Requests speedup, avoid reading .netrc and similar
58 58 session.trust_env = False
59 59
60 60 # prevent urllib3 spawning our logs.
61 61 logging.getLogger("requests.packages.urllib3.connectionpool").setLevel(
62 62 logging.WARNING)
63 63
64 64
65 65 class VcsHttpProxy(object):
66 66 """
67 67 A WSGI application which proxies vcs requests.
68 68
69 69 The goal is to shuffle the data around without touching it. The only
70 70 exception is the extra data from the config object which we send to the
71 71 server as well.
72 72 """
73 73
74 74 def __init__(self, url, repo_path, repo_name, config):
75 75 """
76 76 :param str url: The URL of the VCSServer to call.
77 77 """
78 78 self._url = url
79 79 self._repo_name = repo_name
80 80 self._repo_path = repo_path
81 81 self._config = config
82 82 self.rc_extras = {}
83 83 log.debug(
84 84 "Creating VcsHttpProxy for repo %s, url %s",
85 85 repo_name, url)
86 86
87 87 def __call__(self, environ, start_response):
88 88 config = msgpack.packb(self._config)
89 89 request = webob.request.Request(environ)
90 90 request_headers = request.headers
91 91
92 92 request_headers.update({
93 93 # TODO: johbo: Remove this, rely on URL path only
94 94 'X-RC-Repo-Name': self._repo_name,
95 95 'X-RC-Repo-Path': self._repo_path,
96 96 'X-RC-Path-Info': environ['PATH_INFO'],
97 97
98 98 'X-RC-Repo-Store': self.rc_extras.get('repo_store'),
99 99 'X-RC-Server-Config-File': self.rc_extras.get('config'),
100 100
101 101 'X-RC-Auth-User': self.rc_extras.get('username'),
102 'X-RC-Auth-User-Id': self.rc_extras.get('user_id'),
102 'X-RC-Auth-User-Id': str(self.rc_extras.get('user_id')),
103 103 'X-RC-Auth-User-Ip': self.rc_extras.get('ip'),
104 104
105 105 # TODO: johbo: Avoid encoding and put this into payload?
106 106 'X-RC-Repo-Config': base64.b64encode(config),
107 107 'X-RC-Locked-Status-Code': rhodecode.CONFIG.get('lock_ret_code'),
108 108 })
109 109
110 110 method = environ['REQUEST_METHOD']
111 111
112 112 # Preserve the query string
113 113 url = self._url
114 114 url = urlparse.urljoin(url, self._repo_name)
115 115 if environ.get('QUERY_STRING'):
116 116 url += '?' + environ['QUERY_STRING']
117 117
118 118 log.debug('http-app: preparing request to: %s', url)
119 119 response = session.request(
120 120 method,
121 121 url,
122 122 data=_maybe_stream_request(environ),
123 123 headers=request_headers,
124 124 stream=True)
125 125
126 126 log.debug('http-app: got vcsserver response: %s', response)
127 127 if response.status_code >= 500:
128 128 log.error('Exception returned by vcsserver at: %s %s, %s',
129 129 url, response.status_code, response.content)
130 130
131 131 # Preserve the headers of the response, except hop_by_hop ones
132 132 response_headers = [
133 133 (h, v) for h, v in response.headers.items()
134 134 if not wsgiref.util.is_hop_by_hop(h)
135 135 ]
136 136
137 137 # Build status argument for start_response callable.
138 138 status = '{status_code} {reason_phrase}'.format(
139 139 status_code=response.status_code,
140 140 reason_phrase=response.reason)
141 141
142 142 start_response(status, response_headers)
143 143 return _maybe_stream_response(response)
144 144
145 145
146 146 def read_in_chunks(stream_obj, block_size=1024, chunks=-1):
147 147 """
148 148 Read Stream in chunks, default chunk size: 1k.
149 149 """
150 150 while chunks:
151 151 data = stream_obj.read(block_size)
152 152 if not data:
153 153 break
154 154 yield data
155 155 chunks -= 1
156 156
157 157
158 158 def _is_request_chunked(environ):
159 159 stream = environ.get('HTTP_TRANSFER_ENCODING', '') == 'chunked'
160 160 return stream
161 161
162 162
163 163 def _maybe_stream_request(environ):
164 164 path = environ['PATH_INFO']
165 165 stream = _is_request_chunked(environ)
166 166 log.debug('handling request `%s` with stream support: %s', path, stream)
167 167
168 168 if stream:
169 169 # set stream by 256k
170 170 return read_in_chunks(environ['wsgi.input'], block_size=1024 * 256)
171 171 else:
172 172 return environ['wsgi.input'].read()
173 173
174 174
175 175 def _maybe_stream_response(response):
176 176 """
177 177 Try to generate chunks from the response if it is chunked.
178 178 """
179 179 stream = _is_chunked(response)
180 180 log.debug('returning response with stream: %s', stream)
181 181 if stream:
182 182 # read in 256k Chunks
183 183 return response.raw.read_chunked(amt=1024 * 256)
184 184 else:
185 185 return [response.content]
186 186
187 187
188 188 def _is_chunked(response):
189 189 return response.headers.get('Transfer-Encoding', '') == 'chunked'
@@ -1,81 +1,81 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2015-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 import logging
22 22 from dogpile.cache import register_backend
23 23
24 24 register_backend(
25 25 "dogpile.cache.rc.memory_lru", "rhodecode.lib.rc_cache.backends",
26 26 "LRUMemoryBackend")
27 27
28 28 register_backend(
29 29 "dogpile.cache.rc.file_namespace", "rhodecode.lib.rc_cache.backends",
30 30 "FileNamespaceBackend")
31 31
32 32 register_backend(
33 33 "dogpile.cache.rc.redis", "rhodecode.lib.rc_cache.backends",
34 34 "RedisPickleBackend")
35 35
36 36 register_backend(
37 37 "dogpile.cache.rc.redis_msgpack", "rhodecode.lib.rc_cache.backends",
38 38 "RedisMsgPackBackend")
39 39
40 40
41 41 log = logging.getLogger(__name__)
42 42
43 43 from . import region_meta
44 44 from .utils import (
45 45 get_default_cache_settings, backend_key_generator, get_or_create_region,
46 46 clear_cache_namespace, make_region, InvalidationContext,
47 47 FreshRegionCache, ActiveRegionCache)
48 48
49 49
50 FILE_TREE_CACHE_VER = 'v3'
50 FILE_TREE_CACHE_VER = 'v4'
51 51
52 52
53 53 def configure_dogpile_cache(settings):
54 54 cache_dir = settings.get('cache_dir')
55 55 if cache_dir:
56 56 region_meta.dogpile_config_defaults['cache_dir'] = cache_dir
57 57
58 58 rc_cache_data = get_default_cache_settings(settings, prefixes=['rc_cache.'])
59 59
60 60 # inspect available namespaces
61 61 avail_regions = set()
62 62 for key in rc_cache_data.keys():
63 63 namespace_name = key.split('.', 1)[0]
64 64 avail_regions.add(namespace_name)
65 65 log.debug('dogpile: found following cache regions: %s', avail_regions)
66 66
67 67 # register them into namespace
68 68 for region_name in avail_regions:
69 69 new_region = make_region(
70 70 name=region_name,
71 71 function_key_generator=None
72 72 )
73 73
74 74 new_region.configure_from_config(settings, 'rc_cache.{}.'.format(region_name))
75 75 new_region.function_key_generator = backend_key_generator(new_region.actual_backend)
76 76 log.debug('dogpile: registering a new region %s[%s]', region_name, new_region.__dict__)
77 77 region_meta.dogpile_cache_regions[region_name] = new_region
78 78
79 79
80 80 def includeme(config):
81 81 configure_dogpile_cache(config.registry.settings)
@@ -1,5594 +1,5604 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 """
22 22 Database Models for RhodeCode Enterprise
23 23 """
24 24
25 25 import re
26 26 import os
27 27 import time
28 28 import string
29 29 import hashlib
30 30 import logging
31 31 import datetime
32 32 import uuid
33 33 import warnings
34 34 import ipaddress
35 35 import functools
36 36 import traceback
37 37 import collections
38 38
39 39 from sqlalchemy import (
40 40 or_, and_, not_, func, cast, TypeDecorator, event,
41 41 Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column,
42 42 Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary,
43 43 Text, Float, PickleType, BigInteger)
44 44 from sqlalchemy.sql.expression import true, false, case
45 45 from sqlalchemy.sql.functions import coalesce, count # pragma: no cover
46 46 from sqlalchemy.orm import (
47 47 relationship, joinedload, class_mapper, validates, aliased)
48 48 from sqlalchemy.ext.declarative import declared_attr
49 49 from sqlalchemy.ext.hybrid import hybrid_property
50 50 from sqlalchemy.exc import IntegrityError # pragma: no cover
51 51 from sqlalchemy.dialects.mysql import LONGTEXT
52 52 from zope.cachedescriptors.property import Lazy as LazyProperty
53 53 from pyramid import compat
54 54 from pyramid.threadlocal import get_current_request
55 55 from webhelpers2.text import remove_formatting
56 56
57 57 from rhodecode.translation import _
58 58 from rhodecode.lib.vcs import get_vcs_instance, VCSError
59 59 from rhodecode.lib.vcs.backends.base import EmptyCommit, Reference
60 60 from rhodecode.lib.utils2 import (
61 61 str2bool, safe_str, get_commit_safe, safe_unicode, sha1_safe,
62 62 time_to_datetime, aslist, Optional, safe_int, get_clone_url, AttributeDict,
63 63 glob2re, StrictAttributeDict, cleaned_uri, datetime_to_time, OrderedDefaultDict)
64 64 from rhodecode.lib.jsonalchemy import MutationObj, MutationList, JsonType, \
65 65 JsonRaw
66 66 from rhodecode.lib.ext_json import json
67 67 from rhodecode.lib.caching_query import FromCache
68 68 from rhodecode.lib.encrypt import AESCipher, validate_and_get_enc_data
69 69 from rhodecode.lib.encrypt2 import Encryptor
70 70 from rhodecode.lib.exceptions import (
71 71 ArtifactMetadataDuplicate, ArtifactMetadataBadValueType)
72 72 from rhodecode.model.meta import Base, Session
73 73
74 74 URL_SEP = '/'
75 75 log = logging.getLogger(__name__)
76 76
77 77 # =============================================================================
78 78 # BASE CLASSES
79 79 # =============================================================================
80 80
81 81 # this is propagated from .ini file rhodecode.encrypted_values.secret or
82 82 # beaker.session.secret if first is not set.
83 83 # and initialized at environment.py
84 84 ENCRYPTION_KEY = None
85 85
86 86 # used to sort permissions by types, '#' used here is not allowed to be in
87 87 # usernames, and it's very early in sorted string.printable table.
88 88 PERMISSION_TYPE_SORT = {
89 89 'admin': '####',
90 90 'write': '###',
91 91 'read': '##',
92 92 'none': '#',
93 93 }
94 94
95 95
96 96 def display_user_sort(obj):
97 97 """
98 98 Sort function used to sort permissions in .permissions() function of
99 99 Repository, RepoGroup, UserGroup. Also it put the default user in front
100 100 of all other resources
101 101 """
102 102
103 103 if obj.username == User.DEFAULT_USER:
104 104 return '#####'
105 105 prefix = PERMISSION_TYPE_SORT.get(obj.permission.split('.')[-1], '')
106 106 return prefix + obj.username
107 107
108 108
109 109 def display_user_group_sort(obj):
110 110 """
111 111 Sort function used to sort permissions in .permissions() function of
112 112 Repository, RepoGroup, UserGroup. Also it put the default user in front
113 113 of all other resources
114 114 """
115 115
116 116 prefix = PERMISSION_TYPE_SORT.get(obj.permission.split('.')[-1], '')
117 117 return prefix + obj.users_group_name
118 118
119 119
120 120 def _hash_key(k):
121 121 return sha1_safe(k)
122 122
123 123
124 124 def in_filter_generator(qry, items, limit=500):
125 125 """
126 126 Splits IN() into multiple with OR
127 127 e.g.::
128 128 cnt = Repository.query().filter(
129 129 or_(
130 130 *in_filter_generator(Repository.repo_id, range(100000))
131 131 )).count()
132 132 """
133 133 if not items:
134 134 # empty list will cause empty query which might cause security issues
135 135 # this can lead to hidden unpleasant results
136 136 items = [-1]
137 137
138 138 parts = []
139 139 for chunk in xrange(0, len(items), limit):
140 140 parts.append(
141 141 qry.in_(items[chunk: chunk + limit])
142 142 )
143 143
144 144 return parts
145 145
146 146
147 147 base_table_args = {
148 148 'extend_existing': True,
149 149 'mysql_engine': 'InnoDB',
150 150 'mysql_charset': 'utf8',
151 151 'sqlite_autoincrement': True
152 152 }
153 153
154 154
155 155 class EncryptedTextValue(TypeDecorator):
156 156 """
157 157 Special column for encrypted long text data, use like::
158 158
159 159 value = Column("encrypted_value", EncryptedValue(), nullable=False)
160 160
161 161 This column is intelligent so if value is in unencrypted form it return
162 162 unencrypted form, but on save it always encrypts
163 163 """
164 164 impl = Text
165 165
166 166 def process_bind_param(self, value, dialect):
167 167 """
168 168 Setter for storing value
169 169 """
170 170 import rhodecode
171 171 if not value:
172 172 return value
173 173
174 174 # protect against double encrypting if values is already encrypted
175 175 if value.startswith('enc$aes$') \
176 176 or value.startswith('enc$aes_hmac$') \
177 177 or value.startswith('enc2$'):
178 178 raise ValueError('value needs to be in unencrypted format, '
179 179 'ie. not starting with enc$ or enc2$')
180 180
181 181 algo = rhodecode.CONFIG.get('rhodecode.encrypted_values.algorithm') or 'aes'
182 182 if algo == 'aes':
183 183 return 'enc$aes_hmac$%s' % AESCipher(ENCRYPTION_KEY, hmac=True).encrypt(value)
184 184 elif algo == 'fernet':
185 185 return Encryptor(ENCRYPTION_KEY).encrypt(value)
186 186 else:
187 187 ValueError('Bad encryption algorithm, should be fernet or aes, got: {}'.format(algo))
188 188
189 189 def process_result_value(self, value, dialect):
190 190 """
191 191 Getter for retrieving value
192 192 """
193 193
194 194 import rhodecode
195 195 if not value:
196 196 return value
197 197
198 198 algo = rhodecode.CONFIG.get('rhodecode.encrypted_values.algorithm') or 'aes'
199 199 enc_strict_mode = str2bool(rhodecode.CONFIG.get('rhodecode.encrypted_values.strict') or True)
200 200 if algo == 'aes':
201 201 decrypted_data = validate_and_get_enc_data(value, ENCRYPTION_KEY, enc_strict_mode)
202 202 elif algo == 'fernet':
203 203 return Encryptor(ENCRYPTION_KEY).decrypt(value)
204 204 else:
205 205 ValueError('Bad encryption algorithm, should be fernet or aes, got: {}'.format(algo))
206 206 return decrypted_data
207 207
208 208
209 209 class BaseModel(object):
210 210 """
211 211 Base Model for all classes
212 212 """
213 213
214 214 @classmethod
215 215 def _get_keys(cls):
216 216 """return column names for this model """
217 217 return class_mapper(cls).c.keys()
218 218
219 219 def get_dict(self):
220 220 """
221 221 return dict with keys and values corresponding
222 222 to this model data """
223 223
224 224 d = {}
225 225 for k in self._get_keys():
226 226 d[k] = getattr(self, k)
227 227
228 228 # also use __json__() if present to get additional fields
229 229 _json_attr = getattr(self, '__json__', None)
230 230 if _json_attr:
231 231 # update with attributes from __json__
232 232 if callable(_json_attr):
233 233 _json_attr = _json_attr()
234 234 for k, val in _json_attr.iteritems():
235 235 d[k] = val
236 236 return d
237 237
238 238 def get_appstruct(self):
239 239 """return list with keys and values tuples corresponding
240 240 to this model data """
241 241
242 242 lst = []
243 243 for k in self._get_keys():
244 244 lst.append((k, getattr(self, k),))
245 245 return lst
246 246
247 247 def populate_obj(self, populate_dict):
248 248 """populate model with data from given populate_dict"""
249 249
250 250 for k in self._get_keys():
251 251 if k in populate_dict:
252 252 setattr(self, k, populate_dict[k])
253 253
254 254 @classmethod
255 255 def query(cls):
256 256 return Session().query(cls)
257 257
258 258 @classmethod
259 259 def get(cls, id_):
260 260 if id_:
261 261 return cls.query().get(id_)
262 262
263 263 @classmethod
264 264 def get_or_404(cls, id_):
265 265 from pyramid.httpexceptions import HTTPNotFound
266 266
267 267 try:
268 268 id_ = int(id_)
269 269 except (TypeError, ValueError):
270 270 raise HTTPNotFound()
271 271
272 272 res = cls.query().get(id_)
273 273 if not res:
274 274 raise HTTPNotFound()
275 275 return res
276 276
277 277 @classmethod
278 278 def getAll(cls):
279 279 # deprecated and left for backward compatibility
280 280 return cls.get_all()
281 281
282 282 @classmethod
283 283 def get_all(cls):
284 284 return cls.query().all()
285 285
286 286 @classmethod
287 287 def delete(cls, id_):
288 288 obj = cls.query().get(id_)
289 289 Session().delete(obj)
290 290
291 291 @classmethod
292 292 def identity_cache(cls, session, attr_name, value):
293 293 exist_in_session = []
294 294 for (item_cls, pkey), instance in session.identity_map.items():
295 295 if cls == item_cls and getattr(instance, attr_name) == value:
296 296 exist_in_session.append(instance)
297 297 if exist_in_session:
298 298 if len(exist_in_session) == 1:
299 299 return exist_in_session[0]
300 300 log.exception(
301 301 'multiple objects with attr %s and '
302 302 'value %s found with same name: %r',
303 303 attr_name, value, exist_in_session)
304 304
305 305 def __repr__(self):
306 306 if hasattr(self, '__unicode__'):
307 307 # python repr needs to return str
308 308 try:
309 309 return safe_str(self.__unicode__())
310 310 except UnicodeDecodeError:
311 311 pass
312 312 return '<DB:%s>' % (self.__class__.__name__)
313 313
314 314
315 315 class RhodeCodeSetting(Base, BaseModel):
316 316 __tablename__ = 'rhodecode_settings'
317 317 __table_args__ = (
318 318 UniqueConstraint('app_settings_name'),
319 319 base_table_args
320 320 )
321 321
322 322 SETTINGS_TYPES = {
323 323 'str': safe_str,
324 324 'int': safe_int,
325 325 'unicode': safe_unicode,
326 326 'bool': str2bool,
327 327 'list': functools.partial(aslist, sep=',')
328 328 }
329 329 DEFAULT_UPDATE_URL = 'https://rhodecode.com/api/v1/info/versions'
330 330 GLOBAL_CONF_KEY = 'app_settings'
331 331
332 332 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
333 333 app_settings_name = Column("app_settings_name", String(255), nullable=True, unique=None, default=None)
334 334 _app_settings_value = Column("app_settings_value", String(4096), nullable=True, unique=None, default=None)
335 335 _app_settings_type = Column("app_settings_type", String(255), nullable=True, unique=None, default=None)
336 336
337 337 def __init__(self, key='', val='', type='unicode'):
338 338 self.app_settings_name = key
339 339 self.app_settings_type = type
340 340 self.app_settings_value = val
341 341
342 342 @validates('_app_settings_value')
343 343 def validate_settings_value(self, key, val):
344 344 assert type(val) == unicode
345 345 return val
346 346
347 347 @hybrid_property
348 348 def app_settings_value(self):
349 349 v = self._app_settings_value
350 350 _type = self.app_settings_type
351 351 if _type:
352 352 _type = self.app_settings_type.split('.')[0]
353 353 # decode the encrypted value
354 354 if 'encrypted' in self.app_settings_type:
355 355 cipher = EncryptedTextValue()
356 356 v = safe_unicode(cipher.process_result_value(v, None))
357 357
358 358 converter = self.SETTINGS_TYPES.get(_type) or \
359 359 self.SETTINGS_TYPES['unicode']
360 360 return converter(v)
361 361
362 362 @app_settings_value.setter
363 363 def app_settings_value(self, val):
364 364 """
365 365 Setter that will always make sure we use unicode in app_settings_value
366 366
367 367 :param val:
368 368 """
369 369 val = safe_unicode(val)
370 370 # encode the encrypted value
371 371 if 'encrypted' in self.app_settings_type:
372 372 cipher = EncryptedTextValue()
373 373 val = safe_unicode(cipher.process_bind_param(val, None))
374 374 self._app_settings_value = val
375 375
376 376 @hybrid_property
377 377 def app_settings_type(self):
378 378 return self._app_settings_type
379 379
380 380 @app_settings_type.setter
381 381 def app_settings_type(self, val):
382 382 if val.split('.')[0] not in self.SETTINGS_TYPES:
383 383 raise Exception('type must be one of %s got %s'
384 384 % (self.SETTINGS_TYPES.keys(), val))
385 385 self._app_settings_type = val
386 386
387 387 @classmethod
388 388 def get_by_prefix(cls, prefix):
389 389 return RhodeCodeSetting.query()\
390 390 .filter(RhodeCodeSetting.app_settings_name.startswith(prefix))\
391 391 .all()
392 392
393 393 def __unicode__(self):
394 394 return u"<%s('%s:%s[%s]')>" % (
395 395 self.__class__.__name__,
396 396 self.app_settings_name, self.app_settings_value,
397 397 self.app_settings_type
398 398 )
399 399
400 400
401 401 class RhodeCodeUi(Base, BaseModel):
402 402 __tablename__ = 'rhodecode_ui'
403 403 __table_args__ = (
404 404 UniqueConstraint('ui_key'),
405 405 base_table_args
406 406 )
407 407
408 408 HOOK_REPO_SIZE = 'changegroup.repo_size'
409 409 # HG
410 410 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
411 411 HOOK_PULL = 'outgoing.pull_logger'
412 412 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
413 413 HOOK_PRETX_PUSH = 'pretxnchangegroup.pre_push'
414 414 HOOK_PUSH = 'changegroup.push_logger'
415 415 HOOK_PUSH_KEY = 'pushkey.key_push'
416 416
417 417 HOOKS_BUILTIN = [
418 418 HOOK_PRE_PULL,
419 419 HOOK_PULL,
420 420 HOOK_PRE_PUSH,
421 421 HOOK_PRETX_PUSH,
422 422 HOOK_PUSH,
423 423 HOOK_PUSH_KEY,
424 424 ]
425 425
426 426 # TODO: johbo: Unify way how hooks are configured for git and hg,
427 427 # git part is currently hardcoded.
428 428
429 429 # SVN PATTERNS
430 430 SVN_BRANCH_ID = 'vcs_svn_branch'
431 431 SVN_TAG_ID = 'vcs_svn_tag'
432 432
433 433 ui_id = Column(
434 434 "ui_id", Integer(), nullable=False, unique=True, default=None,
435 435 primary_key=True)
436 436 ui_section = Column(
437 437 "ui_section", String(255), nullable=True, unique=None, default=None)
438 438 ui_key = Column(
439 439 "ui_key", String(255), nullable=True, unique=None, default=None)
440 440 ui_value = Column(
441 441 "ui_value", String(255), nullable=True, unique=None, default=None)
442 442 ui_active = Column(
443 443 "ui_active", Boolean(), nullable=True, unique=None, default=True)
444 444
445 445 def __repr__(self):
446 446 return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.ui_section,
447 447 self.ui_key, self.ui_value)
448 448
449 449
450 450 class RepoRhodeCodeSetting(Base, BaseModel):
451 451 __tablename__ = 'repo_rhodecode_settings'
452 452 __table_args__ = (
453 453 UniqueConstraint(
454 454 'app_settings_name', 'repository_id',
455 455 name='uq_repo_rhodecode_setting_name_repo_id'),
456 456 base_table_args
457 457 )
458 458
459 459 repository_id = Column(
460 460 "repository_id", Integer(), ForeignKey('repositories.repo_id'),
461 461 nullable=False)
462 462 app_settings_id = Column(
463 463 "app_settings_id", Integer(), nullable=False, unique=True,
464 464 default=None, primary_key=True)
465 465 app_settings_name = Column(
466 466 "app_settings_name", String(255), nullable=True, unique=None,
467 467 default=None)
468 468 _app_settings_value = Column(
469 469 "app_settings_value", String(4096), nullable=True, unique=None,
470 470 default=None)
471 471 _app_settings_type = Column(
472 472 "app_settings_type", String(255), nullable=True, unique=None,
473 473 default=None)
474 474
475 475 repository = relationship('Repository')
476 476
477 477 def __init__(self, repository_id, key='', val='', type='unicode'):
478 478 self.repository_id = repository_id
479 479 self.app_settings_name = key
480 480 self.app_settings_type = type
481 481 self.app_settings_value = val
482 482
483 483 @validates('_app_settings_value')
484 484 def validate_settings_value(self, key, val):
485 485 assert type(val) == unicode
486 486 return val
487 487
488 488 @hybrid_property
489 489 def app_settings_value(self):
490 490 v = self._app_settings_value
491 491 type_ = self.app_settings_type
492 492 SETTINGS_TYPES = RhodeCodeSetting.SETTINGS_TYPES
493 493 converter = SETTINGS_TYPES.get(type_) or SETTINGS_TYPES['unicode']
494 494 return converter(v)
495 495
496 496 @app_settings_value.setter
497 497 def app_settings_value(self, val):
498 498 """
499 499 Setter that will always make sure we use unicode in app_settings_value
500 500
501 501 :param val:
502 502 """
503 503 self._app_settings_value = safe_unicode(val)
504 504
505 505 @hybrid_property
506 506 def app_settings_type(self):
507 507 return self._app_settings_type
508 508
509 509 @app_settings_type.setter
510 510 def app_settings_type(self, val):
511 511 SETTINGS_TYPES = RhodeCodeSetting.SETTINGS_TYPES
512 512 if val not in SETTINGS_TYPES:
513 513 raise Exception('type must be one of %s got %s'
514 514 % (SETTINGS_TYPES.keys(), val))
515 515 self._app_settings_type = val
516 516
517 517 def __unicode__(self):
518 518 return u"<%s('%s:%s:%s[%s]')>" % (
519 519 self.__class__.__name__, self.repository.repo_name,
520 520 self.app_settings_name, self.app_settings_value,
521 521 self.app_settings_type
522 522 )
523 523
524 524
525 525 class RepoRhodeCodeUi(Base, BaseModel):
526 526 __tablename__ = 'repo_rhodecode_ui'
527 527 __table_args__ = (
528 528 UniqueConstraint(
529 529 'repository_id', 'ui_section', 'ui_key',
530 530 name='uq_repo_rhodecode_ui_repository_id_section_key'),
531 531 base_table_args
532 532 )
533 533
534 534 repository_id = Column(
535 535 "repository_id", Integer(), ForeignKey('repositories.repo_id'),
536 536 nullable=False)
537 537 ui_id = Column(
538 538 "ui_id", Integer(), nullable=False, unique=True, default=None,
539 539 primary_key=True)
540 540 ui_section = Column(
541 541 "ui_section", String(255), nullable=True, unique=None, default=None)
542 542 ui_key = Column(
543 543 "ui_key", String(255), nullable=True, unique=None, default=None)
544 544 ui_value = Column(
545 545 "ui_value", String(255), nullable=True, unique=None, default=None)
546 546 ui_active = Column(
547 547 "ui_active", Boolean(), nullable=True, unique=None, default=True)
548 548
549 549 repository = relationship('Repository')
550 550
551 551 def __repr__(self):
552 552 return '<%s[%s:%s]%s=>%s]>' % (
553 553 self.__class__.__name__, self.repository.repo_name,
554 554 self.ui_section, self.ui_key, self.ui_value)
555 555
556 556
557 557 class User(Base, BaseModel):
558 558 __tablename__ = 'users'
559 559 __table_args__ = (
560 560 UniqueConstraint('username'), UniqueConstraint('email'),
561 561 Index('u_username_idx', 'username'),
562 562 Index('u_email_idx', 'email'),
563 563 base_table_args
564 564 )
565 565
566 566 DEFAULT_USER = 'default'
567 567 DEFAULT_USER_EMAIL = 'anonymous@rhodecode.org'
568 568 DEFAULT_GRAVATAR_URL = 'https://secure.gravatar.com/avatar/{md5email}?d=identicon&s={size}'
569 569
570 570 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
571 571 username = Column("username", String(255), nullable=True, unique=None, default=None)
572 572 password = Column("password", String(255), nullable=True, unique=None, default=None)
573 573 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
574 574 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
575 575 name = Column("firstname", String(255), nullable=True, unique=None, default=None)
576 576 lastname = Column("lastname", String(255), nullable=True, unique=None, default=None)
577 577 _email = Column("email", String(255), nullable=True, unique=None, default=None)
578 578 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
579 579 last_activity = Column('last_activity', DateTime(timezone=False), nullable=True, unique=None, default=None)
580 580 description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
581 581
582 582 extern_type = Column("extern_type", String(255), nullable=True, unique=None, default=None)
583 583 extern_name = Column("extern_name", String(255), nullable=True, unique=None, default=None)
584 584 _api_key = Column("api_key", String(255), nullable=True, unique=None, default=None)
585 585 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
586 586 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
587 587 _user_data = Column("user_data", LargeBinary(), nullable=True) # JSON data
588 588
589 589 user_log = relationship('UserLog')
590 590 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all, delete-orphan')
591 591
592 592 repositories = relationship('Repository')
593 593 repository_groups = relationship('RepoGroup')
594 594 user_groups = relationship('UserGroup')
595 595
596 596 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
597 597 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
598 598
599 599 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all, delete-orphan')
600 600 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all, delete-orphan')
601 601 user_group_to_perm = relationship('UserUserGroupToPerm', primaryjoin='UserUserGroupToPerm.user_id==User.user_id', cascade='all, delete-orphan')
602 602
603 603 group_member = relationship('UserGroupMember', cascade='all')
604 604
605 605 notifications = relationship('UserNotification', cascade='all')
606 606 # notifications assigned to this user
607 607 user_created_notifications = relationship('Notification', cascade='all')
608 608 # comments created by this user
609 609 user_comments = relationship('ChangesetComment', cascade='all')
610 610 # user profile extra info
611 611 user_emails = relationship('UserEmailMap', cascade='all')
612 612 user_ip_map = relationship('UserIpMap', cascade='all')
613 613 user_auth_tokens = relationship('UserApiKeys', cascade='all')
614 614 user_ssh_keys = relationship('UserSshKeys', cascade='all')
615 615
616 616 # gists
617 617 user_gists = relationship('Gist', cascade='all')
618 618 # user pull requests
619 619 user_pull_requests = relationship('PullRequest', cascade='all')
620 620
621 621 # external identities
622 622 external_identities = relationship(
623 623 'ExternalIdentity',
624 624 primaryjoin="User.user_id==ExternalIdentity.local_user_id",
625 625 cascade='all')
626 626 # review rules
627 627 user_review_rules = relationship('RepoReviewRuleUser', cascade='all')
628 628
629 629 # artifacts owned
630 630 artifacts = relationship('FileStore', primaryjoin='FileStore.user_id==User.user_id')
631 631
632 632 # no cascade, set NULL
633 633 scope_artifacts = relationship('FileStore', primaryjoin='FileStore.scope_user_id==User.user_id')
634 634
635 635 def __unicode__(self):
636 636 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
637 637 self.user_id, self.username)
638 638
639 639 @hybrid_property
640 640 def email(self):
641 641 return self._email
642 642
643 643 @email.setter
644 644 def email(self, val):
645 645 self._email = val.lower() if val else None
646 646
647 647 @hybrid_property
648 648 def first_name(self):
649 649 from rhodecode.lib import helpers as h
650 650 if self.name:
651 651 return h.escape(self.name)
652 652 return self.name
653 653
654 654 @hybrid_property
655 655 def last_name(self):
656 656 from rhodecode.lib import helpers as h
657 657 if self.lastname:
658 658 return h.escape(self.lastname)
659 659 return self.lastname
660 660
661 661 @hybrid_property
662 662 def api_key(self):
663 663 """
664 664 Fetch if exist an auth-token with role ALL connected to this user
665 665 """
666 666 user_auth_token = UserApiKeys.query()\
667 667 .filter(UserApiKeys.user_id == self.user_id)\
668 668 .filter(or_(UserApiKeys.expires == -1,
669 669 UserApiKeys.expires >= time.time()))\
670 670 .filter(UserApiKeys.role == UserApiKeys.ROLE_ALL).first()
671 671 if user_auth_token:
672 672 user_auth_token = user_auth_token.api_key
673 673
674 674 return user_auth_token
675 675
676 676 @api_key.setter
677 677 def api_key(self, val):
678 678 # don't allow to set API key this is deprecated for now
679 679 self._api_key = None
680 680
681 681 @property
682 682 def reviewer_pull_requests(self):
683 683 return PullRequestReviewers.query() \
684 684 .options(joinedload(PullRequestReviewers.pull_request)) \
685 685 .filter(PullRequestReviewers.user_id == self.user_id) \
686 686 .all()
687 687
688 688 @property
689 689 def firstname(self):
690 690 # alias for future
691 691 return self.name
692 692
693 693 @property
694 694 def emails(self):
695 695 other = UserEmailMap.query()\
696 696 .filter(UserEmailMap.user == self) \
697 697 .order_by(UserEmailMap.email_id.asc()) \
698 698 .all()
699 699 return [self.email] + [x.email for x in other]
700 700
701 701 def emails_cached(self):
702 702 emails = UserEmailMap.query()\
703 703 .filter(UserEmailMap.user == self) \
704 704 .order_by(UserEmailMap.email_id.asc())
705 705
706 706 emails = emails.options(
707 707 FromCache("sql_cache_short", "get_user_{}_emails".format(self.user_id))
708 708 )
709 709
710 710 return [self.email] + [x.email for x in emails]
711 711
712 712 @property
713 713 def auth_tokens(self):
714 714 auth_tokens = self.get_auth_tokens()
715 715 return [x.api_key for x in auth_tokens]
716 716
717 717 def get_auth_tokens(self):
718 718 return UserApiKeys.query()\
719 719 .filter(UserApiKeys.user == self)\
720 720 .order_by(UserApiKeys.user_api_key_id.asc())\
721 721 .all()
722 722
723 723 @LazyProperty
724 724 def feed_token(self):
725 725 return self.get_feed_token()
726 726
727 727 def get_feed_token(self, cache=True):
728 728 feed_tokens = UserApiKeys.query()\
729 729 .filter(UserApiKeys.user == self)\
730 730 .filter(UserApiKeys.role == UserApiKeys.ROLE_FEED)
731 731 if cache:
732 732 feed_tokens = feed_tokens.options(
733 733 FromCache("sql_cache_short", "get_user_feed_token_%s" % self.user_id))
734 734
735 735 feed_tokens = feed_tokens.all()
736 736 if feed_tokens:
737 737 return feed_tokens[0].api_key
738 738 return 'NO_FEED_TOKEN_AVAILABLE'
739 739
740 740 @LazyProperty
741 741 def artifact_token(self):
742 742 return self.get_artifact_token()
743 743
744 744 def get_artifact_token(self, cache=True):
745 745 artifacts_tokens = UserApiKeys.query()\
746 746 .filter(UserApiKeys.user == self)\
747 747 .filter(UserApiKeys.role == UserApiKeys.ROLE_ARTIFACT_DOWNLOAD)
748 748 if cache:
749 749 artifacts_tokens = artifacts_tokens.options(
750 750 FromCache("sql_cache_short", "get_user_artifact_token_%s" % self.user_id))
751 751
752 752 artifacts_tokens = artifacts_tokens.all()
753 753 if artifacts_tokens:
754 754 return artifacts_tokens[0].api_key
755 755 return 'NO_ARTIFACT_TOKEN_AVAILABLE'
756 756
757 757 @classmethod
758 758 def get(cls, user_id, cache=False):
759 759 if not user_id:
760 760 return
761 761
762 762 user = cls.query()
763 763 if cache:
764 764 user = user.options(
765 765 FromCache("sql_cache_short", "get_users_%s" % user_id))
766 766 return user.get(user_id)
767 767
768 768 @classmethod
769 769 def extra_valid_auth_tokens(cls, user, role=None):
770 770 tokens = UserApiKeys.query().filter(UserApiKeys.user == user)\
771 771 .filter(or_(UserApiKeys.expires == -1,
772 772 UserApiKeys.expires >= time.time()))
773 773 if role:
774 774 tokens = tokens.filter(or_(UserApiKeys.role == role,
775 775 UserApiKeys.role == UserApiKeys.ROLE_ALL))
776 776 return tokens.all()
777 777
778 778 def authenticate_by_token(self, auth_token, roles=None, scope_repo_id=None):
779 779 from rhodecode.lib import auth
780 780
781 781 log.debug('Trying to authenticate user: %s via auth-token, '
782 782 'and roles: %s', self, roles)
783 783
784 784 if not auth_token:
785 785 return False
786 786
787 787 roles = (roles or []) + [UserApiKeys.ROLE_ALL]
788 788 tokens_q = UserApiKeys.query()\
789 789 .filter(UserApiKeys.user_id == self.user_id)\
790 790 .filter(or_(UserApiKeys.expires == -1,
791 791 UserApiKeys.expires >= time.time()))
792 792
793 793 tokens_q = tokens_q.filter(UserApiKeys.role.in_(roles))
794 794
795 795 crypto_backend = auth.crypto_backend()
796 796 enc_token_map = {}
797 797 plain_token_map = {}
798 798 for token in tokens_q:
799 799 if token.api_key.startswith(crypto_backend.ENC_PREF):
800 800 enc_token_map[token.api_key] = token
801 801 else:
802 802 plain_token_map[token.api_key] = token
803 803 log.debug(
804 804 'Found %s plain and %s encrypted tokens to check for authentication for this user',
805 805 len(plain_token_map), len(enc_token_map))
806 806
807 807 # plain token match comes first
808 808 match = plain_token_map.get(auth_token)
809 809
810 810 # check encrypted tokens now
811 811 if not match:
812 812 for token_hash, token in enc_token_map.items():
813 813 # NOTE(marcink): this is expensive to calculate, but most secure
814 814 if crypto_backend.hash_check(auth_token, token_hash):
815 815 match = token
816 816 break
817 817
818 818 if match:
819 819 log.debug('Found matching token %s', match)
820 820 if match.repo_id:
821 821 log.debug('Found scope, checking for scope match of token %s', match)
822 822 if match.repo_id == scope_repo_id:
823 823 return True
824 824 else:
825 825 log.debug(
826 826 'AUTH_TOKEN: scope mismatch, token has a set repo scope: %s, '
827 827 'and calling scope is:%s, skipping further checks',
828 828 match.repo, scope_repo_id)
829 829 return False
830 830 else:
831 831 return True
832 832
833 833 return False
834 834
835 835 @property
836 836 def ip_addresses(self):
837 837 ret = UserIpMap.query().filter(UserIpMap.user == self).all()
838 838 return [x.ip_addr for x in ret]
839 839
840 840 @property
841 841 def username_and_name(self):
842 842 return '%s (%s %s)' % (self.username, self.first_name, self.last_name)
843 843
844 844 @property
845 845 def username_or_name_or_email(self):
846 846 full_name = self.full_name if self.full_name is not ' ' else None
847 847 return self.username or full_name or self.email
848 848
849 849 @property
850 850 def full_name(self):
851 851 return '%s %s' % (self.first_name, self.last_name)
852 852
853 853 @property
854 854 def full_name_or_username(self):
855 855 return ('%s %s' % (self.first_name, self.last_name)
856 856 if (self.first_name and self.last_name) else self.username)
857 857
858 858 @property
859 859 def full_contact(self):
860 860 return '%s %s <%s>' % (self.first_name, self.last_name, self.email)
861 861
862 862 @property
863 863 def short_contact(self):
864 864 return '%s %s' % (self.first_name, self.last_name)
865 865
866 866 @property
867 867 def is_admin(self):
868 868 return self.admin
869 869
870 870 @property
871 871 def language(self):
872 872 return self.user_data.get('language')
873 873
874 874 def AuthUser(self, **kwargs):
875 875 """
876 876 Returns instance of AuthUser for this user
877 877 """
878 878 from rhodecode.lib.auth import AuthUser
879 879 return AuthUser(user_id=self.user_id, username=self.username, **kwargs)
880 880
881 881 @hybrid_property
882 882 def user_data(self):
883 883 if not self._user_data:
884 884 return {}
885 885
886 886 try:
887 887 return json.loads(self._user_data)
888 888 except TypeError:
889 889 return {}
890 890
891 891 @user_data.setter
892 892 def user_data(self, val):
893 893 if not isinstance(val, dict):
894 894 raise Exception('user_data must be dict, got %s' % type(val))
895 895 try:
896 896 self._user_data = json.dumps(val)
897 897 except Exception:
898 898 log.error(traceback.format_exc())
899 899
900 900 @classmethod
901 901 def get_by_username(cls, username, case_insensitive=False,
902 902 cache=False, identity_cache=False):
903 903 session = Session()
904 904
905 905 if case_insensitive:
906 906 q = cls.query().filter(
907 907 func.lower(cls.username) == func.lower(username))
908 908 else:
909 909 q = cls.query().filter(cls.username == username)
910 910
911 911 if cache:
912 912 if identity_cache:
913 913 val = cls.identity_cache(session, 'username', username)
914 914 if val:
915 915 return val
916 916 else:
917 917 cache_key = "get_user_by_name_%s" % _hash_key(username)
918 918 q = q.options(
919 919 FromCache("sql_cache_short", cache_key))
920 920
921 921 return q.scalar()
922 922
923 923 @classmethod
924 924 def get_by_auth_token(cls, auth_token, cache=False):
925 925 q = UserApiKeys.query()\
926 926 .filter(UserApiKeys.api_key == auth_token)\
927 927 .filter(or_(UserApiKeys.expires == -1,
928 928 UserApiKeys.expires >= time.time()))
929 929 if cache:
930 930 q = q.options(
931 931 FromCache("sql_cache_short", "get_auth_token_%s" % auth_token))
932 932
933 933 match = q.first()
934 934 if match:
935 935 return match.user
936 936
937 937 @classmethod
938 938 def get_by_email(cls, email, case_insensitive=False, cache=False):
939 939
940 940 if case_insensitive:
941 941 q = cls.query().filter(func.lower(cls.email) == func.lower(email))
942 942
943 943 else:
944 944 q = cls.query().filter(cls.email == email)
945 945
946 946 email_key = _hash_key(email)
947 947 if cache:
948 948 q = q.options(
949 949 FromCache("sql_cache_short", "get_email_key_%s" % email_key))
950 950
951 951 ret = q.scalar()
952 952 if ret is None:
953 953 q = UserEmailMap.query()
954 954 # try fetching in alternate email map
955 955 if case_insensitive:
956 956 q = q.filter(func.lower(UserEmailMap.email) == func.lower(email))
957 957 else:
958 958 q = q.filter(UserEmailMap.email == email)
959 959 q = q.options(joinedload(UserEmailMap.user))
960 960 if cache:
961 961 q = q.options(
962 962 FromCache("sql_cache_short", "get_email_map_key_%s" % email_key))
963 963 ret = getattr(q.scalar(), 'user', None)
964 964
965 965 return ret
966 966
967 967 @classmethod
968 968 def get_from_cs_author(cls, author):
969 969 """
970 970 Tries to get User objects out of commit author string
971 971
972 972 :param author:
973 973 """
974 974 from rhodecode.lib.helpers import email, author_name
975 975 # Valid email in the attribute passed, see if they're in the system
976 976 _email = email(author)
977 977 if _email:
978 978 user = cls.get_by_email(_email, case_insensitive=True)
979 979 if user:
980 980 return user
981 981 # Maybe we can match by username?
982 982 _author = author_name(author)
983 983 user = cls.get_by_username(_author, case_insensitive=True)
984 984 if user:
985 985 return user
986 986
987 987 def update_userdata(self, **kwargs):
988 988 usr = self
989 989 old = usr.user_data
990 990 old.update(**kwargs)
991 991 usr.user_data = old
992 992 Session().add(usr)
993 993 log.debug('updated userdata with %s', kwargs)
994 994
995 995 def update_lastlogin(self):
996 996 """Update user lastlogin"""
997 997 self.last_login = datetime.datetime.now()
998 998 Session().add(self)
999 999 log.debug('updated user %s lastlogin', self.username)
1000 1000
1001 1001 def update_password(self, new_password):
1002 1002 from rhodecode.lib.auth import get_crypt_password
1003 1003
1004 1004 self.password = get_crypt_password(new_password)
1005 1005 Session().add(self)
1006 1006
1007 1007 @classmethod
1008 1008 def get_first_super_admin(cls):
1009 1009 user = User.query()\
1010 1010 .filter(User.admin == true()) \
1011 1011 .order_by(User.user_id.asc()) \
1012 1012 .first()
1013 1013
1014 1014 if user is None:
1015 1015 raise Exception('FATAL: Missing administrative account!')
1016 1016 return user
1017 1017
1018 1018 @classmethod
1019 1019 def get_all_super_admins(cls, only_active=False):
1020 1020 """
1021 1021 Returns all admin accounts sorted by username
1022 1022 """
1023 1023 qry = User.query().filter(User.admin == true()).order_by(User.username.asc())
1024 1024 if only_active:
1025 1025 qry = qry.filter(User.active == true())
1026 1026 return qry.all()
1027 1027
1028 1028 @classmethod
1029 1029 def get_all_user_ids(cls, only_active=True):
1030 1030 """
1031 1031 Returns all users IDs
1032 1032 """
1033 1033 qry = Session().query(User.user_id)
1034 1034
1035 1035 if only_active:
1036 1036 qry = qry.filter(User.active == true())
1037 1037 return [x.user_id for x in qry]
1038 1038
1039 1039 @classmethod
1040 1040 def get_default_user(cls, cache=False, refresh=False):
1041 1041 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
1042 1042 if user is None:
1043 1043 raise Exception('FATAL: Missing default account!')
1044 1044 if refresh:
1045 1045 # The default user might be based on outdated state which
1046 1046 # has been loaded from the cache.
1047 1047 # A call to refresh() ensures that the
1048 1048 # latest state from the database is used.
1049 1049 Session().refresh(user)
1050 1050 return user
1051 1051
1052 1052 @classmethod
1053 1053 def get_default_user_id(cls):
1054 1054 import rhodecode
1055 1055 return rhodecode.CONFIG['default_user_id']
1056 1056
1057 1057 def _get_default_perms(self, user, suffix=''):
1058 1058 from rhodecode.model.permission import PermissionModel
1059 1059 return PermissionModel().get_default_perms(user.user_perms, suffix)
1060 1060
1061 1061 def get_default_perms(self, suffix=''):
1062 1062 return self._get_default_perms(self, suffix)
1063 1063
1064 1064 def get_api_data(self, include_secrets=False, details='full'):
1065 1065 """
1066 1066 Common function for generating user related data for API
1067 1067
1068 1068 :param include_secrets: By default secrets in the API data will be replaced
1069 1069 by a placeholder value to prevent exposing this data by accident. In case
1070 1070 this data shall be exposed, set this flag to ``True``.
1071 1071
1072 1072 :param details: details can be 'basic|full' basic gives only a subset of
1073 1073 the available user information that includes user_id, name and emails.
1074 1074 """
1075 1075 user = self
1076 1076 user_data = self.user_data
1077 1077 data = {
1078 1078 'user_id': user.user_id,
1079 1079 'username': user.username,
1080 1080 'firstname': user.name,
1081 1081 'lastname': user.lastname,
1082 1082 'description': user.description,
1083 1083 'email': user.email,
1084 1084 'emails': user.emails,
1085 1085 }
1086 1086 if details == 'basic':
1087 1087 return data
1088 1088
1089 1089 auth_token_length = 40
1090 1090 auth_token_replacement = '*' * auth_token_length
1091 1091
1092 1092 extras = {
1093 1093 'auth_tokens': [auth_token_replacement],
1094 1094 'active': user.active,
1095 1095 'admin': user.admin,
1096 1096 'extern_type': user.extern_type,
1097 1097 'extern_name': user.extern_name,
1098 1098 'last_login': user.last_login,
1099 1099 'last_activity': user.last_activity,
1100 1100 'ip_addresses': user.ip_addresses,
1101 1101 'language': user_data.get('language')
1102 1102 }
1103 1103 data.update(extras)
1104 1104
1105 1105 if include_secrets:
1106 1106 data['auth_tokens'] = user.auth_tokens
1107 1107 return data
1108 1108
1109 1109 def __json__(self):
1110 1110 data = {
1111 1111 'full_name': self.full_name,
1112 1112 'full_name_or_username': self.full_name_or_username,
1113 1113 'short_contact': self.short_contact,
1114 1114 'full_contact': self.full_contact,
1115 1115 }
1116 1116 data.update(self.get_api_data())
1117 1117 return data
1118 1118
1119 1119
1120 1120 class UserApiKeys(Base, BaseModel):
1121 1121 __tablename__ = 'user_api_keys'
1122 1122 __table_args__ = (
1123 1123 Index('uak_api_key_idx', 'api_key'),
1124 1124 Index('uak_api_key_expires_idx', 'api_key', 'expires'),
1125 1125 base_table_args
1126 1126 )
1127 1127 __mapper_args__ = {}
1128 1128
1129 1129 # ApiKey role
1130 1130 ROLE_ALL = 'token_role_all'
1131 1131 ROLE_HTTP = 'token_role_http'
1132 1132 ROLE_VCS = 'token_role_vcs'
1133 1133 ROLE_API = 'token_role_api'
1134 1134 ROLE_FEED = 'token_role_feed'
1135 1135 ROLE_ARTIFACT_DOWNLOAD = 'role_artifact_download'
1136 1136 ROLE_PASSWORD_RESET = 'token_password_reset'
1137 1137
1138 1138 ROLES = [ROLE_ALL, ROLE_HTTP, ROLE_VCS, ROLE_API, ROLE_FEED, ROLE_ARTIFACT_DOWNLOAD]
1139 1139
1140 1140 user_api_key_id = Column("user_api_key_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1141 1141 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1142 1142 api_key = Column("api_key", String(255), nullable=False, unique=True)
1143 1143 description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1144 1144 expires = Column('expires', Float(53), nullable=False)
1145 1145 role = Column('role', String(255), nullable=True)
1146 1146 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1147 1147
1148 1148 # scope columns
1149 1149 repo_id = Column(
1150 1150 'repo_id', Integer(), ForeignKey('repositories.repo_id'),
1151 1151 nullable=True, unique=None, default=None)
1152 1152 repo = relationship('Repository', lazy='joined')
1153 1153
1154 1154 repo_group_id = Column(
1155 1155 'repo_group_id', Integer(), ForeignKey('groups.group_id'),
1156 1156 nullable=True, unique=None, default=None)
1157 1157 repo_group = relationship('RepoGroup', lazy='joined')
1158 1158
1159 1159 user = relationship('User', lazy='joined')
1160 1160
1161 1161 def __unicode__(self):
1162 1162 return u"<%s('%s')>" % (self.__class__.__name__, self.role)
1163 1163
1164 1164 def __json__(self):
1165 1165 data = {
1166 1166 'auth_token': self.api_key,
1167 1167 'role': self.role,
1168 1168 'scope': self.scope_humanized,
1169 1169 'expired': self.expired
1170 1170 }
1171 1171 return data
1172 1172
1173 1173 def get_api_data(self, include_secrets=False):
1174 1174 data = self.__json__()
1175 1175 if include_secrets:
1176 1176 return data
1177 1177 else:
1178 1178 data['auth_token'] = self.token_obfuscated
1179 1179 return data
1180 1180
1181 1181 @hybrid_property
1182 1182 def description_safe(self):
1183 1183 from rhodecode.lib import helpers as h
1184 1184 return h.escape(self.description)
1185 1185
1186 1186 @property
1187 1187 def expired(self):
1188 1188 if self.expires == -1:
1189 1189 return False
1190 1190 return time.time() > self.expires
1191 1191
1192 1192 @classmethod
1193 1193 def _get_role_name(cls, role):
1194 1194 return {
1195 1195 cls.ROLE_ALL: _('all'),
1196 1196 cls.ROLE_HTTP: _('http/web interface'),
1197 1197 cls.ROLE_VCS: _('vcs (git/hg/svn protocol)'),
1198 1198 cls.ROLE_API: _('api calls'),
1199 1199 cls.ROLE_FEED: _('feed access'),
1200 1200 cls.ROLE_ARTIFACT_DOWNLOAD: _('artifacts downloads'),
1201 1201 }.get(role, role)
1202 1202
1203 1203 @property
1204 1204 def role_humanized(self):
1205 1205 return self._get_role_name(self.role)
1206 1206
1207 1207 def _get_scope(self):
1208 1208 if self.repo:
1209 1209 return 'Repository: {}'.format(self.repo.repo_name)
1210 1210 if self.repo_group:
1211 1211 return 'RepositoryGroup: {} (recursive)'.format(self.repo_group.group_name)
1212 1212 return 'Global'
1213 1213
1214 1214 @property
1215 1215 def scope_humanized(self):
1216 1216 return self._get_scope()
1217 1217
1218 1218 @property
1219 1219 def token_obfuscated(self):
1220 1220 if self.api_key:
1221 1221 return self.api_key[:4] + "****"
1222 1222
1223 1223
1224 1224 class UserEmailMap(Base, BaseModel):
1225 1225 __tablename__ = 'user_email_map'
1226 1226 __table_args__ = (
1227 1227 Index('uem_email_idx', 'email'),
1228 1228 UniqueConstraint('email'),
1229 1229 base_table_args
1230 1230 )
1231 1231 __mapper_args__ = {}
1232 1232
1233 1233 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1234 1234 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1235 1235 _email = Column("email", String(255), nullable=True, unique=False, default=None)
1236 1236 user = relationship('User', lazy='joined')
1237 1237
1238 1238 @validates('_email')
1239 1239 def validate_email(self, key, email):
1240 1240 # check if this email is not main one
1241 1241 main_email = Session().query(User).filter(User.email == email).scalar()
1242 1242 if main_email is not None:
1243 1243 raise AttributeError('email %s is present is user table' % email)
1244 1244 return email
1245 1245
1246 1246 @hybrid_property
1247 1247 def email(self):
1248 1248 return self._email
1249 1249
1250 1250 @email.setter
1251 1251 def email(self, val):
1252 1252 self._email = val.lower() if val else None
1253 1253
1254 1254
1255 1255 class UserIpMap(Base, BaseModel):
1256 1256 __tablename__ = 'user_ip_map'
1257 1257 __table_args__ = (
1258 1258 UniqueConstraint('user_id', 'ip_addr'),
1259 1259 base_table_args
1260 1260 )
1261 1261 __mapper_args__ = {}
1262 1262
1263 1263 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1264 1264 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1265 1265 ip_addr = Column("ip_addr", String(255), nullable=True, unique=False, default=None)
1266 1266 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
1267 1267 description = Column("description", String(10000), nullable=True, unique=None, default=None)
1268 1268 user = relationship('User', lazy='joined')
1269 1269
1270 1270 @hybrid_property
1271 1271 def description_safe(self):
1272 1272 from rhodecode.lib import helpers as h
1273 1273 return h.escape(self.description)
1274 1274
1275 1275 @classmethod
1276 1276 def _get_ip_range(cls, ip_addr):
1277 1277 net = ipaddress.ip_network(safe_unicode(ip_addr), strict=False)
1278 1278 return [str(net.network_address), str(net.broadcast_address)]
1279 1279
1280 1280 def __json__(self):
1281 1281 return {
1282 1282 'ip_addr': self.ip_addr,
1283 1283 'ip_range': self._get_ip_range(self.ip_addr),
1284 1284 }
1285 1285
1286 1286 def __unicode__(self):
1287 1287 return u"<%s('user_id:%s=>%s')>" % (self.__class__.__name__,
1288 1288 self.user_id, self.ip_addr)
1289 1289
1290 1290
1291 1291 class UserSshKeys(Base, BaseModel):
1292 1292 __tablename__ = 'user_ssh_keys'
1293 1293 __table_args__ = (
1294 1294 Index('usk_ssh_key_fingerprint_idx', 'ssh_key_fingerprint'),
1295 1295
1296 1296 UniqueConstraint('ssh_key_fingerprint'),
1297 1297
1298 1298 base_table_args
1299 1299 )
1300 1300 __mapper_args__ = {}
1301 1301
1302 1302 ssh_key_id = Column('ssh_key_id', Integer(), nullable=False, unique=True, default=None, primary_key=True)
1303 1303 ssh_key_data = Column('ssh_key_data', String(10240), nullable=False, unique=None, default=None)
1304 1304 ssh_key_fingerprint = Column('ssh_key_fingerprint', String(255), nullable=False, unique=None, default=None)
1305 1305
1306 1306 description = Column('description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
1307 1307
1308 1308 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1309 1309 accessed_on = Column('accessed_on', DateTime(timezone=False), nullable=True, default=None)
1310 1310 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1311 1311
1312 1312 user = relationship('User', lazy='joined')
1313 1313
1314 1314 def __json__(self):
1315 1315 data = {
1316 1316 'ssh_fingerprint': self.ssh_key_fingerprint,
1317 1317 'description': self.description,
1318 1318 'created_on': self.created_on
1319 1319 }
1320 1320 return data
1321 1321
1322 1322 def get_api_data(self):
1323 1323 data = self.__json__()
1324 1324 return data
1325 1325
1326 1326
1327 1327 class UserLog(Base, BaseModel):
1328 1328 __tablename__ = 'user_logs'
1329 1329 __table_args__ = (
1330 1330 base_table_args,
1331 1331 )
1332 1332
1333 1333 VERSION_1 = 'v1'
1334 1334 VERSION_2 = 'v2'
1335 1335 VERSIONS = [VERSION_1, VERSION_2]
1336 1336
1337 1337 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1338 1338 user_id = Column("user_id", Integer(), ForeignKey('users.user_id',ondelete='SET NULL'), nullable=True, unique=None, default=None)
1339 1339 username = Column("username", String(255), nullable=True, unique=None, default=None)
1340 1340 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id', ondelete='SET NULL'), nullable=True, unique=None, default=None)
1341 1341 repository_name = Column("repository_name", String(255), nullable=True, unique=None, default=None)
1342 1342 user_ip = Column("user_ip", String(255), nullable=True, unique=None, default=None)
1343 1343 action = Column("action", Text().with_variant(Text(1200000), 'mysql'), nullable=True, unique=None, default=None)
1344 1344 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
1345 1345
1346 1346 version = Column("version", String(255), nullable=True, default=VERSION_1)
1347 1347 user_data = Column('user_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=LONGTEXT()))))
1348 1348 action_data = Column('action_data_json', MutationObj.as_mutable(JsonType(dialect_map=dict(mysql=LONGTEXT()))))
1349 1349
1350 1350 def __unicode__(self):
1351 1351 return u"<%s('id:%s:%s')>" % (
1352 1352 self.__class__.__name__, self.repository_name, self.action)
1353 1353
1354 1354 def __json__(self):
1355 1355 return {
1356 1356 'user_id': self.user_id,
1357 1357 'username': self.username,
1358 1358 'repository_id': self.repository_id,
1359 1359 'repository_name': self.repository_name,
1360 1360 'user_ip': self.user_ip,
1361 1361 'action_date': self.action_date,
1362 1362 'action': self.action,
1363 1363 }
1364 1364
1365 1365 @hybrid_property
1366 1366 def entry_id(self):
1367 1367 return self.user_log_id
1368 1368
1369 1369 @property
1370 1370 def action_as_day(self):
1371 1371 return datetime.date(*self.action_date.timetuple()[:3])
1372 1372
1373 1373 user = relationship('User')
1374 1374 repository = relationship('Repository', cascade='')
1375 1375
1376 1376
1377 1377 class UserGroup(Base, BaseModel):
1378 1378 __tablename__ = 'users_groups'
1379 1379 __table_args__ = (
1380 1380 base_table_args,
1381 1381 )
1382 1382
1383 1383 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1384 1384 users_group_name = Column("users_group_name", String(255), nullable=False, unique=True, default=None)
1385 1385 user_group_description = Column("user_group_description", String(10000), nullable=True, unique=None, default=None)
1386 1386 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
1387 1387 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
1388 1388 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
1389 1389 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1390 1390 _group_data = Column("group_data", LargeBinary(), nullable=True) # JSON data
1391 1391
1392 1392 members = relationship('UserGroupMember', cascade="all, delete-orphan", lazy="joined")
1393 1393 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
1394 1394 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
1395 1395 users_group_repo_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
1396 1396 user_user_group_to_perm = relationship('UserUserGroupToPerm', cascade='all')
1397 1397 user_group_user_group_to_perm = relationship('UserGroupUserGroupToPerm ', primaryjoin="UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id", cascade='all')
1398 1398
1399 1399 user_group_review_rules = relationship('RepoReviewRuleUserGroup', cascade='all')
1400 1400 user = relationship('User', primaryjoin="User.user_id==UserGroup.user_id")
1401 1401
1402 1402 @classmethod
1403 1403 def _load_group_data(cls, column):
1404 1404 if not column:
1405 1405 return {}
1406 1406
1407 1407 try:
1408 1408 return json.loads(column) or {}
1409 1409 except TypeError:
1410 1410 return {}
1411 1411
1412 1412 @hybrid_property
1413 1413 def description_safe(self):
1414 1414 from rhodecode.lib import helpers as h
1415 1415 return h.escape(self.user_group_description)
1416 1416
1417 1417 @hybrid_property
1418 1418 def group_data(self):
1419 1419 return self._load_group_data(self._group_data)
1420 1420
1421 1421 @group_data.expression
1422 1422 def group_data(self, **kwargs):
1423 1423 return self._group_data
1424 1424
1425 1425 @group_data.setter
1426 1426 def group_data(self, val):
1427 1427 try:
1428 1428 self._group_data = json.dumps(val)
1429 1429 except Exception:
1430 1430 log.error(traceback.format_exc())
1431 1431
1432 1432 @classmethod
1433 1433 def _load_sync(cls, group_data):
1434 1434 if group_data:
1435 1435 return group_data.get('extern_type')
1436 1436
1437 1437 @property
1438 1438 def sync(self):
1439 1439 return self._load_sync(self.group_data)
1440 1440
1441 1441 def __unicode__(self):
1442 1442 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
1443 1443 self.users_group_id,
1444 1444 self.users_group_name)
1445 1445
1446 1446 @classmethod
1447 1447 def get_by_group_name(cls, group_name, cache=False,
1448 1448 case_insensitive=False):
1449 1449 if case_insensitive:
1450 1450 q = cls.query().filter(func.lower(cls.users_group_name) ==
1451 1451 func.lower(group_name))
1452 1452
1453 1453 else:
1454 1454 q = cls.query().filter(cls.users_group_name == group_name)
1455 1455 if cache:
1456 1456 q = q.options(
1457 1457 FromCache("sql_cache_short", "get_group_%s" % _hash_key(group_name)))
1458 1458 return q.scalar()
1459 1459
1460 1460 @classmethod
1461 1461 def get(cls, user_group_id, cache=False):
1462 1462 if not user_group_id:
1463 1463 return
1464 1464
1465 1465 user_group = cls.query()
1466 1466 if cache:
1467 1467 user_group = user_group.options(
1468 1468 FromCache("sql_cache_short", "get_users_group_%s" % user_group_id))
1469 1469 return user_group.get(user_group_id)
1470 1470
1471 1471 def permissions(self, with_admins=True, with_owner=True,
1472 1472 expand_from_user_groups=False):
1473 1473 """
1474 1474 Permissions for user groups
1475 1475 """
1476 1476 _admin_perm = 'usergroup.admin'
1477 1477
1478 1478 owner_row = []
1479 1479 if with_owner:
1480 1480 usr = AttributeDict(self.user.get_dict())
1481 1481 usr.owner_row = True
1482 1482 usr.permission = _admin_perm
1483 1483 owner_row.append(usr)
1484 1484
1485 1485 super_admin_ids = []
1486 1486 super_admin_rows = []
1487 1487 if with_admins:
1488 1488 for usr in User.get_all_super_admins():
1489 1489 super_admin_ids.append(usr.user_id)
1490 1490 # if this admin is also owner, don't double the record
1491 1491 if usr.user_id == owner_row[0].user_id:
1492 1492 owner_row[0].admin_row = True
1493 1493 else:
1494 1494 usr = AttributeDict(usr.get_dict())
1495 1495 usr.admin_row = True
1496 1496 usr.permission = _admin_perm
1497 1497 super_admin_rows.append(usr)
1498 1498
1499 1499 q = UserUserGroupToPerm.query().filter(UserUserGroupToPerm.user_group == self)
1500 1500 q = q.options(joinedload(UserUserGroupToPerm.user_group),
1501 1501 joinedload(UserUserGroupToPerm.user),
1502 1502 joinedload(UserUserGroupToPerm.permission),)
1503 1503
1504 1504 # get owners and admins and permissions. We do a trick of re-writing
1505 1505 # objects from sqlalchemy to named-tuples due to sqlalchemy session
1506 1506 # has a global reference and changing one object propagates to all
1507 1507 # others. This means if admin is also an owner admin_row that change
1508 1508 # would propagate to both objects
1509 1509 perm_rows = []
1510 1510 for _usr in q.all():
1511 1511 usr = AttributeDict(_usr.user.get_dict())
1512 1512 # if this user is also owner/admin, mark as duplicate record
1513 1513 if usr.user_id == owner_row[0].user_id or usr.user_id in super_admin_ids:
1514 1514 usr.duplicate_perm = True
1515 1515 usr.permission = _usr.permission.permission_name
1516 1516 perm_rows.append(usr)
1517 1517
1518 1518 # filter the perm rows by 'default' first and then sort them by
1519 1519 # admin,write,read,none permissions sorted again alphabetically in
1520 1520 # each group
1521 1521 perm_rows = sorted(perm_rows, key=display_user_sort)
1522 1522
1523 1523 user_groups_rows = []
1524 1524 if expand_from_user_groups:
1525 1525 for ug in self.permission_user_groups(with_members=True):
1526 1526 for user_data in ug.members:
1527 1527 user_groups_rows.append(user_data)
1528 1528
1529 1529 return super_admin_rows + owner_row + perm_rows + user_groups_rows
1530 1530
1531 1531 def permission_user_groups(self, with_members=False):
1532 1532 q = UserGroupUserGroupToPerm.query()\
1533 1533 .filter(UserGroupUserGroupToPerm.target_user_group == self)
1534 1534 q = q.options(joinedload(UserGroupUserGroupToPerm.user_group),
1535 1535 joinedload(UserGroupUserGroupToPerm.target_user_group),
1536 1536 joinedload(UserGroupUserGroupToPerm.permission),)
1537 1537
1538 1538 perm_rows = []
1539 1539 for _user_group in q.all():
1540 1540 entry = AttributeDict(_user_group.user_group.get_dict())
1541 1541 entry.permission = _user_group.permission.permission_name
1542 1542 if with_members:
1543 1543 entry.members = [x.user.get_dict()
1544 1544 for x in _user_group.user_group.members]
1545 1545 perm_rows.append(entry)
1546 1546
1547 1547 perm_rows = sorted(perm_rows, key=display_user_group_sort)
1548 1548 return perm_rows
1549 1549
1550 1550 def _get_default_perms(self, user_group, suffix=''):
1551 1551 from rhodecode.model.permission import PermissionModel
1552 1552 return PermissionModel().get_default_perms(user_group.users_group_to_perm, suffix)
1553 1553
1554 1554 def get_default_perms(self, suffix=''):
1555 1555 return self._get_default_perms(self, suffix)
1556 1556
1557 1557 def get_api_data(self, with_group_members=True, include_secrets=False):
1558 1558 """
1559 1559 :param include_secrets: See :meth:`User.get_api_data`, this parameter is
1560 1560 basically forwarded.
1561 1561
1562 1562 """
1563 1563 user_group = self
1564 1564 data = {
1565 1565 'users_group_id': user_group.users_group_id,
1566 1566 'group_name': user_group.users_group_name,
1567 1567 'group_description': user_group.user_group_description,
1568 1568 'active': user_group.users_group_active,
1569 1569 'owner': user_group.user.username,
1570 1570 'sync': user_group.sync,
1571 1571 'owner_email': user_group.user.email,
1572 1572 }
1573 1573
1574 1574 if with_group_members:
1575 1575 users = []
1576 1576 for user in user_group.members:
1577 1577 user = user.user
1578 1578 users.append(user.get_api_data(include_secrets=include_secrets))
1579 1579 data['users'] = users
1580 1580
1581 1581 return data
1582 1582
1583 1583
1584 1584 class UserGroupMember(Base, BaseModel):
1585 1585 __tablename__ = 'users_groups_members'
1586 1586 __table_args__ = (
1587 1587 base_table_args,
1588 1588 )
1589 1589
1590 1590 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1591 1591 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1592 1592 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1593 1593
1594 1594 user = relationship('User', lazy='joined')
1595 1595 users_group = relationship('UserGroup')
1596 1596
1597 1597 def __init__(self, gr_id='', u_id=''):
1598 1598 self.users_group_id = gr_id
1599 1599 self.user_id = u_id
1600 1600
1601 1601
1602 1602 class RepositoryField(Base, BaseModel):
1603 1603 __tablename__ = 'repositories_fields'
1604 1604 __table_args__ = (
1605 1605 UniqueConstraint('repository_id', 'field_key'), # no-multi field
1606 1606 base_table_args,
1607 1607 )
1608 1608
1609 1609 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
1610 1610
1611 1611 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1612 1612 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1613 1613 field_key = Column("field_key", String(250))
1614 1614 field_label = Column("field_label", String(1024), nullable=False)
1615 1615 field_value = Column("field_value", String(10000), nullable=False)
1616 1616 field_desc = Column("field_desc", String(1024), nullable=False)
1617 1617 field_type = Column("field_type", String(255), nullable=False, unique=None)
1618 1618 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1619 1619
1620 1620 repository = relationship('Repository')
1621 1621
1622 1622 @property
1623 1623 def field_key_prefixed(self):
1624 1624 return 'ex_%s' % self.field_key
1625 1625
1626 1626 @classmethod
1627 1627 def un_prefix_key(cls, key):
1628 1628 if key.startswith(cls.PREFIX):
1629 1629 return key[len(cls.PREFIX):]
1630 1630 return key
1631 1631
1632 1632 @classmethod
1633 1633 def get_by_key_name(cls, key, repo):
1634 1634 row = cls.query()\
1635 1635 .filter(cls.repository == repo)\
1636 1636 .filter(cls.field_key == key).scalar()
1637 1637 return row
1638 1638
1639 1639
1640 1640 class Repository(Base, BaseModel):
1641 1641 __tablename__ = 'repositories'
1642 1642 __table_args__ = (
1643 1643 Index('r_repo_name_idx', 'repo_name', mysql_length=255),
1644 1644 base_table_args,
1645 1645 )
1646 1646 DEFAULT_CLONE_URI = '{scheme}://{user}@{netloc}/{repo}'
1647 1647 DEFAULT_CLONE_URI_ID = '{scheme}://{user}@{netloc}/_{repoid}'
1648 1648 DEFAULT_CLONE_URI_SSH = 'ssh://{sys_user}@{hostname}/{repo}'
1649 1649
1650 1650 STATE_CREATED = 'repo_state_created'
1651 1651 STATE_PENDING = 'repo_state_pending'
1652 1652 STATE_ERROR = 'repo_state_error'
1653 1653
1654 1654 LOCK_AUTOMATIC = 'lock_auto'
1655 1655 LOCK_API = 'lock_api'
1656 1656 LOCK_WEB = 'lock_web'
1657 1657 LOCK_PULL = 'lock_pull'
1658 1658
1659 1659 NAME_SEP = URL_SEP
1660 1660
1661 1661 repo_id = Column(
1662 1662 "repo_id", Integer(), nullable=False, unique=True, default=None,
1663 1663 primary_key=True)
1664 1664 _repo_name = Column(
1665 1665 "repo_name", Text(), nullable=False, default=None)
1666 1666 repo_name_hash = Column(
1667 1667 "repo_name_hash", String(255), nullable=False, unique=True)
1668 1668 repo_state = Column("repo_state", String(255), nullable=True)
1669 1669
1670 1670 clone_uri = Column(
1671 1671 "clone_uri", EncryptedTextValue(), nullable=True, unique=False,
1672 1672 default=None)
1673 1673 push_uri = Column(
1674 1674 "push_uri", EncryptedTextValue(), nullable=True, unique=False,
1675 1675 default=None)
1676 1676 repo_type = Column(
1677 1677 "repo_type", String(255), nullable=False, unique=False, default=None)
1678 1678 user_id = Column(
1679 1679 "user_id", Integer(), ForeignKey('users.user_id'), nullable=False,
1680 1680 unique=False, default=None)
1681 1681 private = Column(
1682 1682 "private", Boolean(), nullable=True, unique=None, default=None)
1683 1683 archived = Column(
1684 1684 "archived", Boolean(), nullable=True, unique=None, default=None)
1685 1685 enable_statistics = Column(
1686 1686 "statistics", Boolean(), nullable=True, unique=None, default=True)
1687 1687 enable_downloads = Column(
1688 1688 "downloads", Boolean(), nullable=True, unique=None, default=True)
1689 1689 description = Column(
1690 1690 "description", String(10000), nullable=True, unique=None, default=None)
1691 1691 created_on = Column(
1692 1692 'created_on', DateTime(timezone=False), nullable=True, unique=None,
1693 1693 default=datetime.datetime.now)
1694 1694 updated_on = Column(
1695 1695 'updated_on', DateTime(timezone=False), nullable=True, unique=None,
1696 1696 default=datetime.datetime.now)
1697 1697 _landing_revision = Column(
1698 1698 "landing_revision", String(255), nullable=False, unique=False,
1699 1699 default=None)
1700 1700 enable_locking = Column(
1701 1701 "enable_locking", Boolean(), nullable=False, unique=None,
1702 1702 default=False)
1703 1703 _locked = Column(
1704 1704 "locked", String(255), nullable=True, unique=False, default=None)
1705 1705 _changeset_cache = Column(
1706 1706 "changeset_cache", LargeBinary(), nullable=True) # JSON data
1707 1707
1708 1708 fork_id = Column(
1709 1709 "fork_id", Integer(), ForeignKey('repositories.repo_id'),
1710 1710 nullable=True, unique=False, default=None)
1711 1711 group_id = Column(
1712 1712 "group_id", Integer(), ForeignKey('groups.group_id'), nullable=True,
1713 1713 unique=False, default=None)
1714 1714
1715 1715 user = relationship('User', lazy='joined')
1716 1716 fork = relationship('Repository', remote_side=repo_id, lazy='joined')
1717 1717 group = relationship('RepoGroup', lazy='joined')
1718 1718 repo_to_perm = relationship(
1719 1719 'UserRepoToPerm', cascade='all',
1720 1720 order_by='UserRepoToPerm.repo_to_perm_id')
1721 1721 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
1722 1722 stats = relationship('Statistics', cascade='all', uselist=False)
1723 1723
1724 1724 followers = relationship(
1725 1725 'UserFollowing',
1726 1726 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
1727 1727 cascade='all')
1728 1728 extra_fields = relationship(
1729 1729 'RepositoryField', cascade="all, delete-orphan")
1730 1730 logs = relationship('UserLog')
1731 1731 comments = relationship(
1732 1732 'ChangesetComment', cascade="all, delete-orphan")
1733 1733 pull_requests_source = relationship(
1734 1734 'PullRequest',
1735 1735 primaryjoin='PullRequest.source_repo_id==Repository.repo_id',
1736 1736 cascade="all, delete-orphan")
1737 1737 pull_requests_target = relationship(
1738 1738 'PullRequest',
1739 1739 primaryjoin='PullRequest.target_repo_id==Repository.repo_id',
1740 1740 cascade="all, delete-orphan")
1741 1741 ui = relationship('RepoRhodeCodeUi', cascade="all")
1742 1742 settings = relationship('RepoRhodeCodeSetting', cascade="all")
1743 1743 integrations = relationship('Integration', cascade="all, delete-orphan")
1744 1744
1745 1745 scoped_tokens = relationship('UserApiKeys', cascade="all")
1746 1746
1747 1747 # no cascade, set NULL
1748 1748 artifacts = relationship('FileStore', primaryjoin='FileStore.scope_repo_id==Repository.repo_id')
1749 1749
1750 1750 def __unicode__(self):
1751 1751 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
1752 1752 safe_unicode(self.repo_name))
1753 1753
1754 1754 @hybrid_property
1755 1755 def description_safe(self):
1756 1756 from rhodecode.lib import helpers as h
1757 1757 return h.escape(self.description)
1758 1758
1759 1759 @hybrid_property
1760 1760 def landing_rev(self):
1761 # always should return [rev_type, rev]
1761 # always should return [rev_type, rev], e.g ['branch', 'master']
1762 1762 if self._landing_revision:
1763 1763 _rev_info = self._landing_revision.split(':')
1764 1764 if len(_rev_info) < 2:
1765 1765 _rev_info.insert(0, 'rev')
1766 1766 return [_rev_info[0], _rev_info[1]]
1767 1767 return [None, None]
1768 1768
1769 @property
1770 def landing_ref_type(self):
1771 return self.landing_rev[0]
1772
1773 @property
1774 def landing_ref_name(self):
1775 return self.landing_rev[1]
1776
1769 1777 @landing_rev.setter
1770 1778 def landing_rev(self, val):
1771 1779 if ':' not in val:
1772 1780 raise ValueError('value must be delimited with `:` and consist '
1773 1781 'of <rev_type>:<rev>, got %s instead' % val)
1774 1782 self._landing_revision = val
1775 1783
1776 1784 @hybrid_property
1777 1785 def locked(self):
1778 1786 if self._locked:
1779 1787 user_id, timelocked, reason = self._locked.split(':')
1780 1788 lock_values = int(user_id), timelocked, reason
1781 1789 else:
1782 1790 lock_values = [None, None, None]
1783 1791 return lock_values
1784 1792
1785 1793 @locked.setter
1786 1794 def locked(self, val):
1787 1795 if val and isinstance(val, (list, tuple)):
1788 1796 self._locked = ':'.join(map(str, val))
1789 1797 else:
1790 1798 self._locked = None
1791 1799
1792 1800 @classmethod
1793 1801 def _load_changeset_cache(cls, repo_id, changeset_cache_raw):
1794 1802 from rhodecode.lib.vcs.backends.base import EmptyCommit
1795 1803 dummy = EmptyCommit().__json__()
1796 1804 if not changeset_cache_raw:
1797 1805 dummy['source_repo_id'] = repo_id
1798 1806 return json.loads(json.dumps(dummy))
1799 1807
1800 1808 try:
1801 1809 return json.loads(changeset_cache_raw)
1802 1810 except TypeError:
1803 1811 return dummy
1804 1812 except Exception:
1805 1813 log.error(traceback.format_exc())
1806 1814 return dummy
1807 1815
1808 1816 @hybrid_property
1809 1817 def changeset_cache(self):
1810 1818 return self._load_changeset_cache(self.repo_id, self._changeset_cache)
1811 1819
1812 1820 @changeset_cache.setter
1813 1821 def changeset_cache(self, val):
1814 1822 try:
1815 1823 self._changeset_cache = json.dumps(val)
1816 1824 except Exception:
1817 1825 log.error(traceback.format_exc())
1818 1826
1819 1827 @hybrid_property
1820 1828 def repo_name(self):
1821 1829 return self._repo_name
1822 1830
1823 1831 @repo_name.setter
1824 1832 def repo_name(self, value):
1825 1833 self._repo_name = value
1826 1834 self.repo_name_hash = hashlib.sha1(safe_str(value)).hexdigest()
1827 1835
1828 1836 @classmethod
1829 1837 def normalize_repo_name(cls, repo_name):
1830 1838 """
1831 1839 Normalizes os specific repo_name to the format internally stored inside
1832 1840 database using URL_SEP
1833 1841
1834 1842 :param cls:
1835 1843 :param repo_name:
1836 1844 """
1837 1845 return cls.NAME_SEP.join(repo_name.split(os.sep))
1838 1846
1839 1847 @classmethod
1840 1848 def get_by_repo_name(cls, repo_name, cache=False, identity_cache=False):
1841 1849 session = Session()
1842 1850 q = session.query(cls).filter(cls.repo_name == repo_name)
1843 1851
1844 1852 if cache:
1845 1853 if identity_cache:
1846 1854 val = cls.identity_cache(session, 'repo_name', repo_name)
1847 1855 if val:
1848 1856 return val
1849 1857 else:
1850 1858 cache_key = "get_repo_by_name_%s" % _hash_key(repo_name)
1851 1859 q = q.options(
1852 1860 FromCache("sql_cache_short", cache_key))
1853 1861
1854 1862 return q.scalar()
1855 1863
1856 1864 @classmethod
1857 1865 def get_by_id_or_repo_name(cls, repoid):
1858 1866 if isinstance(repoid, (int, long)):
1859 1867 try:
1860 1868 repo = cls.get(repoid)
1861 1869 except ValueError:
1862 1870 repo = None
1863 1871 else:
1864 1872 repo = cls.get_by_repo_name(repoid)
1865 1873 return repo
1866 1874
1867 1875 @classmethod
1868 1876 def get_by_full_path(cls, repo_full_path):
1869 1877 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
1870 1878 repo_name = cls.normalize_repo_name(repo_name)
1871 1879 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
1872 1880
1873 1881 @classmethod
1874 1882 def get_repo_forks(cls, repo_id):
1875 1883 return cls.query().filter(Repository.fork_id == repo_id)
1876 1884
1877 1885 @classmethod
1878 1886 def base_path(cls):
1879 1887 """
1880 1888 Returns base path when all repos are stored
1881 1889
1882 1890 :param cls:
1883 1891 """
1884 1892 q = Session().query(RhodeCodeUi)\
1885 1893 .filter(RhodeCodeUi.ui_key == cls.NAME_SEP)
1886 1894 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
1887 1895 return q.one().ui_value
1888 1896
1889 1897 @classmethod
1890 1898 def get_all_repos(cls, user_id=Optional(None), group_id=Optional(None),
1891 1899 case_insensitive=True, archived=False):
1892 1900 q = Repository.query()
1893 1901
1894 1902 if not archived:
1895 1903 q = q.filter(Repository.archived.isnot(true()))
1896 1904
1897 1905 if not isinstance(user_id, Optional):
1898 1906 q = q.filter(Repository.user_id == user_id)
1899 1907
1900 1908 if not isinstance(group_id, Optional):
1901 1909 q = q.filter(Repository.group_id == group_id)
1902 1910
1903 1911 if case_insensitive:
1904 1912 q = q.order_by(func.lower(Repository.repo_name))
1905 1913 else:
1906 1914 q = q.order_by(Repository.repo_name)
1907 1915
1908 1916 return q.all()
1909 1917
1910 1918 @property
1911 1919 def repo_uid(self):
1912 1920 return '_{}'.format(self.repo_id)
1913 1921
1914 1922 @property
1915 1923 def forks(self):
1916 1924 """
1917 1925 Return forks of this repo
1918 1926 """
1919 1927 return Repository.get_repo_forks(self.repo_id)
1920 1928
1921 1929 @property
1922 1930 def parent(self):
1923 1931 """
1924 1932 Returns fork parent
1925 1933 """
1926 1934 return self.fork
1927 1935
1928 1936 @property
1929 1937 def just_name(self):
1930 1938 return self.repo_name.split(self.NAME_SEP)[-1]
1931 1939
1932 1940 @property
1933 1941 def groups_with_parents(self):
1934 1942 groups = []
1935 1943 if self.group is None:
1936 1944 return groups
1937 1945
1938 1946 cur_gr = self.group
1939 1947 groups.insert(0, cur_gr)
1940 1948 while 1:
1941 1949 gr = getattr(cur_gr, 'parent_group', None)
1942 1950 cur_gr = cur_gr.parent_group
1943 1951 if gr is None:
1944 1952 break
1945 1953 groups.insert(0, gr)
1946 1954
1947 1955 return groups
1948 1956
1949 1957 @property
1950 1958 def groups_and_repo(self):
1951 1959 return self.groups_with_parents, self
1952 1960
1953 1961 @LazyProperty
1954 1962 def repo_path(self):
1955 1963 """
1956 1964 Returns base full path for that repository means where it actually
1957 1965 exists on a filesystem
1958 1966 """
1959 1967 q = Session().query(RhodeCodeUi).filter(
1960 1968 RhodeCodeUi.ui_key == self.NAME_SEP)
1961 1969 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
1962 1970 return q.one().ui_value
1963 1971
1964 1972 @property
1965 1973 def repo_full_path(self):
1966 1974 p = [self.repo_path]
1967 1975 # we need to split the name by / since this is how we store the
1968 1976 # names in the database, but that eventually needs to be converted
1969 1977 # into a valid system path
1970 1978 p += self.repo_name.split(self.NAME_SEP)
1971 1979 return os.path.join(*map(safe_unicode, p))
1972 1980
1973 1981 @property
1974 1982 def cache_keys(self):
1975 1983 """
1976 1984 Returns associated cache keys for that repo
1977 1985 """
1978 1986 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
1979 1987 repo_id=self.repo_id)
1980 1988 return CacheKey.query()\
1981 1989 .filter(CacheKey.cache_args == invalidation_namespace)\
1982 1990 .order_by(CacheKey.cache_key)\
1983 1991 .all()
1984 1992
1985 1993 @property
1986 1994 def cached_diffs_relative_dir(self):
1987 1995 """
1988 1996 Return a relative to the repository store path of cached diffs
1989 1997 used for safe display for users, who shouldn't know the absolute store
1990 1998 path
1991 1999 """
1992 2000 return os.path.join(
1993 2001 os.path.dirname(self.repo_name),
1994 2002 self.cached_diffs_dir.split(os.path.sep)[-1])
1995 2003
1996 2004 @property
1997 2005 def cached_diffs_dir(self):
1998 2006 path = self.repo_full_path
1999 2007 return os.path.join(
2000 2008 os.path.dirname(path),
2001 2009 '.__shadow_diff_cache_repo_{}'.format(self.repo_id))
2002 2010
2003 2011 def cached_diffs(self):
2004 2012 diff_cache_dir = self.cached_diffs_dir
2005 2013 if os.path.isdir(diff_cache_dir):
2006 2014 return os.listdir(diff_cache_dir)
2007 2015 return []
2008 2016
2009 2017 def shadow_repos(self):
2010 2018 shadow_repos_pattern = '.__shadow_repo_{}'.format(self.repo_id)
2011 2019 return [
2012 2020 x for x in os.listdir(os.path.dirname(self.repo_full_path))
2013 2021 if x.startswith(shadow_repos_pattern)]
2014 2022
2015 2023 def get_new_name(self, repo_name):
2016 2024 """
2017 2025 returns new full repository name based on assigned group and new new
2018 2026
2019 2027 :param group_name:
2020 2028 """
2021 2029 path_prefix = self.group.full_path_splitted if self.group else []
2022 2030 return self.NAME_SEP.join(path_prefix + [repo_name])
2023 2031
2024 2032 @property
2025 2033 def _config(self):
2026 2034 """
2027 2035 Returns db based config object.
2028 2036 """
2029 2037 from rhodecode.lib.utils import make_db_config
2030 2038 return make_db_config(clear_session=False, repo=self)
2031 2039
2032 2040 def permissions(self, with_admins=True, with_owner=True,
2033 2041 expand_from_user_groups=False):
2034 2042 """
2035 2043 Permissions for repositories
2036 2044 """
2037 2045 _admin_perm = 'repository.admin'
2038 2046
2039 2047 owner_row = []
2040 2048 if with_owner:
2041 2049 usr = AttributeDict(self.user.get_dict())
2042 2050 usr.owner_row = True
2043 2051 usr.permission = _admin_perm
2044 2052 usr.permission_id = None
2045 2053 owner_row.append(usr)
2046 2054
2047 2055 super_admin_ids = []
2048 2056 super_admin_rows = []
2049 2057 if with_admins:
2050 2058 for usr in User.get_all_super_admins():
2051 2059 super_admin_ids.append(usr.user_id)
2052 2060 # if this admin is also owner, don't double the record
2053 2061 if usr.user_id == owner_row[0].user_id:
2054 2062 owner_row[0].admin_row = True
2055 2063 else:
2056 2064 usr = AttributeDict(usr.get_dict())
2057 2065 usr.admin_row = True
2058 2066 usr.permission = _admin_perm
2059 2067 usr.permission_id = None
2060 2068 super_admin_rows.append(usr)
2061 2069
2062 2070 q = UserRepoToPerm.query().filter(UserRepoToPerm.repository == self)
2063 2071 q = q.options(joinedload(UserRepoToPerm.repository),
2064 2072 joinedload(UserRepoToPerm.user),
2065 2073 joinedload(UserRepoToPerm.permission),)
2066 2074
2067 2075 # get owners and admins and permissions. We do a trick of re-writing
2068 2076 # objects from sqlalchemy to named-tuples due to sqlalchemy session
2069 2077 # has a global reference and changing one object propagates to all
2070 2078 # others. This means if admin is also an owner admin_row that change
2071 2079 # would propagate to both objects
2072 2080 perm_rows = []
2073 2081 for _usr in q.all():
2074 2082 usr = AttributeDict(_usr.user.get_dict())
2075 2083 # if this user is also owner/admin, mark as duplicate record
2076 2084 if usr.user_id == owner_row[0].user_id or usr.user_id in super_admin_ids:
2077 2085 usr.duplicate_perm = True
2078 2086 # also check if this permission is maybe used by branch_permissions
2079 2087 if _usr.branch_perm_entry:
2080 2088 usr.branch_rules = [x.branch_rule_id for x in _usr.branch_perm_entry]
2081 2089
2082 2090 usr.permission = _usr.permission.permission_name
2083 2091 usr.permission_id = _usr.repo_to_perm_id
2084 2092 perm_rows.append(usr)
2085 2093
2086 2094 # filter the perm rows by 'default' first and then sort them by
2087 2095 # admin,write,read,none permissions sorted again alphabetically in
2088 2096 # each group
2089 2097 perm_rows = sorted(perm_rows, key=display_user_sort)
2090 2098
2091 2099 user_groups_rows = []
2092 2100 if expand_from_user_groups:
2093 2101 for ug in self.permission_user_groups(with_members=True):
2094 2102 for user_data in ug.members:
2095 2103 user_groups_rows.append(user_data)
2096 2104
2097 2105 return super_admin_rows + owner_row + perm_rows + user_groups_rows
2098 2106
2099 2107 def permission_user_groups(self, with_members=True):
2100 2108 q = UserGroupRepoToPerm.query()\
2101 2109 .filter(UserGroupRepoToPerm.repository == self)
2102 2110 q = q.options(joinedload(UserGroupRepoToPerm.repository),
2103 2111 joinedload(UserGroupRepoToPerm.users_group),
2104 2112 joinedload(UserGroupRepoToPerm.permission),)
2105 2113
2106 2114 perm_rows = []
2107 2115 for _user_group in q.all():
2108 2116 entry = AttributeDict(_user_group.users_group.get_dict())
2109 2117 entry.permission = _user_group.permission.permission_name
2110 2118 if with_members:
2111 2119 entry.members = [x.user.get_dict()
2112 2120 for x in _user_group.users_group.members]
2113 2121 perm_rows.append(entry)
2114 2122
2115 2123 perm_rows = sorted(perm_rows, key=display_user_group_sort)
2116 2124 return perm_rows
2117 2125
2118 2126 def get_api_data(self, include_secrets=False):
2119 2127 """
2120 2128 Common function for generating repo api data
2121 2129
2122 2130 :param include_secrets: See :meth:`User.get_api_data`.
2123 2131
2124 2132 """
2125 2133 # TODO: mikhail: Here there is an anti-pattern, we probably need to
2126 2134 # move this methods on models level.
2127 2135 from rhodecode.model.settings import SettingsModel
2128 2136 from rhodecode.model.repo import RepoModel
2129 2137
2130 2138 repo = self
2131 2139 _user_id, _time, _reason = self.locked
2132 2140
2133 2141 data = {
2134 2142 'repo_id': repo.repo_id,
2135 2143 'repo_name': repo.repo_name,
2136 2144 'repo_type': repo.repo_type,
2137 2145 'clone_uri': repo.clone_uri or '',
2138 2146 'push_uri': repo.push_uri or '',
2139 2147 'url': RepoModel().get_url(self),
2140 2148 'private': repo.private,
2141 2149 'created_on': repo.created_on,
2142 2150 'description': repo.description_safe,
2143 2151 'landing_rev': repo.landing_rev,
2144 2152 'owner': repo.user.username,
2145 2153 'fork_of': repo.fork.repo_name if repo.fork else None,
2146 2154 'fork_of_id': repo.fork.repo_id if repo.fork else None,
2147 2155 'enable_statistics': repo.enable_statistics,
2148 2156 'enable_locking': repo.enable_locking,
2149 2157 'enable_downloads': repo.enable_downloads,
2150 2158 'last_changeset': repo.changeset_cache,
2151 2159 'locked_by': User.get(_user_id).get_api_data(
2152 2160 include_secrets=include_secrets) if _user_id else None,
2153 2161 'locked_date': time_to_datetime(_time) if _time else None,
2154 2162 'lock_reason': _reason if _reason else None,
2155 2163 }
2156 2164
2157 2165 # TODO: mikhail: should be per-repo settings here
2158 2166 rc_config = SettingsModel().get_all_settings()
2159 2167 repository_fields = str2bool(
2160 2168 rc_config.get('rhodecode_repository_fields'))
2161 2169 if repository_fields:
2162 2170 for f in self.extra_fields:
2163 2171 data[f.field_key_prefixed] = f.field_value
2164 2172
2165 2173 return data
2166 2174
2167 2175 @classmethod
2168 2176 def lock(cls, repo, user_id, lock_time=None, lock_reason=None):
2169 2177 if not lock_time:
2170 2178 lock_time = time.time()
2171 2179 if not lock_reason:
2172 2180 lock_reason = cls.LOCK_AUTOMATIC
2173 2181 repo.locked = [user_id, lock_time, lock_reason]
2174 2182 Session().add(repo)
2175 2183 Session().commit()
2176 2184
2177 2185 @classmethod
2178 2186 def unlock(cls, repo):
2179 2187 repo.locked = None
2180 2188 Session().add(repo)
2181 2189 Session().commit()
2182 2190
2183 2191 @classmethod
2184 2192 def getlock(cls, repo):
2185 2193 return repo.locked
2186 2194
2187 2195 def is_user_lock(self, user_id):
2188 2196 if self.lock[0]:
2189 2197 lock_user_id = safe_int(self.lock[0])
2190 2198 user_id = safe_int(user_id)
2191 2199 # both are ints, and they are equal
2192 2200 return all([lock_user_id, user_id]) and lock_user_id == user_id
2193 2201
2194 2202 return False
2195 2203
2196 2204 def get_locking_state(self, action, user_id, only_when_enabled=True):
2197 2205 """
2198 2206 Checks locking on this repository, if locking is enabled and lock is
2199 2207 present returns a tuple of make_lock, locked, locked_by.
2200 2208 make_lock can have 3 states None (do nothing) True, make lock
2201 2209 False release lock, This value is later propagated to hooks, which
2202 2210 do the locking. Think about this as signals passed to hooks what to do.
2203 2211
2204 2212 """
2205 2213 # TODO: johbo: This is part of the business logic and should be moved
2206 2214 # into the RepositoryModel.
2207 2215
2208 2216 if action not in ('push', 'pull'):
2209 2217 raise ValueError("Invalid action value: %s" % repr(action))
2210 2218
2211 2219 # defines if locked error should be thrown to user
2212 2220 currently_locked = False
2213 2221 # defines if new lock should be made, tri-state
2214 2222 make_lock = None
2215 2223 repo = self
2216 2224 user = User.get(user_id)
2217 2225
2218 2226 lock_info = repo.locked
2219 2227
2220 2228 if repo and (repo.enable_locking or not only_when_enabled):
2221 2229 if action == 'push':
2222 2230 # check if it's already locked !, if it is compare users
2223 2231 locked_by_user_id = lock_info[0]
2224 2232 if user.user_id == locked_by_user_id:
2225 2233 log.debug(
2226 2234 'Got `push` action from user %s, now unlocking', user)
2227 2235 # unlock if we have push from user who locked
2228 2236 make_lock = False
2229 2237 else:
2230 2238 # we're not the same user who locked, ban with
2231 2239 # code defined in settings (default is 423 HTTP Locked) !
2232 2240 log.debug('Repo %s is currently locked by %s', repo, user)
2233 2241 currently_locked = True
2234 2242 elif action == 'pull':
2235 2243 # [0] user [1] date
2236 2244 if lock_info[0] and lock_info[1]:
2237 2245 log.debug('Repo %s is currently locked by %s', repo, user)
2238 2246 currently_locked = True
2239 2247 else:
2240 2248 log.debug('Setting lock on repo %s by %s', repo, user)
2241 2249 make_lock = True
2242 2250
2243 2251 else:
2244 2252 log.debug('Repository %s do not have locking enabled', repo)
2245 2253
2246 2254 log.debug('FINAL locking values make_lock:%s,locked:%s,locked_by:%s',
2247 2255 make_lock, currently_locked, lock_info)
2248 2256
2249 2257 from rhodecode.lib.auth import HasRepoPermissionAny
2250 2258 perm_check = HasRepoPermissionAny('repository.write', 'repository.admin')
2251 2259 if make_lock and not perm_check(repo_name=repo.repo_name, user=user):
2252 2260 # if we don't have at least write permission we cannot make a lock
2253 2261 log.debug('lock state reset back to FALSE due to lack '
2254 2262 'of at least read permission')
2255 2263 make_lock = False
2256 2264
2257 2265 return make_lock, currently_locked, lock_info
2258 2266
2259 2267 @property
2260 2268 def last_commit_cache_update_diff(self):
2261 2269 return time.time() - (safe_int(self.changeset_cache.get('updated_on')) or 0)
2262 2270
2263 2271 @classmethod
2264 2272 def _load_commit_change(cls, last_commit_cache):
2265 2273 from rhodecode.lib.vcs.utils.helpers import parse_datetime
2266 2274 empty_date = datetime.datetime.fromtimestamp(0)
2267 2275 date_latest = last_commit_cache.get('date', empty_date)
2268 2276 try:
2269 2277 return parse_datetime(date_latest)
2270 2278 except Exception:
2271 2279 return empty_date
2272 2280
2273 2281 @property
2274 2282 def last_commit_change(self):
2275 2283 return self._load_commit_change(self.changeset_cache)
2276 2284
2277 2285 @property
2278 2286 def last_db_change(self):
2279 2287 return self.updated_on
2280 2288
2281 2289 @property
2282 2290 def clone_uri_hidden(self):
2283 2291 clone_uri = self.clone_uri
2284 2292 if clone_uri:
2285 2293 import urlobject
2286 2294 url_obj = urlobject.URLObject(cleaned_uri(clone_uri))
2287 2295 if url_obj.password:
2288 2296 clone_uri = url_obj.with_password('*****')
2289 2297 return clone_uri
2290 2298
2291 2299 @property
2292 2300 def push_uri_hidden(self):
2293 2301 push_uri = self.push_uri
2294 2302 if push_uri:
2295 2303 import urlobject
2296 2304 url_obj = urlobject.URLObject(cleaned_uri(push_uri))
2297 2305 if url_obj.password:
2298 2306 push_uri = url_obj.with_password('*****')
2299 2307 return push_uri
2300 2308
2301 2309 def clone_url(self, **override):
2302 2310 from rhodecode.model.settings import SettingsModel
2303 2311
2304 2312 uri_tmpl = None
2305 2313 if 'with_id' in override:
2306 2314 uri_tmpl = self.DEFAULT_CLONE_URI_ID
2307 2315 del override['with_id']
2308 2316
2309 2317 if 'uri_tmpl' in override:
2310 2318 uri_tmpl = override['uri_tmpl']
2311 2319 del override['uri_tmpl']
2312 2320
2313 2321 ssh = False
2314 2322 if 'ssh' in override:
2315 2323 ssh = True
2316 2324 del override['ssh']
2317 2325
2318 2326 # we didn't override our tmpl from **overrides
2319 2327 request = get_current_request()
2320 2328 if not uri_tmpl:
2321 2329 if hasattr(request, 'call_context') and hasattr(request.call_context, 'rc_config'):
2322 2330 rc_config = request.call_context.rc_config
2323 2331 else:
2324 2332 rc_config = SettingsModel().get_all_settings(cache=True)
2325 2333
2326 2334 if ssh:
2327 2335 uri_tmpl = rc_config.get(
2328 2336 'rhodecode_clone_uri_ssh_tmpl') or self.DEFAULT_CLONE_URI_SSH
2329 2337
2330 2338 else:
2331 2339 uri_tmpl = rc_config.get(
2332 2340 'rhodecode_clone_uri_tmpl') or self.DEFAULT_CLONE_URI
2333 2341
2334 2342 return get_clone_url(request=request,
2335 2343 uri_tmpl=uri_tmpl,
2336 2344 repo_name=self.repo_name,
2337 2345 repo_id=self.repo_id,
2338 2346 repo_type=self.repo_type,
2339 2347 **override)
2340 2348
2341 2349 def set_state(self, state):
2342 2350 self.repo_state = state
2343 2351 Session().add(self)
2344 2352 #==========================================================================
2345 2353 # SCM PROPERTIES
2346 2354 #==========================================================================
2347 2355
2348 2356 def get_commit(self, commit_id=None, commit_idx=None, pre_load=None, maybe_unreachable=False):
2349 2357 return get_commit_safe(
2350 2358 self.scm_instance(), commit_id, commit_idx, pre_load=pre_load,
2351 2359 maybe_unreachable=maybe_unreachable)
2352 2360
2353 2361 def get_changeset(self, rev=None, pre_load=None):
2354 2362 warnings.warn("Use get_commit", DeprecationWarning)
2355 2363 commit_id = None
2356 2364 commit_idx = None
2357 2365 if isinstance(rev, compat.string_types):
2358 2366 commit_id = rev
2359 2367 else:
2360 2368 commit_idx = rev
2361 2369 return self.get_commit(commit_id=commit_id, commit_idx=commit_idx,
2362 2370 pre_load=pre_load)
2363 2371
2364 2372 def get_landing_commit(self):
2365 2373 """
2366 2374 Returns landing commit, or if that doesn't exist returns the tip
2367 2375 """
2368 2376 _rev_type, _rev = self.landing_rev
2369 2377 commit = self.get_commit(_rev)
2370 2378 if isinstance(commit, EmptyCommit):
2371 2379 return self.get_commit()
2372 2380 return commit
2373 2381
2374 2382 def flush_commit_cache(self):
2375 2383 self.update_commit_cache(cs_cache={'raw_id':'0'})
2376 2384 self.update_commit_cache()
2377 2385
2378 2386 def update_commit_cache(self, cs_cache=None, config=None):
2379 2387 """
2380 2388 Update cache of last commit for repository
2381 2389 cache_keys should be::
2382 2390
2383 2391 source_repo_id
2384 2392 short_id
2385 2393 raw_id
2386 2394 revision
2387 2395 parents
2388 2396 message
2389 2397 date
2390 2398 author
2391 2399 updated_on
2392 2400
2393 2401 """
2394 2402 from rhodecode.lib.vcs.backends.base import BaseChangeset
2395 2403 from rhodecode.lib.vcs.utils.helpers import parse_datetime
2396 2404 empty_date = datetime.datetime.fromtimestamp(0)
2397 2405
2398 2406 if cs_cache is None:
2399 2407 # use no-cache version here
2400 2408 try:
2401 2409 scm_repo = self.scm_instance(cache=False, config=config)
2402 2410 except VCSError:
2403 2411 scm_repo = None
2404 2412 empty = scm_repo is None or scm_repo.is_empty()
2405 2413
2406 2414 if not empty:
2407 2415 cs_cache = scm_repo.get_commit(
2408 2416 pre_load=["author", "date", "message", "parents", "branch"])
2409 2417 else:
2410 2418 cs_cache = EmptyCommit()
2411 2419
2412 2420 if isinstance(cs_cache, BaseChangeset):
2413 2421 cs_cache = cs_cache.__json__()
2414 2422
2415 2423 def is_outdated(new_cs_cache):
2416 2424 if (new_cs_cache['raw_id'] != self.changeset_cache['raw_id'] or
2417 2425 new_cs_cache['revision'] != self.changeset_cache['revision']):
2418 2426 return True
2419 2427 return False
2420 2428
2421 2429 # check if we have maybe already latest cached revision
2422 2430 if is_outdated(cs_cache) or not self.changeset_cache:
2423 2431 _current_datetime = datetime.datetime.utcnow()
2424 2432 last_change = cs_cache.get('date') or _current_datetime
2425 2433 # we check if last update is newer than the new value
2426 2434 # if yes, we use the current timestamp instead. Imagine you get
2427 2435 # old commit pushed 1y ago, we'd set last update 1y to ago.
2428 2436 last_change_timestamp = datetime_to_time(last_change)
2429 2437 current_timestamp = datetime_to_time(last_change)
2430 2438 if last_change_timestamp > current_timestamp and not empty:
2431 2439 cs_cache['date'] = _current_datetime
2432 2440
2433 2441 _date_latest = parse_datetime(cs_cache.get('date') or empty_date)
2434 2442 cs_cache['updated_on'] = time.time()
2435 2443 self.changeset_cache = cs_cache
2436 2444 self.updated_on = last_change
2437 2445 Session().add(self)
2438 2446 Session().commit()
2439 2447
2440 2448 else:
2441 2449 if empty:
2442 2450 cs_cache = EmptyCommit().__json__()
2443 2451 else:
2444 2452 cs_cache = self.changeset_cache
2445 2453
2446 2454 _date_latest = parse_datetime(cs_cache.get('date') or empty_date)
2447 2455
2448 2456 cs_cache['updated_on'] = time.time()
2449 2457 self.changeset_cache = cs_cache
2450 2458 self.updated_on = _date_latest
2451 2459 Session().add(self)
2452 2460 Session().commit()
2453 2461
2454 2462 log.debug('updated repo `%s` with new commit cache %s, and last update_date: %s',
2455 2463 self.repo_name, cs_cache, _date_latest)
2456 2464
2457 2465 @property
2458 2466 def tip(self):
2459 2467 return self.get_commit('tip')
2460 2468
2461 2469 @property
2462 2470 def author(self):
2463 2471 return self.tip.author
2464 2472
2465 2473 @property
2466 2474 def last_change(self):
2467 2475 return self.scm_instance().last_change
2468 2476
2469 2477 def get_comments(self, revisions=None):
2470 2478 """
2471 2479 Returns comments for this repository grouped by revisions
2472 2480
2473 2481 :param revisions: filter query by revisions only
2474 2482 """
2475 2483 cmts = ChangesetComment.query()\
2476 2484 .filter(ChangesetComment.repo == self)
2477 2485 if revisions:
2478 2486 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
2479 2487 grouped = collections.defaultdict(list)
2480 2488 for cmt in cmts.all():
2481 2489 grouped[cmt.revision].append(cmt)
2482 2490 return grouped
2483 2491
2484 2492 def statuses(self, revisions=None):
2485 2493 """
2486 2494 Returns statuses for this repository
2487 2495
2488 2496 :param revisions: list of revisions to get statuses for
2489 2497 """
2490 2498 statuses = ChangesetStatus.query()\
2491 2499 .filter(ChangesetStatus.repo == self)\
2492 2500 .filter(ChangesetStatus.version == 0)
2493 2501
2494 2502 if revisions:
2495 2503 # Try doing the filtering in chunks to avoid hitting limits
2496 2504 size = 500
2497 2505 status_results = []
2498 2506 for chunk in xrange(0, len(revisions), size):
2499 2507 status_results += statuses.filter(
2500 2508 ChangesetStatus.revision.in_(
2501 2509 revisions[chunk: chunk+size])
2502 2510 ).all()
2503 2511 else:
2504 2512 status_results = statuses.all()
2505 2513
2506 2514 grouped = {}
2507 2515
2508 2516 # maybe we have open new pullrequest without a status?
2509 2517 stat = ChangesetStatus.STATUS_UNDER_REVIEW
2510 2518 status_lbl = ChangesetStatus.get_status_lbl(stat)
2511 2519 for pr in PullRequest.query().filter(PullRequest.source_repo == self).all():
2512 2520 for rev in pr.revisions:
2513 2521 pr_id = pr.pull_request_id
2514 2522 pr_repo = pr.target_repo.repo_name
2515 2523 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
2516 2524
2517 2525 for stat in status_results:
2518 2526 pr_id = pr_repo = None
2519 2527 if stat.pull_request:
2520 2528 pr_id = stat.pull_request.pull_request_id
2521 2529 pr_repo = stat.pull_request.target_repo.repo_name
2522 2530 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
2523 2531 pr_id, pr_repo]
2524 2532 return grouped
2525 2533
2526 2534 # ==========================================================================
2527 2535 # SCM CACHE INSTANCE
2528 2536 # ==========================================================================
2529 2537
2530 2538 def scm_instance(self, **kwargs):
2531 2539 import rhodecode
2532 2540
2533 2541 # Passing a config will not hit the cache currently only used
2534 2542 # for repo2dbmapper
2535 2543 config = kwargs.pop('config', None)
2536 2544 cache = kwargs.pop('cache', None)
2537 2545 vcs_full_cache = kwargs.pop('vcs_full_cache', None)
2538 2546 if vcs_full_cache is not None:
2539 2547 # allows override global config
2540 2548 full_cache = vcs_full_cache
2541 2549 else:
2542 2550 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
2543 2551 # if cache is NOT defined use default global, else we have a full
2544 2552 # control over cache behaviour
2545 2553 if cache is None and full_cache and not config:
2546 2554 log.debug('Initializing pure cached instance for %s', self.repo_path)
2547 2555 return self._get_instance_cached()
2548 2556
2549 2557 # cache here is sent to the "vcs server"
2550 2558 return self._get_instance(cache=bool(cache), config=config)
2551 2559
2552 2560 def _get_instance_cached(self):
2553 2561 from rhodecode.lib import rc_cache
2554 2562
2555 2563 cache_namespace_uid = 'cache_repo_instance.{}'.format(self.repo_id)
2556 2564 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
2557 2565 repo_id=self.repo_id)
2558 2566 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
2559 2567
2560 2568 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
2561 2569 def get_instance_cached(repo_id, context_id, _cache_state_uid):
2562 2570 return self._get_instance(repo_state_uid=_cache_state_uid)
2563 2571
2564 2572 # we must use thread scoped cache here,
2565 2573 # because each thread of gevent needs it's own not shared connection and cache
2566 2574 # we also alter `args` so the cache key is individual for every green thread.
2567 2575 inv_context_manager = rc_cache.InvalidationContext(
2568 2576 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace,
2569 2577 thread_scoped=True)
2570 2578 with inv_context_manager as invalidation_context:
2571 2579 cache_state_uid = invalidation_context.cache_data['cache_state_uid']
2572 2580 args = (self.repo_id, inv_context_manager.cache_key, cache_state_uid)
2573 2581
2574 2582 # re-compute and store cache if we get invalidate signal
2575 2583 if invalidation_context.should_invalidate():
2576 2584 instance = get_instance_cached.refresh(*args)
2577 2585 else:
2578 2586 instance = get_instance_cached(*args)
2579 2587
2580 2588 log.debug('Repo instance fetched in %.4fs', inv_context_manager.compute_time)
2581 2589 return instance
2582 2590
2583 2591 def _get_instance(self, cache=True, config=None, repo_state_uid=None):
2584 2592 log.debug('Initializing %s instance `%s` with cache flag set to: %s',
2585 2593 self.repo_type, self.repo_path, cache)
2586 2594 config = config or self._config
2587 2595 custom_wire = {
2588 2596 'cache': cache, # controls the vcs.remote cache
2589 2597 'repo_state_uid': repo_state_uid
2590 2598 }
2591 2599 repo = get_vcs_instance(
2592 2600 repo_path=safe_str(self.repo_full_path),
2593 2601 config=config,
2594 2602 with_wire=custom_wire,
2595 2603 create=False,
2596 2604 _vcs_alias=self.repo_type)
2597 2605 if repo is not None:
2598 2606 repo.count() # cache rebuild
2599 2607 return repo
2600 2608
2601 2609 def get_shadow_repository_path(self, workspace_id):
2602 2610 from rhodecode.lib.vcs.backends.base import BaseRepository
2603 2611 shadow_repo_path = BaseRepository._get_shadow_repository_path(
2604 2612 self.repo_full_path, self.repo_id, workspace_id)
2605 2613 return shadow_repo_path
2606 2614
2607 2615 def __json__(self):
2608 2616 return {'landing_rev': self.landing_rev}
2609 2617
2610 2618 def get_dict(self):
2611 2619
2612 2620 # Since we transformed `repo_name` to a hybrid property, we need to
2613 2621 # keep compatibility with the code which uses `repo_name` field.
2614 2622
2615 2623 result = super(Repository, self).get_dict()
2616 2624 result['repo_name'] = result.pop('_repo_name', None)
2617 2625 return result
2618 2626
2619 2627
2620 2628 class RepoGroup(Base, BaseModel):
2621 2629 __tablename__ = 'groups'
2622 2630 __table_args__ = (
2623 2631 UniqueConstraint('group_name', 'group_parent_id'),
2624 2632 base_table_args,
2625 2633 )
2626 2634 __mapper_args__ = {'order_by': 'group_name'}
2627 2635
2628 2636 CHOICES_SEPARATOR = '/' # used to generate select2 choices for nested groups
2629 2637
2630 2638 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
2631 2639 _group_name = Column("group_name", String(255), nullable=False, unique=True, default=None)
2632 2640 group_name_hash = Column("repo_group_name_hash", String(1024), nullable=False, unique=False)
2633 2641 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
2634 2642 group_description = Column("group_description", String(10000), nullable=True, unique=None, default=None)
2635 2643 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
2636 2644 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
2637 2645 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2638 2646 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
2639 2647 personal = Column('personal', Boolean(), nullable=True, unique=None, default=None)
2640 2648 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) # JSON data
2641 2649
2642 2650 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
2643 2651 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
2644 2652 parent_group = relationship('RepoGroup', remote_side=group_id)
2645 2653 user = relationship('User')
2646 2654 integrations = relationship('Integration', cascade="all, delete-orphan")
2647 2655
2648 2656 # no cascade, set NULL
2649 2657 scope_artifacts = relationship('FileStore', primaryjoin='FileStore.scope_repo_group_id==RepoGroup.group_id')
2650 2658
2651 2659 def __init__(self, group_name='', parent_group=None):
2652 2660 self.group_name = group_name
2653 2661 self.parent_group = parent_group
2654 2662
2655 2663 def __unicode__(self):
2656 2664 return u"<%s('id:%s:%s')>" % (
2657 2665 self.__class__.__name__, self.group_id, self.group_name)
2658 2666
2659 2667 @hybrid_property
2660 2668 def group_name(self):
2661 2669 return self._group_name
2662 2670
2663 2671 @group_name.setter
2664 2672 def group_name(self, value):
2665 2673 self._group_name = value
2666 2674 self.group_name_hash = self.hash_repo_group_name(value)
2667 2675
2668 2676 @classmethod
2669 2677 def _load_changeset_cache(cls, repo_id, changeset_cache_raw):
2670 2678 from rhodecode.lib.vcs.backends.base import EmptyCommit
2671 2679 dummy = EmptyCommit().__json__()
2672 2680 if not changeset_cache_raw:
2673 2681 dummy['source_repo_id'] = repo_id
2674 2682 return json.loads(json.dumps(dummy))
2675 2683
2676 2684 try:
2677 2685 return json.loads(changeset_cache_raw)
2678 2686 except TypeError:
2679 2687 return dummy
2680 2688 except Exception:
2681 2689 log.error(traceback.format_exc())
2682 2690 return dummy
2683 2691
2684 2692 @hybrid_property
2685 2693 def changeset_cache(self):
2686 2694 return self._load_changeset_cache('', self._changeset_cache)
2687 2695
2688 2696 @changeset_cache.setter
2689 2697 def changeset_cache(self, val):
2690 2698 try:
2691 2699 self._changeset_cache = json.dumps(val)
2692 2700 except Exception:
2693 2701 log.error(traceback.format_exc())
2694 2702
2695 2703 @validates('group_parent_id')
2696 2704 def validate_group_parent_id(self, key, val):
2697 2705 """
2698 2706 Check cycle references for a parent group to self
2699 2707 """
2700 2708 if self.group_id and val:
2701 2709 assert val != self.group_id
2702 2710
2703 2711 return val
2704 2712
2705 2713 @hybrid_property
2706 2714 def description_safe(self):
2707 2715 from rhodecode.lib import helpers as h
2708 2716 return h.escape(self.group_description)
2709 2717
2710 2718 @classmethod
2711 2719 def hash_repo_group_name(cls, repo_group_name):
2712 2720 val = remove_formatting(repo_group_name)
2713 2721 val = safe_str(val).lower()
2714 2722 chars = []
2715 2723 for c in val:
2716 2724 if c not in string.ascii_letters:
2717 2725 c = str(ord(c))
2718 2726 chars.append(c)
2719 2727
2720 2728 return ''.join(chars)
2721 2729
2722 2730 @classmethod
2723 2731 def _generate_choice(cls, repo_group):
2724 2732 from webhelpers2.html import literal as _literal
2725 2733 _name = lambda k: _literal(cls.CHOICES_SEPARATOR.join(k))
2726 2734 return repo_group.group_id, _name(repo_group.full_path_splitted)
2727 2735
2728 2736 @classmethod
2729 2737 def groups_choices(cls, groups=None, show_empty_group=True):
2730 2738 if not groups:
2731 2739 groups = cls.query().all()
2732 2740
2733 2741 repo_groups = []
2734 2742 if show_empty_group:
2735 2743 repo_groups = [(-1, u'-- %s --' % _('No parent'))]
2736 2744
2737 2745 repo_groups.extend([cls._generate_choice(x) for x in groups])
2738 2746
2739 2747 repo_groups = sorted(
2740 2748 repo_groups, key=lambda t: t[1].split(cls.CHOICES_SEPARATOR)[0])
2741 2749 return repo_groups
2742 2750
2743 2751 @classmethod
2744 2752 def url_sep(cls):
2745 2753 return URL_SEP
2746 2754
2747 2755 @classmethod
2748 2756 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
2749 2757 if case_insensitive:
2750 2758 gr = cls.query().filter(func.lower(cls.group_name)
2751 2759 == func.lower(group_name))
2752 2760 else:
2753 2761 gr = cls.query().filter(cls.group_name == group_name)
2754 2762 if cache:
2755 2763 name_key = _hash_key(group_name)
2756 2764 gr = gr.options(
2757 2765 FromCache("sql_cache_short", "get_group_%s" % name_key))
2758 2766 return gr.scalar()
2759 2767
2760 2768 @classmethod
2761 2769 def get_user_personal_repo_group(cls, user_id):
2762 2770 user = User.get(user_id)
2763 2771 if user.username == User.DEFAULT_USER:
2764 2772 return None
2765 2773
2766 2774 return cls.query()\
2767 2775 .filter(cls.personal == true()) \
2768 2776 .filter(cls.user == user) \
2769 2777 .order_by(cls.group_id.asc()) \
2770 2778 .first()
2771 2779
2772 2780 @classmethod
2773 2781 def get_all_repo_groups(cls, user_id=Optional(None), group_id=Optional(None),
2774 2782 case_insensitive=True):
2775 2783 q = RepoGroup.query()
2776 2784
2777 2785 if not isinstance(user_id, Optional):
2778 2786 q = q.filter(RepoGroup.user_id == user_id)
2779 2787
2780 2788 if not isinstance(group_id, Optional):
2781 2789 q = q.filter(RepoGroup.group_parent_id == group_id)
2782 2790
2783 2791 if case_insensitive:
2784 2792 q = q.order_by(func.lower(RepoGroup.group_name))
2785 2793 else:
2786 2794 q = q.order_by(RepoGroup.group_name)
2787 2795 return q.all()
2788 2796
2789 2797 @property
2790 2798 def parents(self, parents_recursion_limit=10):
2791 2799 groups = []
2792 2800 if self.parent_group is None:
2793 2801 return groups
2794 2802 cur_gr = self.parent_group
2795 2803 groups.insert(0, cur_gr)
2796 2804 cnt = 0
2797 2805 while 1:
2798 2806 cnt += 1
2799 2807 gr = getattr(cur_gr, 'parent_group', None)
2800 2808 cur_gr = cur_gr.parent_group
2801 2809 if gr is None:
2802 2810 break
2803 2811 if cnt == parents_recursion_limit:
2804 2812 # this will prevent accidental infinit loops
2805 2813 log.error('more than %s parents found for group %s, stopping '
2806 2814 'recursive parent fetching', parents_recursion_limit, self)
2807 2815 break
2808 2816
2809 2817 groups.insert(0, gr)
2810 2818 return groups
2811 2819
2812 2820 @property
2813 2821 def last_commit_cache_update_diff(self):
2814 2822 return time.time() - (safe_int(self.changeset_cache.get('updated_on')) or 0)
2815 2823
2816 2824 @classmethod
2817 2825 def _load_commit_change(cls, last_commit_cache):
2818 2826 from rhodecode.lib.vcs.utils.helpers import parse_datetime
2819 2827 empty_date = datetime.datetime.fromtimestamp(0)
2820 2828 date_latest = last_commit_cache.get('date', empty_date)
2821 2829 try:
2822 2830 return parse_datetime(date_latest)
2823 2831 except Exception:
2824 2832 return empty_date
2825 2833
2826 2834 @property
2827 2835 def last_commit_change(self):
2828 2836 return self._load_commit_change(self.changeset_cache)
2829 2837
2830 2838 @property
2831 2839 def last_db_change(self):
2832 2840 return self.updated_on
2833 2841
2834 2842 @property
2835 2843 def children(self):
2836 2844 return RepoGroup.query().filter(RepoGroup.parent_group == self)
2837 2845
2838 2846 @property
2839 2847 def name(self):
2840 2848 return self.group_name.split(RepoGroup.url_sep())[-1]
2841 2849
2842 2850 @property
2843 2851 def full_path(self):
2844 2852 return self.group_name
2845 2853
2846 2854 @property
2847 2855 def full_path_splitted(self):
2848 2856 return self.group_name.split(RepoGroup.url_sep())
2849 2857
2850 2858 @property
2851 2859 def repositories(self):
2852 2860 return Repository.query()\
2853 2861 .filter(Repository.group == self)\
2854 2862 .order_by(Repository.repo_name)
2855 2863
2856 2864 @property
2857 2865 def repositories_recursive_count(self):
2858 2866 cnt = self.repositories.count()
2859 2867
2860 2868 def children_count(group):
2861 2869 cnt = 0
2862 2870 for child in group.children:
2863 2871 cnt += child.repositories.count()
2864 2872 cnt += children_count(child)
2865 2873 return cnt
2866 2874
2867 2875 return cnt + children_count(self)
2868 2876
2869 2877 def _recursive_objects(self, include_repos=True, include_groups=True):
2870 2878 all_ = []
2871 2879
2872 2880 def _get_members(root_gr):
2873 2881 if include_repos:
2874 2882 for r in root_gr.repositories:
2875 2883 all_.append(r)
2876 2884 childs = root_gr.children.all()
2877 2885 if childs:
2878 2886 for gr in childs:
2879 2887 if include_groups:
2880 2888 all_.append(gr)
2881 2889 _get_members(gr)
2882 2890
2883 2891 root_group = []
2884 2892 if include_groups:
2885 2893 root_group = [self]
2886 2894
2887 2895 _get_members(self)
2888 2896 return root_group + all_
2889 2897
2890 2898 def recursive_groups_and_repos(self):
2891 2899 """
2892 2900 Recursive return all groups, with repositories in those groups
2893 2901 """
2894 2902 return self._recursive_objects()
2895 2903
2896 2904 def recursive_groups(self):
2897 2905 """
2898 2906 Returns all children groups for this group including children of children
2899 2907 """
2900 2908 return self._recursive_objects(include_repos=False)
2901 2909
2902 2910 def recursive_repos(self):
2903 2911 """
2904 2912 Returns all children repositories for this group
2905 2913 """
2906 2914 return self._recursive_objects(include_groups=False)
2907 2915
2908 2916 def get_new_name(self, group_name):
2909 2917 """
2910 2918 returns new full group name based on parent and new name
2911 2919
2912 2920 :param group_name:
2913 2921 """
2914 2922 path_prefix = (self.parent_group.full_path_splitted if
2915 2923 self.parent_group else [])
2916 2924 return RepoGroup.url_sep().join(path_prefix + [group_name])
2917 2925
2918 2926 def update_commit_cache(self, config=None):
2919 2927 """
2920 2928 Update cache of last commit for newest repository inside this repository group.
2921 2929 cache_keys should be::
2922 2930
2923 2931 source_repo_id
2924 2932 short_id
2925 2933 raw_id
2926 2934 revision
2927 2935 parents
2928 2936 message
2929 2937 date
2930 2938 author
2931 2939
2932 2940 """
2933 2941 from rhodecode.lib.vcs.utils.helpers import parse_datetime
2934 2942 empty_date = datetime.datetime.fromtimestamp(0)
2935 2943
2936 2944 def repo_groups_and_repos(root_gr):
2937 2945 for _repo in root_gr.repositories:
2938 2946 yield _repo
2939 2947 for child_group in root_gr.children.all():
2940 2948 yield child_group
2941 2949
2942 2950 latest_repo_cs_cache = {}
2943 2951 for obj in repo_groups_and_repos(self):
2944 2952 repo_cs_cache = obj.changeset_cache
2945 2953 date_latest = latest_repo_cs_cache.get('date', empty_date)
2946 2954 date_current = repo_cs_cache.get('date', empty_date)
2947 2955 current_timestamp = datetime_to_time(parse_datetime(date_latest))
2948 2956 if current_timestamp < datetime_to_time(parse_datetime(date_current)):
2949 2957 latest_repo_cs_cache = repo_cs_cache
2950 2958 if hasattr(obj, 'repo_id'):
2951 2959 latest_repo_cs_cache['source_repo_id'] = obj.repo_id
2952 2960 else:
2953 2961 latest_repo_cs_cache['source_repo_id'] = repo_cs_cache.get('source_repo_id')
2954 2962
2955 2963 _date_latest = parse_datetime(latest_repo_cs_cache.get('date') or empty_date)
2956 2964
2957 2965 latest_repo_cs_cache['updated_on'] = time.time()
2958 2966 self.changeset_cache = latest_repo_cs_cache
2959 2967 self.updated_on = _date_latest
2960 2968 Session().add(self)
2961 2969 Session().commit()
2962 2970
2963 2971 log.debug('updated repo group `%s` with new commit cache %s, and last update_date: %s',
2964 2972 self.group_name, latest_repo_cs_cache, _date_latest)
2965 2973
2966 2974 def permissions(self, with_admins=True, with_owner=True,
2967 2975 expand_from_user_groups=False):
2968 2976 """
2969 2977 Permissions for repository groups
2970 2978 """
2971 2979 _admin_perm = 'group.admin'
2972 2980
2973 2981 owner_row = []
2974 2982 if with_owner:
2975 2983 usr = AttributeDict(self.user.get_dict())
2976 2984 usr.owner_row = True
2977 2985 usr.permission = _admin_perm
2978 2986 owner_row.append(usr)
2979 2987
2980 2988 super_admin_ids = []
2981 2989 super_admin_rows = []
2982 2990 if with_admins:
2983 2991 for usr in User.get_all_super_admins():
2984 2992 super_admin_ids.append(usr.user_id)
2985 2993 # if this admin is also owner, don't double the record
2986 2994 if usr.user_id == owner_row[0].user_id:
2987 2995 owner_row[0].admin_row = True
2988 2996 else:
2989 2997 usr = AttributeDict(usr.get_dict())
2990 2998 usr.admin_row = True
2991 2999 usr.permission = _admin_perm
2992 3000 super_admin_rows.append(usr)
2993 3001
2994 3002 q = UserRepoGroupToPerm.query().filter(UserRepoGroupToPerm.group == self)
2995 3003 q = q.options(joinedload(UserRepoGroupToPerm.group),
2996 3004 joinedload(UserRepoGroupToPerm.user),
2997 3005 joinedload(UserRepoGroupToPerm.permission),)
2998 3006
2999 3007 # get owners and admins and permissions. We do a trick of re-writing
3000 3008 # objects from sqlalchemy to named-tuples due to sqlalchemy session
3001 3009 # has a global reference and changing one object propagates to all
3002 3010 # others. This means if admin is also an owner admin_row that change
3003 3011 # would propagate to both objects
3004 3012 perm_rows = []
3005 3013 for _usr in q.all():
3006 3014 usr = AttributeDict(_usr.user.get_dict())
3007 3015 # if this user is also owner/admin, mark as duplicate record
3008 3016 if usr.user_id == owner_row[0].user_id or usr.user_id in super_admin_ids:
3009 3017 usr.duplicate_perm = True
3010 3018 usr.permission = _usr.permission.permission_name
3011 3019 perm_rows.append(usr)
3012 3020
3013 3021 # filter the perm rows by 'default' first and then sort them by
3014 3022 # admin,write,read,none permissions sorted again alphabetically in
3015 3023 # each group
3016 3024 perm_rows = sorted(perm_rows, key=display_user_sort)
3017 3025
3018 3026 user_groups_rows = []
3019 3027 if expand_from_user_groups:
3020 3028 for ug in self.permission_user_groups(with_members=True):
3021 3029 for user_data in ug.members:
3022 3030 user_groups_rows.append(user_data)
3023 3031
3024 3032 return super_admin_rows + owner_row + perm_rows + user_groups_rows
3025 3033
3026 3034 def permission_user_groups(self, with_members=False):
3027 3035 q = UserGroupRepoGroupToPerm.query()\
3028 3036 .filter(UserGroupRepoGroupToPerm.group == self)
3029 3037 q = q.options(joinedload(UserGroupRepoGroupToPerm.group),
3030 3038 joinedload(UserGroupRepoGroupToPerm.users_group),
3031 3039 joinedload(UserGroupRepoGroupToPerm.permission),)
3032 3040
3033 3041 perm_rows = []
3034 3042 for _user_group in q.all():
3035 3043 entry = AttributeDict(_user_group.users_group.get_dict())
3036 3044 entry.permission = _user_group.permission.permission_name
3037 3045 if with_members:
3038 3046 entry.members = [x.user.get_dict()
3039 3047 for x in _user_group.users_group.members]
3040 3048 perm_rows.append(entry)
3041 3049
3042 3050 perm_rows = sorted(perm_rows, key=display_user_group_sort)
3043 3051 return perm_rows
3044 3052
3045 3053 def get_api_data(self):
3046 3054 """
3047 3055 Common function for generating api data
3048 3056
3049 3057 """
3050 3058 group = self
3051 3059 data = {
3052 3060 'group_id': group.group_id,
3053 3061 'group_name': group.group_name,
3054 3062 'group_description': group.description_safe,
3055 3063 'parent_group': group.parent_group.group_name if group.parent_group else None,
3056 3064 'repositories': [x.repo_name for x in group.repositories],
3057 3065 'owner': group.user.username,
3058 3066 }
3059 3067 return data
3060 3068
3061 3069 def get_dict(self):
3062 3070 # Since we transformed `group_name` to a hybrid property, we need to
3063 3071 # keep compatibility with the code which uses `group_name` field.
3064 3072 result = super(RepoGroup, self).get_dict()
3065 3073 result['group_name'] = result.pop('_group_name', None)
3066 3074 return result
3067 3075
3068 3076
3069 3077 class Permission(Base, BaseModel):
3070 3078 __tablename__ = 'permissions'
3071 3079 __table_args__ = (
3072 3080 Index('p_perm_name_idx', 'permission_name'),
3073 3081 base_table_args,
3074 3082 )
3075 3083
3076 3084 PERMS = [
3077 3085 ('hg.admin', _('RhodeCode Super Administrator')),
3078 3086
3079 3087 ('repository.none', _('Repository no access')),
3080 3088 ('repository.read', _('Repository read access')),
3081 3089 ('repository.write', _('Repository write access')),
3082 3090 ('repository.admin', _('Repository admin access')),
3083 3091
3084 3092 ('group.none', _('Repository group no access')),
3085 3093 ('group.read', _('Repository group read access')),
3086 3094 ('group.write', _('Repository group write access')),
3087 3095 ('group.admin', _('Repository group admin access')),
3088 3096
3089 3097 ('usergroup.none', _('User group no access')),
3090 3098 ('usergroup.read', _('User group read access')),
3091 3099 ('usergroup.write', _('User group write access')),
3092 3100 ('usergroup.admin', _('User group admin access')),
3093 3101
3094 3102 ('branch.none', _('Branch no permissions')),
3095 3103 ('branch.merge', _('Branch access by web merge')),
3096 3104 ('branch.push', _('Branch access by push')),
3097 3105 ('branch.push_force', _('Branch access by push with force')),
3098 3106
3099 3107 ('hg.repogroup.create.false', _('Repository Group creation disabled')),
3100 3108 ('hg.repogroup.create.true', _('Repository Group creation enabled')),
3101 3109
3102 3110 ('hg.usergroup.create.false', _('User Group creation disabled')),
3103 3111 ('hg.usergroup.create.true', _('User Group creation enabled')),
3104 3112
3105 3113 ('hg.create.none', _('Repository creation disabled')),
3106 3114 ('hg.create.repository', _('Repository creation enabled')),
3107 3115 ('hg.create.write_on_repogroup.true', _('Repository creation enabled with write permission to a repository group')),
3108 3116 ('hg.create.write_on_repogroup.false', _('Repository creation disabled with write permission to a repository group')),
3109 3117
3110 3118 ('hg.fork.none', _('Repository forking disabled')),
3111 3119 ('hg.fork.repository', _('Repository forking enabled')),
3112 3120
3113 3121 ('hg.register.none', _('Registration disabled')),
3114 3122 ('hg.register.manual_activate', _('User Registration with manual account activation')),
3115 3123 ('hg.register.auto_activate', _('User Registration with automatic account activation')),
3116 3124
3117 3125 ('hg.password_reset.enabled', _('Password reset enabled')),
3118 3126 ('hg.password_reset.hidden', _('Password reset hidden')),
3119 3127 ('hg.password_reset.disabled', _('Password reset disabled')),
3120 3128
3121 3129 ('hg.extern_activate.manual', _('Manual activation of external account')),
3122 3130 ('hg.extern_activate.auto', _('Automatic activation of external account')),
3123 3131
3124 3132 ('hg.inherit_default_perms.false', _('Inherit object permissions from default user disabled')),
3125 3133 ('hg.inherit_default_perms.true', _('Inherit object permissions from default user enabled')),
3126 3134 ]
3127 3135
3128 3136 # definition of system default permissions for DEFAULT user, created on
3129 3137 # system setup
3130 3138 DEFAULT_USER_PERMISSIONS = [
3131 3139 # object perms
3132 3140 'repository.read',
3133 3141 'group.read',
3134 3142 'usergroup.read',
3135 3143 # branch, for backward compat we need same value as before so forced pushed
3136 3144 'branch.push_force',
3137 3145 # global
3138 3146 'hg.create.repository',
3139 3147 'hg.repogroup.create.false',
3140 3148 'hg.usergroup.create.false',
3141 3149 'hg.create.write_on_repogroup.true',
3142 3150 'hg.fork.repository',
3143 3151 'hg.register.manual_activate',
3144 3152 'hg.password_reset.enabled',
3145 3153 'hg.extern_activate.auto',
3146 3154 'hg.inherit_default_perms.true',
3147 3155 ]
3148 3156
3149 3157 # defines which permissions are more important higher the more important
3150 3158 # Weight defines which permissions are more important.
3151 3159 # The higher number the more important.
3152 3160 PERM_WEIGHTS = {
3153 3161 'repository.none': 0,
3154 3162 'repository.read': 1,
3155 3163 'repository.write': 3,
3156 3164 'repository.admin': 4,
3157 3165
3158 3166 'group.none': 0,
3159 3167 'group.read': 1,
3160 3168 'group.write': 3,
3161 3169 'group.admin': 4,
3162 3170
3163 3171 'usergroup.none': 0,
3164 3172 'usergroup.read': 1,
3165 3173 'usergroup.write': 3,
3166 3174 'usergroup.admin': 4,
3167 3175
3168 3176 'branch.none': 0,
3169 3177 'branch.merge': 1,
3170 3178 'branch.push': 3,
3171 3179 'branch.push_force': 4,
3172 3180
3173 3181 'hg.repogroup.create.false': 0,
3174 3182 'hg.repogroup.create.true': 1,
3175 3183
3176 3184 'hg.usergroup.create.false': 0,
3177 3185 'hg.usergroup.create.true': 1,
3178 3186
3179 3187 'hg.fork.none': 0,
3180 3188 'hg.fork.repository': 1,
3181 3189 'hg.create.none': 0,
3182 3190 'hg.create.repository': 1
3183 3191 }
3184 3192
3185 3193 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3186 3194 permission_name = Column("permission_name", String(255), nullable=True, unique=None, default=None)
3187 3195 permission_longname = Column("permission_longname", String(255), nullable=True, unique=None, default=None)
3188 3196
3189 3197 def __unicode__(self):
3190 3198 return u"<%s('%s:%s')>" % (
3191 3199 self.__class__.__name__, self.permission_id, self.permission_name
3192 3200 )
3193 3201
3194 3202 @classmethod
3195 3203 def get_by_key(cls, key):
3196 3204 return cls.query().filter(cls.permission_name == key).scalar()
3197 3205
3198 3206 @classmethod
3199 3207 def get_default_repo_perms(cls, user_id, repo_id=None):
3200 3208 q = Session().query(UserRepoToPerm, Repository, Permission)\
3201 3209 .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
3202 3210 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
3203 3211 .filter(UserRepoToPerm.user_id == user_id)
3204 3212 if repo_id:
3205 3213 q = q.filter(UserRepoToPerm.repository_id == repo_id)
3206 3214 return q.all()
3207 3215
3208 3216 @classmethod
3209 3217 def get_default_repo_branch_perms(cls, user_id, repo_id=None):
3210 3218 q = Session().query(UserToRepoBranchPermission, UserRepoToPerm, Permission) \
3211 3219 .join(
3212 3220 Permission,
3213 3221 UserToRepoBranchPermission.permission_id == Permission.permission_id) \
3214 3222 .join(
3215 3223 UserRepoToPerm,
3216 3224 UserToRepoBranchPermission.rule_to_perm_id == UserRepoToPerm.repo_to_perm_id) \
3217 3225 .filter(UserRepoToPerm.user_id == user_id)
3218 3226
3219 3227 if repo_id:
3220 3228 q = q.filter(UserToRepoBranchPermission.repository_id == repo_id)
3221 3229 return q.order_by(UserToRepoBranchPermission.rule_order).all()
3222 3230
3223 3231 @classmethod
3224 3232 def get_default_repo_perms_from_user_group(cls, user_id, repo_id=None):
3225 3233 q = Session().query(UserGroupRepoToPerm, Repository, Permission)\
3226 3234 .join(
3227 3235 Permission,
3228 3236 UserGroupRepoToPerm.permission_id == Permission.permission_id)\
3229 3237 .join(
3230 3238 Repository,
3231 3239 UserGroupRepoToPerm.repository_id == Repository.repo_id)\
3232 3240 .join(
3233 3241 UserGroup,
3234 3242 UserGroupRepoToPerm.users_group_id ==
3235 3243 UserGroup.users_group_id)\
3236 3244 .join(
3237 3245 UserGroupMember,
3238 3246 UserGroupRepoToPerm.users_group_id ==
3239 3247 UserGroupMember.users_group_id)\
3240 3248 .filter(
3241 3249 UserGroupMember.user_id == user_id,
3242 3250 UserGroup.users_group_active == true())
3243 3251 if repo_id:
3244 3252 q = q.filter(UserGroupRepoToPerm.repository_id == repo_id)
3245 3253 return q.all()
3246 3254
3247 3255 @classmethod
3248 3256 def get_default_repo_branch_perms_from_user_group(cls, user_id, repo_id=None):
3249 3257 q = Session().query(UserGroupToRepoBranchPermission, UserGroupRepoToPerm, Permission) \
3250 3258 .join(
3251 3259 Permission,
3252 3260 UserGroupToRepoBranchPermission.permission_id == Permission.permission_id) \
3253 3261 .join(
3254 3262 UserGroupRepoToPerm,
3255 3263 UserGroupToRepoBranchPermission.rule_to_perm_id == UserGroupRepoToPerm.users_group_to_perm_id) \
3256 3264 .join(
3257 3265 UserGroup,
3258 3266 UserGroupRepoToPerm.users_group_id == UserGroup.users_group_id) \
3259 3267 .join(
3260 3268 UserGroupMember,
3261 3269 UserGroupRepoToPerm.users_group_id == UserGroupMember.users_group_id) \
3262 3270 .filter(
3263 3271 UserGroupMember.user_id == user_id,
3264 3272 UserGroup.users_group_active == true())
3265 3273
3266 3274 if repo_id:
3267 3275 q = q.filter(UserGroupToRepoBranchPermission.repository_id == repo_id)
3268 3276 return q.order_by(UserGroupToRepoBranchPermission.rule_order).all()
3269 3277
3270 3278 @classmethod
3271 3279 def get_default_group_perms(cls, user_id, repo_group_id=None):
3272 3280 q = Session().query(UserRepoGroupToPerm, RepoGroup, Permission)\
3273 3281 .join(
3274 3282 Permission,
3275 3283 UserRepoGroupToPerm.permission_id == Permission.permission_id)\
3276 3284 .join(
3277 3285 RepoGroup,
3278 3286 UserRepoGroupToPerm.group_id == RepoGroup.group_id)\
3279 3287 .filter(UserRepoGroupToPerm.user_id == user_id)
3280 3288 if repo_group_id:
3281 3289 q = q.filter(UserRepoGroupToPerm.group_id == repo_group_id)
3282 3290 return q.all()
3283 3291
3284 3292 @classmethod
3285 3293 def get_default_group_perms_from_user_group(
3286 3294 cls, user_id, repo_group_id=None):
3287 3295 q = Session().query(UserGroupRepoGroupToPerm, RepoGroup, Permission)\
3288 3296 .join(
3289 3297 Permission,
3290 3298 UserGroupRepoGroupToPerm.permission_id ==
3291 3299 Permission.permission_id)\
3292 3300 .join(
3293 3301 RepoGroup,
3294 3302 UserGroupRepoGroupToPerm.group_id == RepoGroup.group_id)\
3295 3303 .join(
3296 3304 UserGroup,
3297 3305 UserGroupRepoGroupToPerm.users_group_id ==
3298 3306 UserGroup.users_group_id)\
3299 3307 .join(
3300 3308 UserGroupMember,
3301 3309 UserGroupRepoGroupToPerm.users_group_id ==
3302 3310 UserGroupMember.users_group_id)\
3303 3311 .filter(
3304 3312 UserGroupMember.user_id == user_id,
3305 3313 UserGroup.users_group_active == true())
3306 3314 if repo_group_id:
3307 3315 q = q.filter(UserGroupRepoGroupToPerm.group_id == repo_group_id)
3308 3316 return q.all()
3309 3317
3310 3318 @classmethod
3311 3319 def get_default_user_group_perms(cls, user_id, user_group_id=None):
3312 3320 q = Session().query(UserUserGroupToPerm, UserGroup, Permission)\
3313 3321 .join((Permission, UserUserGroupToPerm.permission_id == Permission.permission_id))\
3314 3322 .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
3315 3323 .filter(UserUserGroupToPerm.user_id == user_id)
3316 3324 if user_group_id:
3317 3325 q = q.filter(UserUserGroupToPerm.user_group_id == user_group_id)
3318 3326 return q.all()
3319 3327
3320 3328 @classmethod
3321 3329 def get_default_user_group_perms_from_user_group(
3322 3330 cls, user_id, user_group_id=None):
3323 3331 TargetUserGroup = aliased(UserGroup, name='target_user_group')
3324 3332 q = Session().query(UserGroupUserGroupToPerm, UserGroup, Permission)\
3325 3333 .join(
3326 3334 Permission,
3327 3335 UserGroupUserGroupToPerm.permission_id ==
3328 3336 Permission.permission_id)\
3329 3337 .join(
3330 3338 TargetUserGroup,
3331 3339 UserGroupUserGroupToPerm.target_user_group_id ==
3332 3340 TargetUserGroup.users_group_id)\
3333 3341 .join(
3334 3342 UserGroup,
3335 3343 UserGroupUserGroupToPerm.user_group_id ==
3336 3344 UserGroup.users_group_id)\
3337 3345 .join(
3338 3346 UserGroupMember,
3339 3347 UserGroupUserGroupToPerm.user_group_id ==
3340 3348 UserGroupMember.users_group_id)\
3341 3349 .filter(
3342 3350 UserGroupMember.user_id == user_id,
3343 3351 UserGroup.users_group_active == true())
3344 3352 if user_group_id:
3345 3353 q = q.filter(
3346 3354 UserGroupUserGroupToPerm.user_group_id == user_group_id)
3347 3355
3348 3356 return q.all()
3349 3357
3350 3358
3351 3359 class UserRepoToPerm(Base, BaseModel):
3352 3360 __tablename__ = 'repo_to_perm'
3353 3361 __table_args__ = (
3354 3362 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
3355 3363 base_table_args
3356 3364 )
3357 3365
3358 3366 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3359 3367 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
3360 3368 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3361 3369 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
3362 3370
3363 3371 user = relationship('User')
3364 3372 repository = relationship('Repository')
3365 3373 permission = relationship('Permission')
3366 3374
3367 3375 branch_perm_entry = relationship('UserToRepoBranchPermission', cascade="all, delete-orphan", lazy='joined')
3368 3376
3369 3377 @classmethod
3370 3378 def create(cls, user, repository, permission):
3371 3379 n = cls()
3372 3380 n.user = user
3373 3381 n.repository = repository
3374 3382 n.permission = permission
3375 3383 Session().add(n)
3376 3384 return n
3377 3385
3378 3386 def __unicode__(self):
3379 3387 return u'<%s => %s >' % (self.user, self.repository)
3380 3388
3381 3389
3382 3390 class UserUserGroupToPerm(Base, BaseModel):
3383 3391 __tablename__ = 'user_user_group_to_perm'
3384 3392 __table_args__ = (
3385 3393 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
3386 3394 base_table_args
3387 3395 )
3388 3396
3389 3397 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3390 3398 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
3391 3399 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3392 3400 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3393 3401
3394 3402 user = relationship('User')
3395 3403 user_group = relationship('UserGroup')
3396 3404 permission = relationship('Permission')
3397 3405
3398 3406 @classmethod
3399 3407 def create(cls, user, user_group, permission):
3400 3408 n = cls()
3401 3409 n.user = user
3402 3410 n.user_group = user_group
3403 3411 n.permission = permission
3404 3412 Session().add(n)
3405 3413 return n
3406 3414
3407 3415 def __unicode__(self):
3408 3416 return u'<%s => %s >' % (self.user, self.user_group)
3409 3417
3410 3418
3411 3419 class UserToPerm(Base, BaseModel):
3412 3420 __tablename__ = 'user_to_perm'
3413 3421 __table_args__ = (
3414 3422 UniqueConstraint('user_id', 'permission_id'),
3415 3423 base_table_args
3416 3424 )
3417 3425
3418 3426 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3419 3427 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
3420 3428 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3421 3429
3422 3430 user = relationship('User')
3423 3431 permission = relationship('Permission', lazy='joined')
3424 3432
3425 3433 def __unicode__(self):
3426 3434 return u'<%s => %s >' % (self.user, self.permission)
3427 3435
3428 3436
3429 3437 class UserGroupRepoToPerm(Base, BaseModel):
3430 3438 __tablename__ = 'users_group_repo_to_perm'
3431 3439 __table_args__ = (
3432 3440 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
3433 3441 base_table_args
3434 3442 )
3435 3443
3436 3444 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3437 3445 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3438 3446 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3439 3447 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
3440 3448
3441 3449 users_group = relationship('UserGroup')
3442 3450 permission = relationship('Permission')
3443 3451 repository = relationship('Repository')
3444 3452 user_group_branch_perms = relationship('UserGroupToRepoBranchPermission', cascade='all')
3445 3453
3446 3454 @classmethod
3447 3455 def create(cls, users_group, repository, permission):
3448 3456 n = cls()
3449 3457 n.users_group = users_group
3450 3458 n.repository = repository
3451 3459 n.permission = permission
3452 3460 Session().add(n)
3453 3461 return n
3454 3462
3455 3463 def __unicode__(self):
3456 3464 return u'<UserGroupRepoToPerm:%s => %s >' % (self.users_group, self.repository)
3457 3465
3458 3466
3459 3467 class UserGroupUserGroupToPerm(Base, BaseModel):
3460 3468 __tablename__ = 'user_group_user_group_to_perm'
3461 3469 __table_args__ = (
3462 3470 UniqueConstraint('target_user_group_id', 'user_group_id', 'permission_id'),
3463 3471 CheckConstraint('target_user_group_id != user_group_id'),
3464 3472 base_table_args
3465 3473 )
3466 3474
3467 3475 user_group_user_group_to_perm_id = Column("user_group_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3468 3476 target_user_group_id = Column("target_user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3469 3477 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3470 3478 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3471 3479
3472 3480 target_user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
3473 3481 user_group = relationship('UserGroup', primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
3474 3482 permission = relationship('Permission')
3475 3483
3476 3484 @classmethod
3477 3485 def create(cls, target_user_group, user_group, permission):
3478 3486 n = cls()
3479 3487 n.target_user_group = target_user_group
3480 3488 n.user_group = user_group
3481 3489 n.permission = permission
3482 3490 Session().add(n)
3483 3491 return n
3484 3492
3485 3493 def __unicode__(self):
3486 3494 return u'<UserGroupUserGroup:%s => %s >' % (self.target_user_group, self.user_group)
3487 3495
3488 3496
3489 3497 class UserGroupToPerm(Base, BaseModel):
3490 3498 __tablename__ = 'users_group_to_perm'
3491 3499 __table_args__ = (
3492 3500 UniqueConstraint('users_group_id', 'permission_id',),
3493 3501 base_table_args
3494 3502 )
3495 3503
3496 3504 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3497 3505 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3498 3506 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3499 3507
3500 3508 users_group = relationship('UserGroup')
3501 3509 permission = relationship('Permission')
3502 3510
3503 3511
3504 3512 class UserRepoGroupToPerm(Base, BaseModel):
3505 3513 __tablename__ = 'user_repo_group_to_perm'
3506 3514 __table_args__ = (
3507 3515 UniqueConstraint('user_id', 'group_id', 'permission_id'),
3508 3516 base_table_args
3509 3517 )
3510 3518
3511 3519 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3512 3520 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
3513 3521 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
3514 3522 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3515 3523
3516 3524 user = relationship('User')
3517 3525 group = relationship('RepoGroup')
3518 3526 permission = relationship('Permission')
3519 3527
3520 3528 @classmethod
3521 3529 def create(cls, user, repository_group, permission):
3522 3530 n = cls()
3523 3531 n.user = user
3524 3532 n.group = repository_group
3525 3533 n.permission = permission
3526 3534 Session().add(n)
3527 3535 return n
3528 3536
3529 3537
3530 3538 class UserGroupRepoGroupToPerm(Base, BaseModel):
3531 3539 __tablename__ = 'users_group_repo_group_to_perm'
3532 3540 __table_args__ = (
3533 3541 UniqueConstraint('users_group_id', 'group_id'),
3534 3542 base_table_args
3535 3543 )
3536 3544
3537 3545 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3538 3546 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
3539 3547 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
3540 3548 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
3541 3549
3542 3550 users_group = relationship('UserGroup')
3543 3551 permission = relationship('Permission')
3544 3552 group = relationship('RepoGroup')
3545 3553
3546 3554 @classmethod
3547 3555 def create(cls, user_group, repository_group, permission):
3548 3556 n = cls()
3549 3557 n.users_group = user_group
3550 3558 n.group = repository_group
3551 3559 n.permission = permission
3552 3560 Session().add(n)
3553 3561 return n
3554 3562
3555 3563 def __unicode__(self):
3556 3564 return u'<UserGroupRepoGroupToPerm:%s => %s >' % (self.users_group, self.group)
3557 3565
3558 3566
3559 3567 class Statistics(Base, BaseModel):
3560 3568 __tablename__ = 'statistics'
3561 3569 __table_args__ = (
3562 3570 base_table_args
3563 3571 )
3564 3572
3565 3573 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3566 3574 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
3567 3575 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
3568 3576 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
3569 3577 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
3570 3578 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
3571 3579
3572 3580 repository = relationship('Repository', single_parent=True)
3573 3581
3574 3582
3575 3583 class UserFollowing(Base, BaseModel):
3576 3584 __tablename__ = 'user_followings'
3577 3585 __table_args__ = (
3578 3586 UniqueConstraint('user_id', 'follows_repository_id'),
3579 3587 UniqueConstraint('user_id', 'follows_user_id'),
3580 3588 base_table_args
3581 3589 )
3582 3590
3583 3591 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3584 3592 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
3585 3593 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
3586 3594 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
3587 3595 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
3588 3596
3589 3597 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
3590 3598
3591 3599 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
3592 3600 follows_repository = relationship('Repository', order_by='Repository.repo_name')
3593 3601
3594 3602 @classmethod
3595 3603 def get_repo_followers(cls, repo_id):
3596 3604 return cls.query().filter(cls.follows_repo_id == repo_id)
3597 3605
3598 3606
3599 3607 class CacheKey(Base, BaseModel):
3600 3608 __tablename__ = 'cache_invalidation'
3601 3609 __table_args__ = (
3602 3610 UniqueConstraint('cache_key'),
3603 3611 Index('key_idx', 'cache_key'),
3604 3612 base_table_args,
3605 3613 )
3606 3614
3607 3615 CACHE_TYPE_FEED = 'FEED'
3608 3616
3609 3617 # namespaces used to register process/thread aware caches
3610 3618 REPO_INVALIDATION_NAMESPACE = 'repo_cache:{repo_id}'
3611 3619 SETTINGS_INVALIDATION_NAMESPACE = 'system_settings'
3612 3620
3613 3621 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
3614 3622 cache_key = Column("cache_key", String(255), nullable=True, unique=None, default=None)
3615 3623 cache_args = Column("cache_args", String(255), nullable=True, unique=None, default=None)
3616 3624 cache_state_uid = Column("cache_state_uid", String(255), nullable=True, unique=None, default=None)
3617 3625 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
3618 3626
3619 3627 def __init__(self, cache_key, cache_args='', cache_state_uid=None):
3620 3628 self.cache_key = cache_key
3621 3629 self.cache_args = cache_args
3622 3630 self.cache_active = False
3623 3631 # first key should be same for all entries, since all workers should share it
3624 3632 self.cache_state_uid = cache_state_uid or self.generate_new_state_uid()
3625 3633
3626 3634 def __unicode__(self):
3627 3635 return u"<%s('%s:%s[%s]')>" % (
3628 3636 self.__class__.__name__,
3629 3637 self.cache_id, self.cache_key, self.cache_active)
3630 3638
3631 3639 def _cache_key_partition(self):
3632 3640 prefix, repo_name, suffix = self.cache_key.partition(self.cache_args)
3633 3641 return prefix, repo_name, suffix
3634 3642
3635 3643 def get_prefix(self):
3636 3644 """
3637 3645 Try to extract prefix from existing cache key. The key could consist
3638 3646 of prefix, repo_name, suffix
3639 3647 """
3640 3648 # this returns prefix, repo_name, suffix
3641 3649 return self._cache_key_partition()[0]
3642 3650
3643 3651 def get_suffix(self):
3644 3652 """
3645 3653 get suffix that might have been used in _get_cache_key to
3646 3654 generate self.cache_key. Only used for informational purposes
3647 3655 in repo_edit.mako.
3648 3656 """
3649 3657 # prefix, repo_name, suffix
3650 3658 return self._cache_key_partition()[2]
3651 3659
3652 3660 @classmethod
3653 3661 def generate_new_state_uid(cls, based_on=None):
3654 3662 if based_on:
3655 3663 return str(uuid.uuid5(uuid.NAMESPACE_URL, safe_str(based_on)))
3656 3664 else:
3657 3665 return str(uuid.uuid4())
3658 3666
3659 3667 @classmethod
3660 3668 def delete_all_cache(cls):
3661 3669 """
3662 3670 Delete all cache keys from database.
3663 3671 Should only be run when all instances are down and all entries
3664 3672 thus stale.
3665 3673 """
3666 3674 cls.query().delete()
3667 3675 Session().commit()
3668 3676
3669 3677 @classmethod
3670 3678 def set_invalidate(cls, cache_uid, delete=False):
3671 3679 """
3672 3680 Mark all caches of a repo as invalid in the database.
3673 3681 """
3674 3682
3675 3683 try:
3676 3684 qry = Session().query(cls).filter(cls.cache_args == cache_uid)
3677 3685 if delete:
3678 3686 qry.delete()
3679 3687 log.debug('cache objects deleted for cache args %s',
3680 3688 safe_str(cache_uid))
3681 3689 else:
3682 3690 qry.update({"cache_active": False,
3683 3691 "cache_state_uid": cls.generate_new_state_uid()})
3684 3692 log.debug('cache objects marked as invalid for cache args %s',
3685 3693 safe_str(cache_uid))
3686 3694
3687 3695 Session().commit()
3688 3696 except Exception:
3689 3697 log.exception(
3690 3698 'Cache key invalidation failed for cache args %s',
3691 3699 safe_str(cache_uid))
3692 3700 Session().rollback()
3693 3701
3694 3702 @classmethod
3695 3703 def get_active_cache(cls, cache_key):
3696 3704 inv_obj = cls.query().filter(cls.cache_key == cache_key).scalar()
3697 3705 if inv_obj:
3698 3706 return inv_obj
3699 3707 return None
3700 3708
3701 3709 @classmethod
3702 3710 def get_namespace_map(cls, namespace):
3703 3711 return {
3704 3712 x.cache_key: x
3705 3713 for x in cls.query().filter(cls.cache_args == namespace)}
3706 3714
3707 3715
3708 3716 class ChangesetComment(Base, BaseModel):
3709 3717 __tablename__ = 'changeset_comments'
3710 3718 __table_args__ = (
3711 3719 Index('cc_revision_idx', 'revision'),
3712 3720 base_table_args,
3713 3721 )
3714 3722
3715 3723 COMMENT_OUTDATED = u'comment_outdated'
3716 3724 COMMENT_TYPE_NOTE = u'note'
3717 3725 COMMENT_TYPE_TODO = u'todo'
3718 3726 COMMENT_TYPES = [COMMENT_TYPE_NOTE, COMMENT_TYPE_TODO]
3719 3727
3720 3728 OP_IMMUTABLE = u'immutable'
3721 3729 OP_CHANGEABLE = u'changeable'
3722 3730
3723 3731 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
3724 3732 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
3725 3733 revision = Column('revision', String(40), nullable=True)
3726 3734 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
3727 3735 pull_request_version_id = Column("pull_request_version_id", Integer(), ForeignKey('pull_request_versions.pull_request_version_id'), nullable=True)
3728 3736 line_no = Column('line_no', Unicode(10), nullable=True)
3729 3737 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
3730 3738 f_path = Column('f_path', Unicode(1000), nullable=True)
3731 3739 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
3732 3740 text = Column('text', UnicodeText().with_variant(UnicodeText(25000), 'mysql'), nullable=False)
3733 3741 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
3734 3742 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
3735 3743 renderer = Column('renderer', Unicode(64), nullable=True)
3736 3744 display_state = Column('display_state', Unicode(128), nullable=True)
3737 3745 immutable_state = Column('immutable_state', Unicode(128), nullable=True, default=OP_CHANGEABLE)
3738 3746
3739 3747 comment_type = Column('comment_type', Unicode(128), nullable=True, default=COMMENT_TYPE_NOTE)
3740 3748 resolved_comment_id = Column('resolved_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'), nullable=True)
3741 3749
3742 3750 resolved_comment = relationship('ChangesetComment', remote_side=comment_id, back_populates='resolved_by')
3743 3751 resolved_by = relationship('ChangesetComment', back_populates='resolved_comment')
3744 3752
3745 3753 author = relationship('User', lazy='joined')
3746 3754 repo = relationship('Repository')
3747 3755 status_change = relationship('ChangesetStatus', cascade="all, delete-orphan", lazy='joined')
3748 3756 pull_request = relationship('PullRequest', lazy='joined')
3749 3757 pull_request_version = relationship('PullRequestVersion')
3750 3758
3751 3759 @classmethod
3752 3760 def get_users(cls, revision=None, pull_request_id=None):
3753 3761 """
3754 3762 Returns user associated with this ChangesetComment. ie those
3755 3763 who actually commented
3756 3764
3757 3765 :param cls:
3758 3766 :param revision:
3759 3767 """
3760 3768 q = Session().query(User)\
3761 3769 .join(ChangesetComment.author)
3762 3770 if revision:
3763 3771 q = q.filter(cls.revision == revision)
3764 3772 elif pull_request_id:
3765 3773 q = q.filter(cls.pull_request_id == pull_request_id)
3766 3774 return q.all()
3767 3775
3768 3776 @classmethod
3769 3777 def get_index_from_version(cls, pr_version, versions):
3770 3778 num_versions = [x.pull_request_version_id for x in versions]
3771 3779 try:
3772 3780 return num_versions.index(pr_version) +1
3773 3781 except (IndexError, ValueError):
3774 3782 return
3775 3783
3776 3784 @property
3777 3785 def outdated(self):
3778 3786 return self.display_state == self.COMMENT_OUTDATED
3779 3787
3780 3788 @property
3781 3789 def immutable(self):
3782 3790 return self.immutable_state == self.OP_IMMUTABLE
3783 3791
3784 3792 def outdated_at_version(self, version):
3785 3793 """
3786 3794 Checks if comment is outdated for given pull request version
3787 3795 """
3788 3796 return self.outdated and self.pull_request_version_id != version
3789 3797
3790 3798 def older_than_version(self, version):
3791 3799 """
3792 3800 Checks if comment is made from previous version than given
3793 3801 """
3794 3802 if version is None:
3795 3803 return self.pull_request_version_id is not None
3796 3804
3797 3805 return self.pull_request_version_id < version
3798 3806
3799 3807 @property
3800 3808 def resolved(self):
3801 3809 return self.resolved_by[0] if self.resolved_by else None
3802 3810
3803 3811 @property
3804 3812 def is_todo(self):
3805 3813 return self.comment_type == self.COMMENT_TYPE_TODO
3806 3814
3807 3815 @property
3808 3816 def is_inline(self):
3809 3817 return self.line_no and self.f_path
3810 3818
3811 3819 def get_index_version(self, versions):
3812 3820 return self.get_index_from_version(
3813 3821 self.pull_request_version_id, versions)
3814 3822
3815 3823 def __repr__(self):
3816 3824 if self.comment_id:
3817 3825 return '<DB:Comment #%s>' % self.comment_id
3818 3826 else:
3819 3827 return '<DB:Comment at %#x>' % id(self)
3820 3828
3821 3829 def get_api_data(self):
3822 3830 comment = self
3823 3831 data = {
3824 3832 'comment_id': comment.comment_id,
3825 3833 'comment_type': comment.comment_type,
3826 3834 'comment_text': comment.text,
3827 3835 'comment_status': comment.status_change,
3828 3836 'comment_f_path': comment.f_path,
3829 3837 'comment_lineno': comment.line_no,
3830 3838 'comment_author': comment.author,
3831 3839 'comment_created_on': comment.created_on,
3832 3840 'comment_resolved_by': self.resolved,
3833 3841 'comment_commit_id': comment.revision,
3834 3842 'comment_pull_request_id': comment.pull_request_id,
3835 3843 }
3836 3844 return data
3837 3845
3838 3846 def __json__(self):
3839 3847 data = dict()
3840 3848 data.update(self.get_api_data())
3841 3849 return data
3842 3850
3843 3851
3844 3852 class ChangesetStatus(Base, BaseModel):
3845 3853 __tablename__ = 'changeset_statuses'
3846 3854 __table_args__ = (
3847 3855 Index('cs_revision_idx', 'revision'),
3848 3856 Index('cs_version_idx', 'version'),
3849 3857 UniqueConstraint('repo_id', 'revision', 'version'),
3850 3858 base_table_args
3851 3859 )
3852 3860
3853 3861 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
3854 3862 STATUS_APPROVED = 'approved'
3855 3863 STATUS_REJECTED = 'rejected'
3856 3864 STATUS_UNDER_REVIEW = 'under_review'
3857 3865
3858 3866 STATUSES = [
3859 3867 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
3860 3868 (STATUS_APPROVED, _("Approved")),
3861 3869 (STATUS_REJECTED, _("Rejected")),
3862 3870 (STATUS_UNDER_REVIEW, _("Under Review")),
3863 3871 ]
3864 3872
3865 3873 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
3866 3874 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
3867 3875 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
3868 3876 revision = Column('revision', String(40), nullable=False)
3869 3877 status = Column('status', String(128), nullable=False, default=DEFAULT)
3870 3878 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
3871 3879 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
3872 3880 version = Column('version', Integer(), nullable=False, default=0)
3873 3881 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
3874 3882
3875 3883 author = relationship('User', lazy='joined')
3876 3884 repo = relationship('Repository')
3877 3885 comment = relationship('ChangesetComment', lazy='joined')
3878 3886 pull_request = relationship('PullRequest', lazy='joined')
3879 3887
3880 3888 def __unicode__(self):
3881 3889 return u"<%s('%s[v%s]:%s')>" % (
3882 3890 self.__class__.__name__,
3883 3891 self.status, self.version, self.author
3884 3892 )
3885 3893
3886 3894 @classmethod
3887 3895 def get_status_lbl(cls, value):
3888 3896 return dict(cls.STATUSES).get(value)
3889 3897
3890 3898 @property
3891 3899 def status_lbl(self):
3892 3900 return ChangesetStatus.get_status_lbl(self.status)
3893 3901
3894 3902 def get_api_data(self):
3895 3903 status = self
3896 3904 data = {
3897 3905 'status_id': status.changeset_status_id,
3898 3906 'status': status.status,
3899 3907 }
3900 3908 return data
3901 3909
3902 3910 def __json__(self):
3903 3911 data = dict()
3904 3912 data.update(self.get_api_data())
3905 3913 return data
3906 3914
3907 3915
3908 3916 class _SetState(object):
3909 3917 """
3910 3918 Context processor allowing changing state for sensitive operation such as
3911 3919 pull request update or merge
3912 3920 """
3913 3921
3914 3922 def __init__(self, pull_request, pr_state, back_state=None):
3915 3923 self._pr = pull_request
3916 3924 self._org_state = back_state or pull_request.pull_request_state
3917 3925 self._pr_state = pr_state
3918 3926 self._current_state = None
3919 3927
3920 3928 def __enter__(self):
3921 3929 log.debug('StateLock: entering set state context of pr %s, setting state to: `%s`',
3922 3930 self._pr, self._pr_state)
3923 3931 self.set_pr_state(self._pr_state)
3924 3932 return self
3925 3933
3926 3934 def __exit__(self, exc_type, exc_val, exc_tb):
3927 3935 if exc_val is not None:
3928 3936 log.error(traceback.format_exc(exc_tb))
3929 3937 return None
3930 3938
3931 3939 self.set_pr_state(self._org_state)
3932 3940 log.debug('StateLock: exiting set state context of pr %s, setting state to: `%s`',
3933 3941 self._pr, self._org_state)
3934 3942
3935 3943 @property
3936 3944 def state(self):
3937 3945 return self._current_state
3938 3946
3939 3947 def set_pr_state(self, pr_state):
3940 3948 try:
3941 3949 self._pr.pull_request_state = pr_state
3942 3950 Session().add(self._pr)
3943 3951 Session().commit()
3944 3952 self._current_state = pr_state
3945 3953 except Exception:
3946 3954 log.exception('Failed to set PullRequest %s state to %s', self._pr, pr_state)
3947 3955 raise
3948 3956
3949 3957
3950 3958 class _PullRequestBase(BaseModel):
3951 3959 """
3952 3960 Common attributes of pull request and version entries.
3953 3961 """
3954 3962
3955 3963 # .status values
3956 3964 STATUS_NEW = u'new'
3957 3965 STATUS_OPEN = u'open'
3958 3966 STATUS_CLOSED = u'closed'
3959 3967
3960 3968 # available states
3961 3969 STATE_CREATING = u'creating'
3962 3970 STATE_UPDATING = u'updating'
3963 3971 STATE_MERGING = u'merging'
3964 3972 STATE_CREATED = u'created'
3965 3973
3966 3974 title = Column('title', Unicode(255), nullable=True)
3967 3975 description = Column(
3968 3976 'description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'),
3969 3977 nullable=True)
3970 3978 description_renderer = Column('description_renderer', Unicode(64), nullable=True)
3971 3979
3972 3980 # new/open/closed status of pull request (not approve/reject/etc)
3973 3981 status = Column('status', Unicode(255), nullable=False, default=STATUS_NEW)
3974 3982 created_on = Column(
3975 3983 'created_on', DateTime(timezone=False), nullable=False,
3976 3984 default=datetime.datetime.now)
3977 3985 updated_on = Column(
3978 3986 'updated_on', DateTime(timezone=False), nullable=False,
3979 3987 default=datetime.datetime.now)
3980 3988
3981 3989 pull_request_state = Column("pull_request_state", String(255), nullable=True)
3982 3990
3983 3991 @declared_attr
3984 3992 def user_id(cls):
3985 3993 return Column(
3986 3994 "user_id", Integer(), ForeignKey('users.user_id'), nullable=False,
3987 3995 unique=None)
3988 3996
3989 3997 # 500 revisions max
3990 3998 _revisions = Column(
3991 3999 'revisions', UnicodeText().with_variant(UnicodeText(20500), 'mysql'))
3992 4000
3993 4001 common_ancestor_id = Column('common_ancestor_id', Unicode(255), nullable=True)
3994 4002
3995 4003 @declared_attr
3996 4004 def source_repo_id(cls):
3997 4005 # TODO: dan: rename column to source_repo_id
3998 4006 return Column(
3999 4007 'org_repo_id', Integer(), ForeignKey('repositories.repo_id'),
4000 4008 nullable=False)
4001 4009
4002 4010 _source_ref = Column('org_ref', Unicode(255), nullable=False)
4003 4011
4004 4012 @hybrid_property
4005 4013 def source_ref(self):
4006 4014 return self._source_ref
4007 4015
4008 4016 @source_ref.setter
4009 4017 def source_ref(self, val):
4010 4018 parts = (val or '').split(':')
4011 4019 if len(parts) != 3:
4012 4020 raise ValueError(
4013 4021 'Invalid reference format given: {}, expected X:Y:Z'.format(val))
4014 4022 self._source_ref = safe_unicode(val)
4015 4023
4016 4024 _target_ref = Column('other_ref', Unicode(255), nullable=False)
4017 4025
4018 4026 @hybrid_property
4019 4027 def target_ref(self):
4020 4028 return self._target_ref
4021 4029
4022 4030 @target_ref.setter
4023 4031 def target_ref(self, val):
4024 4032 parts = (val or '').split(':')
4025 4033 if len(parts) != 3:
4026 4034 raise ValueError(
4027 4035 'Invalid reference format given: {}, expected X:Y:Z'.format(val))
4028 4036 self._target_ref = safe_unicode(val)
4029 4037
4030 4038 @declared_attr
4031 4039 def target_repo_id(cls):
4032 4040 # TODO: dan: rename column to target_repo_id
4033 4041 return Column(
4034 4042 'other_repo_id', Integer(), ForeignKey('repositories.repo_id'),
4035 4043 nullable=False)
4036 4044
4037 4045 _shadow_merge_ref = Column('shadow_merge_ref', Unicode(255), nullable=True)
4038 4046
4039 4047 # TODO: dan: rename column to last_merge_source_rev
4040 4048 _last_merge_source_rev = Column(
4041 4049 'last_merge_org_rev', String(40), nullable=True)
4042 4050 # TODO: dan: rename column to last_merge_target_rev
4043 4051 _last_merge_target_rev = Column(
4044 4052 'last_merge_other_rev', String(40), nullable=True)
4045 4053 _last_merge_status = Column('merge_status', Integer(), nullable=True)
4046 4054 last_merge_metadata = Column(
4047 4055 'last_merge_metadata', MutationObj.as_mutable(
4048 4056 JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
4049 4057
4050 4058 merge_rev = Column('merge_rev', String(40), nullable=True)
4051 4059
4052 4060 reviewer_data = Column(
4053 4061 'reviewer_data_json', MutationObj.as_mutable(
4054 4062 JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
4055 4063
4056 4064 @property
4057 4065 def reviewer_data_json(self):
4058 4066 return json.dumps(self.reviewer_data)
4059 4067
4060 4068 @property
4061 4069 def work_in_progress(self):
4062 4070 """checks if pull request is work in progress by checking the title"""
4063 4071 title = self.title.upper()
4064 4072 if re.match(r'^(\[WIP\]\s*|WIP:\s*|WIP\s+)', title):
4065 4073 return True
4066 4074 return False
4067 4075
4068 4076 @hybrid_property
4069 4077 def description_safe(self):
4070 4078 from rhodecode.lib import helpers as h
4071 4079 return h.escape(self.description)
4072 4080
4073 4081 @hybrid_property
4074 4082 def revisions(self):
4075 4083 return self._revisions.split(':') if self._revisions else []
4076 4084
4077 4085 @revisions.setter
4078 4086 def revisions(self, val):
4079 4087 self._revisions = u':'.join(val)
4080 4088
4081 4089 @hybrid_property
4082 4090 def last_merge_status(self):
4083 4091 return safe_int(self._last_merge_status)
4084 4092
4085 4093 @last_merge_status.setter
4086 4094 def last_merge_status(self, val):
4087 4095 self._last_merge_status = val
4088 4096
4089 4097 @declared_attr
4090 4098 def author(cls):
4091 4099 return relationship('User', lazy='joined')
4092 4100
4093 4101 @declared_attr
4094 4102 def source_repo(cls):
4095 4103 return relationship(
4096 4104 'Repository',
4097 4105 primaryjoin='%s.source_repo_id==Repository.repo_id' % cls.__name__)
4098 4106
4099 4107 @property
4100 4108 def source_ref_parts(self):
4101 4109 return self.unicode_to_reference(self.source_ref)
4102 4110
4103 4111 @declared_attr
4104 4112 def target_repo(cls):
4105 4113 return relationship(
4106 4114 'Repository',
4107 4115 primaryjoin='%s.target_repo_id==Repository.repo_id' % cls.__name__)
4108 4116
4109 4117 @property
4110 4118 def target_ref_parts(self):
4111 4119 return self.unicode_to_reference(self.target_ref)
4112 4120
4113 4121 @property
4114 4122 def shadow_merge_ref(self):
4115 4123 return self.unicode_to_reference(self._shadow_merge_ref)
4116 4124
4117 4125 @shadow_merge_ref.setter
4118 4126 def shadow_merge_ref(self, ref):
4119 4127 self._shadow_merge_ref = self.reference_to_unicode(ref)
4120 4128
4121 4129 @staticmethod
4122 4130 def unicode_to_reference(raw):
4123 4131 """
4124 4132 Convert a unicode (or string) to a reference object.
4125 4133 If unicode evaluates to False it returns None.
4126 4134 """
4127 4135 if raw:
4128 4136 refs = raw.split(':')
4129 4137 return Reference(*refs)
4130 4138 else:
4131 4139 return None
4132 4140
4133 4141 @staticmethod
4134 4142 def reference_to_unicode(ref):
4135 4143 """
4136 4144 Convert a reference object to unicode.
4137 4145 If reference is None it returns None.
4138 4146 """
4139 4147 if ref:
4140 4148 return u':'.join(ref)
4141 4149 else:
4142 4150 return None
4143 4151
4144 4152 def get_api_data(self, with_merge_state=True):
4145 4153 from rhodecode.model.pull_request import PullRequestModel
4146 4154
4147 4155 pull_request = self
4148 4156 if with_merge_state:
4149 4157 merge_response, merge_status, msg = \
4150 4158 PullRequestModel().merge_status(pull_request)
4151 4159 merge_state = {
4152 4160 'status': merge_status,
4153 4161 'message': safe_unicode(msg),
4154 4162 }
4155 4163 else:
4156 4164 merge_state = {'status': 'not_available',
4157 4165 'message': 'not_available'}
4158 4166
4159 4167 merge_data = {
4160 4168 'clone_url': PullRequestModel().get_shadow_clone_url(pull_request),
4161 4169 'reference': (
4162 4170 pull_request.shadow_merge_ref._asdict()
4163 4171 if pull_request.shadow_merge_ref else None),
4164 4172 }
4165 4173
4166 4174 data = {
4167 4175 'pull_request_id': pull_request.pull_request_id,
4168 4176 'url': PullRequestModel().get_url(pull_request),
4169 4177 'title': pull_request.title,
4170 4178 'description': pull_request.description,
4171 4179 'status': pull_request.status,
4172 4180 'state': pull_request.pull_request_state,
4173 4181 'created_on': pull_request.created_on,
4174 4182 'updated_on': pull_request.updated_on,
4175 4183 'commit_ids': pull_request.revisions,
4176 4184 'review_status': pull_request.calculated_review_status(),
4177 4185 'mergeable': merge_state,
4178 4186 'source': {
4179 4187 'clone_url': pull_request.source_repo.clone_url(),
4180 4188 'repository': pull_request.source_repo.repo_name,
4181 4189 'reference': {
4182 4190 'name': pull_request.source_ref_parts.name,
4183 4191 'type': pull_request.source_ref_parts.type,
4184 4192 'commit_id': pull_request.source_ref_parts.commit_id,
4185 4193 },
4186 4194 },
4187 4195 'target': {
4188 4196 'clone_url': pull_request.target_repo.clone_url(),
4189 4197 'repository': pull_request.target_repo.repo_name,
4190 4198 'reference': {
4191 4199 'name': pull_request.target_ref_parts.name,
4192 4200 'type': pull_request.target_ref_parts.type,
4193 4201 'commit_id': pull_request.target_ref_parts.commit_id,
4194 4202 },
4195 4203 },
4196 4204 'merge': merge_data,
4197 4205 'author': pull_request.author.get_api_data(include_secrets=False,
4198 4206 details='basic'),
4199 4207 'reviewers': [
4200 4208 {
4201 4209 'user': reviewer.get_api_data(include_secrets=False,
4202 4210 details='basic'),
4203 4211 'reasons': reasons,
4204 4212 'review_status': st[0][1].status if st else 'not_reviewed',
4205 4213 }
4206 4214 for obj, reviewer, reasons, mandatory, st in
4207 4215 pull_request.reviewers_statuses()
4208 4216 ]
4209 4217 }
4210 4218
4211 4219 return data
4212 4220
4213 4221 def set_state(self, pull_request_state, final_state=None):
4214 4222 """
4215 4223 # goes from initial state to updating to initial state.
4216 4224 # initial state can be changed by specifying back_state=
4217 4225 with pull_request_obj.set_state(PullRequest.STATE_UPDATING):
4218 4226 pull_request.merge()
4219 4227
4220 4228 :param pull_request_state:
4221 4229 :param final_state:
4222 4230
4223 4231 """
4224 4232
4225 4233 return _SetState(self, pull_request_state, back_state=final_state)
4226 4234
4227 4235
4228 4236 class PullRequest(Base, _PullRequestBase):
4229 4237 __tablename__ = 'pull_requests'
4230 4238 __table_args__ = (
4231 4239 base_table_args,
4232 4240 )
4233 4241
4234 4242 pull_request_id = Column(
4235 4243 'pull_request_id', Integer(), nullable=False, primary_key=True)
4236 4244
4237 4245 def __repr__(self):
4238 4246 if self.pull_request_id:
4239 4247 return '<DB:PullRequest #%s>' % self.pull_request_id
4240 4248 else:
4241 4249 return '<DB:PullRequest at %#x>' % id(self)
4242 4250
4243 4251 reviewers = relationship('PullRequestReviewers', cascade="all, delete-orphan")
4244 4252 statuses = relationship('ChangesetStatus', cascade="all, delete-orphan")
4245 4253 comments = relationship('ChangesetComment', cascade="all, delete-orphan")
4246 4254 versions = relationship('PullRequestVersion', cascade="all, delete-orphan",
4247 4255 lazy='dynamic')
4248 4256
4249 4257 @classmethod
4250 4258 def get_pr_display_object(cls, pull_request_obj, org_pull_request_obj,
4251 4259 internal_methods=None):
4252 4260
4253 4261 class PullRequestDisplay(object):
4254 4262 """
4255 4263 Special object wrapper for showing PullRequest data via Versions
4256 4264 It mimics PR object as close as possible. This is read only object
4257 4265 just for display
4258 4266 """
4259 4267
4260 4268 def __init__(self, attrs, internal=None):
4261 4269 self.attrs = attrs
4262 4270 # internal have priority over the given ones via attrs
4263 4271 self.internal = internal or ['versions']
4264 4272
4265 4273 def __getattr__(self, item):
4266 4274 if item in self.internal:
4267 4275 return getattr(self, item)
4268 4276 try:
4269 4277 return self.attrs[item]
4270 4278 except KeyError:
4271 4279 raise AttributeError(
4272 4280 '%s object has no attribute %s' % (self, item))
4273 4281
4274 4282 def __repr__(self):
4275 4283 return '<DB:PullRequestDisplay #%s>' % self.attrs.get('pull_request_id')
4276 4284
4277 4285 def versions(self):
4278 4286 return pull_request_obj.versions.order_by(
4279 4287 PullRequestVersion.pull_request_version_id).all()
4280 4288
4281 4289 def is_closed(self):
4282 4290 return pull_request_obj.is_closed()
4283 4291
4284 4292 def is_state_changing(self):
4285 4293 return pull_request_obj.is_state_changing()
4286 4294
4287 4295 @property
4288 4296 def pull_request_version_id(self):
4289 4297 return getattr(pull_request_obj, 'pull_request_version_id', None)
4290 4298
4291 4299 attrs = StrictAttributeDict(pull_request_obj.get_api_data(with_merge_state=False))
4292 4300
4293 4301 attrs.author = StrictAttributeDict(
4294 4302 pull_request_obj.author.get_api_data())
4295 4303 if pull_request_obj.target_repo:
4296 4304 attrs.target_repo = StrictAttributeDict(
4297 4305 pull_request_obj.target_repo.get_api_data())
4298 4306 attrs.target_repo.clone_url = pull_request_obj.target_repo.clone_url
4299 4307
4300 4308 if pull_request_obj.source_repo:
4301 4309 attrs.source_repo = StrictAttributeDict(
4302 4310 pull_request_obj.source_repo.get_api_data())
4303 4311 attrs.source_repo.clone_url = pull_request_obj.source_repo.clone_url
4304 4312
4305 4313 attrs.source_ref_parts = pull_request_obj.source_ref_parts
4306 4314 attrs.target_ref_parts = pull_request_obj.target_ref_parts
4307 4315 attrs.revisions = pull_request_obj.revisions
4308 4316 attrs.common_ancestor_id = pull_request_obj.common_ancestor_id
4309 4317 attrs.shadow_merge_ref = org_pull_request_obj.shadow_merge_ref
4310 4318 attrs.reviewer_data = org_pull_request_obj.reviewer_data
4311 4319 attrs.reviewer_data_json = org_pull_request_obj.reviewer_data_json
4312 4320
4313 4321 return PullRequestDisplay(attrs, internal=internal_methods)
4314 4322
4315 4323 def is_closed(self):
4316 4324 return self.status == self.STATUS_CLOSED
4317 4325
4318 4326 def is_state_changing(self):
4319 4327 return self.pull_request_state != PullRequest.STATE_CREATED
4320 4328
4321 4329 def __json__(self):
4322 4330 return {
4323 4331 'revisions': self.revisions,
4324 4332 'versions': self.versions_count
4325 4333 }
4326 4334
4327 4335 def calculated_review_status(self):
4328 4336 from rhodecode.model.changeset_status import ChangesetStatusModel
4329 4337 return ChangesetStatusModel().calculated_review_status(self)
4330 4338
4331 4339 def reviewers_statuses(self):
4332 4340 from rhodecode.model.changeset_status import ChangesetStatusModel
4333 4341 return ChangesetStatusModel().reviewers_statuses(self)
4334 4342
4335 4343 @property
4336 4344 def workspace_id(self):
4337 4345 from rhodecode.model.pull_request import PullRequestModel
4338 4346 return PullRequestModel()._workspace_id(self)
4339 4347
4340 4348 def get_shadow_repo(self):
4341 4349 workspace_id = self.workspace_id
4342 4350 shadow_repository_path = self.target_repo.get_shadow_repository_path(workspace_id)
4343 4351 if os.path.isdir(shadow_repository_path):
4344 4352 vcs_obj = self.target_repo.scm_instance()
4345 4353 return vcs_obj.get_shadow_instance(shadow_repository_path)
4346 4354
4347 4355 @property
4348 4356 def versions_count(self):
4349 4357 """
4350 4358 return number of versions this PR have, e.g a PR that once been
4351 4359 updated will have 2 versions
4352 4360 """
4353 4361 return self.versions.count() + 1
4354 4362
4355 4363
4356 4364 class PullRequestVersion(Base, _PullRequestBase):
4357 4365 __tablename__ = 'pull_request_versions'
4358 4366 __table_args__ = (
4359 4367 base_table_args,
4360 4368 )
4361 4369
4362 4370 pull_request_version_id = Column(
4363 4371 'pull_request_version_id', Integer(), nullable=False, primary_key=True)
4364 4372 pull_request_id = Column(
4365 4373 'pull_request_id', Integer(),
4366 4374 ForeignKey('pull_requests.pull_request_id'), nullable=False)
4367 4375 pull_request = relationship('PullRequest')
4368 4376
4369 4377 def __repr__(self):
4370 4378 if self.pull_request_version_id:
4371 4379 return '<DB:PullRequestVersion #%s>' % self.pull_request_version_id
4372 4380 else:
4373 4381 return '<DB:PullRequestVersion at %#x>' % id(self)
4374 4382
4375 4383 @property
4376 4384 def reviewers(self):
4377 4385 return self.pull_request.reviewers
4378 4386
4379 4387 @property
4380 4388 def versions(self):
4381 4389 return self.pull_request.versions
4382 4390
4383 4391 def is_closed(self):
4384 4392 # calculate from original
4385 4393 return self.pull_request.status == self.STATUS_CLOSED
4386 4394
4387 4395 def is_state_changing(self):
4388 4396 return self.pull_request.pull_request_state != PullRequest.STATE_CREATED
4389 4397
4390 4398 def calculated_review_status(self):
4391 4399 return self.pull_request.calculated_review_status()
4392 4400
4393 4401 def reviewers_statuses(self):
4394 4402 return self.pull_request.reviewers_statuses()
4395 4403
4396 4404
4397 4405 class PullRequestReviewers(Base, BaseModel):
4398 4406 __tablename__ = 'pull_request_reviewers'
4399 4407 __table_args__ = (
4400 4408 base_table_args,
4401 4409 )
4402 4410
4403 4411 @hybrid_property
4404 4412 def reasons(self):
4405 4413 if not self._reasons:
4406 4414 return []
4407 4415 return self._reasons
4408 4416
4409 4417 @reasons.setter
4410 4418 def reasons(self, val):
4411 4419 val = val or []
4412 4420 if any(not isinstance(x, compat.string_types) for x in val):
4413 4421 raise Exception('invalid reasons type, must be list of strings')
4414 4422 self._reasons = val
4415 4423
4416 4424 pull_requests_reviewers_id = Column(
4417 4425 'pull_requests_reviewers_id', Integer(), nullable=False,
4418 4426 primary_key=True)
4419 4427 pull_request_id = Column(
4420 4428 "pull_request_id", Integer(),
4421 4429 ForeignKey('pull_requests.pull_request_id'), nullable=False)
4422 4430 user_id = Column(
4423 4431 "user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
4424 4432 _reasons = Column(
4425 4433 'reason', MutationList.as_mutable(
4426 4434 JsonType('list', dialect_map=dict(mysql=UnicodeText(16384)))))
4427 4435
4428 4436 mandatory = Column("mandatory", Boolean(), nullable=False, default=False)
4429 4437 user = relationship('User')
4430 4438 pull_request = relationship('PullRequest')
4431 4439
4432 4440 rule_data = Column(
4433 4441 'rule_data_json',
4434 4442 JsonType(dialect_map=dict(mysql=UnicodeText(16384))))
4435 4443
4436 4444 def rule_user_group_data(self):
4437 4445 """
4438 4446 Returns the voting user group rule data for this reviewer
4439 4447 """
4440 4448
4441 4449 if self.rule_data and 'vote_rule' in self.rule_data:
4442 4450 user_group_data = {}
4443 4451 if 'rule_user_group_entry_id' in self.rule_data:
4444 4452 # means a group with voting rules !
4445 4453 user_group_data['id'] = self.rule_data['rule_user_group_entry_id']
4446 4454 user_group_data['name'] = self.rule_data['rule_name']
4447 4455 user_group_data['vote_rule'] = self.rule_data['vote_rule']
4448 4456
4449 4457 return user_group_data
4450 4458
4451 4459 def __unicode__(self):
4452 4460 return u"<%s('id:%s')>" % (self.__class__.__name__,
4453 4461 self.pull_requests_reviewers_id)
4454 4462
4455 4463
4456 4464 class Notification(Base, BaseModel):
4457 4465 __tablename__ = 'notifications'
4458 4466 __table_args__ = (
4459 4467 Index('notification_type_idx', 'type'),
4460 4468 base_table_args,
4461 4469 )
4462 4470
4463 4471 TYPE_CHANGESET_COMMENT = u'cs_comment'
4464 4472 TYPE_MESSAGE = u'message'
4465 4473 TYPE_MENTION = u'mention'
4466 4474 TYPE_REGISTRATION = u'registration'
4467 4475 TYPE_PULL_REQUEST = u'pull_request'
4468 4476 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
4469 4477 TYPE_PULL_REQUEST_UPDATE = u'pull_request_update'
4470 4478
4471 4479 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
4472 4480 subject = Column('subject', Unicode(512), nullable=True)
4473 4481 body = Column('body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
4474 4482 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
4475 4483 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
4476 4484 type_ = Column('type', Unicode(255))
4477 4485
4478 4486 created_by_user = relationship('User')
4479 4487 notifications_to_users = relationship('UserNotification', lazy='joined',
4480 4488 cascade="all, delete-orphan")
4481 4489
4482 4490 @property
4483 4491 def recipients(self):
4484 4492 return [x.user for x in UserNotification.query()\
4485 4493 .filter(UserNotification.notification == self)\
4486 4494 .order_by(UserNotification.user_id.asc()).all()]
4487 4495
4488 4496 @classmethod
4489 4497 def create(cls, created_by, subject, body, recipients, type_=None):
4490 4498 if type_ is None:
4491 4499 type_ = Notification.TYPE_MESSAGE
4492 4500
4493 4501 notification = cls()
4494 4502 notification.created_by_user = created_by
4495 4503 notification.subject = subject
4496 4504 notification.body = body
4497 4505 notification.type_ = type_
4498 4506 notification.created_on = datetime.datetime.now()
4499 4507
4500 4508 # For each recipient link the created notification to his account
4501 4509 for u in recipients:
4502 4510 assoc = UserNotification()
4503 4511 assoc.user_id = u.user_id
4504 4512 assoc.notification = notification
4505 4513
4506 4514 # if created_by is inside recipients mark his notification
4507 4515 # as read
4508 4516 if u.user_id == created_by.user_id:
4509 4517 assoc.read = True
4510 4518 Session().add(assoc)
4511 4519
4512 4520 Session().add(notification)
4513 4521
4514 4522 return notification
4515 4523
4516 4524
4517 4525 class UserNotification(Base, BaseModel):
4518 4526 __tablename__ = 'user_to_notification'
4519 4527 __table_args__ = (
4520 4528 UniqueConstraint('user_id', 'notification_id'),
4521 4529 base_table_args
4522 4530 )
4523 4531
4524 4532 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
4525 4533 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
4526 4534 read = Column('read', Boolean, default=False)
4527 4535 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
4528 4536
4529 4537 user = relationship('User', lazy="joined")
4530 4538 notification = relationship('Notification', lazy="joined",
4531 4539 order_by=lambda: Notification.created_on.desc(),)
4532 4540
4533 4541 def mark_as_read(self):
4534 4542 self.read = True
4535 4543 Session().add(self)
4536 4544
4537 4545
4538 4546 class UserNotice(Base, BaseModel):
4539 4547 __tablename__ = 'user_notices'
4540 4548 __table_args__ = (
4541 4549 base_table_args
4542 4550 )
4543 4551
4544 4552 NOTIFICATION_TYPE_MESSAGE = 'message'
4545 4553 NOTIFICATION_TYPE_NOTICE = 'notice'
4546 4554
4547 4555 NOTIFICATION_LEVEL_INFO = 'info'
4548 4556 NOTIFICATION_LEVEL_WARNING = 'warning'
4549 4557 NOTIFICATION_LEVEL_ERROR = 'error'
4550 4558
4551 4559 user_notice_id = Column('gist_id', Integer(), primary_key=True)
4552 4560
4553 4561 notice_subject = Column('notice_subject', Unicode(512), nullable=True)
4554 4562 notice_body = Column('notice_body', UnicodeText().with_variant(UnicodeText(50000), 'mysql'), nullable=True)
4555 4563
4556 4564 notice_read = Column('notice_read', Boolean, default=False)
4557 4565
4558 4566 notification_level = Column('notification_level', String(1024), default=NOTIFICATION_LEVEL_INFO)
4559 4567 notification_type = Column('notification_type', String(1024), default=NOTIFICATION_TYPE_NOTICE)
4560 4568
4561 4569 notice_created_by = Column('notice_created_by', Integer(), ForeignKey('users.user_id'), nullable=True)
4562 4570 notice_created_on = Column('notice_created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
4563 4571
4564 4572 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'))
4565 4573 user = relationship('User', lazy="joined", primaryjoin='User.user_id==UserNotice.user_id')
4566 4574
4567 4575 @classmethod
4568 4576 def create_for_user(cls, user, subject, body, notice_level=NOTIFICATION_LEVEL_INFO, allow_duplicate=False):
4569 4577
4570 4578 if notice_level not in [cls.NOTIFICATION_LEVEL_ERROR,
4571 4579 cls.NOTIFICATION_LEVEL_WARNING,
4572 4580 cls.NOTIFICATION_LEVEL_INFO]:
4573 4581 return
4574 4582
4575 4583 from rhodecode.model.user import UserModel
4576 4584 user = UserModel().get_user(user)
4577 4585
4578 4586 new_notice = UserNotice()
4579 4587 if not allow_duplicate:
4580 4588 existing_msg = UserNotice().query() \
4581 4589 .filter(UserNotice.user == user) \
4582 4590 .filter(UserNotice.notice_body == body) \
4583 4591 .filter(UserNotice.notice_read == false()) \
4584 4592 .scalar()
4585 4593 if existing_msg:
4586 4594 log.warning('Ignoring duplicate notice for user %s', user)
4587 4595 return
4588 4596
4589 4597 new_notice.user = user
4590 4598 new_notice.notice_subject = subject
4591 4599 new_notice.notice_body = body
4592 4600 new_notice.notification_level = notice_level
4593 4601 Session().add(new_notice)
4594 4602 Session().commit()
4595 4603
4596 4604
4597 4605 class Gist(Base, BaseModel):
4598 4606 __tablename__ = 'gists'
4599 4607 __table_args__ = (
4600 4608 Index('g_gist_access_id_idx', 'gist_access_id'),
4601 4609 Index('g_created_on_idx', 'created_on'),
4602 4610 base_table_args
4603 4611 )
4604 4612
4605 4613 GIST_PUBLIC = u'public'
4606 4614 GIST_PRIVATE = u'private'
4607 4615 DEFAULT_FILENAME = u'gistfile1.txt'
4608 4616
4609 4617 ACL_LEVEL_PUBLIC = u'acl_public'
4610 4618 ACL_LEVEL_PRIVATE = u'acl_private'
4611 4619
4612 4620 gist_id = Column('gist_id', Integer(), primary_key=True)
4613 4621 gist_access_id = Column('gist_access_id', Unicode(250))
4614 4622 gist_description = Column('gist_description', UnicodeText().with_variant(UnicodeText(1024), 'mysql'))
4615 4623 gist_owner = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=True)
4616 4624 gist_expires = Column('gist_expires', Float(53), nullable=False)
4617 4625 gist_type = Column('gist_type', Unicode(128), nullable=False)
4618 4626 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
4619 4627 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
4620 4628 acl_level = Column('acl_level', Unicode(128), nullable=True)
4621 4629
4622 4630 owner = relationship('User')
4623 4631
4624 4632 def __repr__(self):
4625 4633 return '<Gist:[%s]%s>' % (self.gist_type, self.gist_access_id)
4626 4634
4627 4635 @hybrid_property
4628 4636 def description_safe(self):
4629 4637 from rhodecode.lib import helpers as h
4630 4638 return h.escape(self.gist_description)
4631 4639
4632 4640 @classmethod
4633 4641 def get_or_404(cls, id_):
4634 4642 from pyramid.httpexceptions import HTTPNotFound
4635 4643
4636 4644 res = cls.query().filter(cls.gist_access_id == id_).scalar()
4637 4645 if not res:
4638 4646 raise HTTPNotFound()
4639 4647 return res
4640 4648
4641 4649 @classmethod
4642 4650 def get_by_access_id(cls, gist_access_id):
4643 4651 return cls.query().filter(cls.gist_access_id == gist_access_id).scalar()
4644 4652
4645 4653 def gist_url(self):
4646 4654 from rhodecode.model.gist import GistModel
4647 4655 return GistModel().get_url(self)
4648 4656
4649 4657 @classmethod
4650 4658 def base_path(cls):
4651 4659 """
4652 4660 Returns base path when all gists are stored
4653 4661
4654 4662 :param cls:
4655 4663 """
4656 4664 from rhodecode.model.gist import GIST_STORE_LOC
4657 4665 q = Session().query(RhodeCodeUi)\
4658 4666 .filter(RhodeCodeUi.ui_key == URL_SEP)
4659 4667 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
4660 4668 return os.path.join(q.one().ui_value, GIST_STORE_LOC)
4661 4669
4662 4670 def get_api_data(self):
4663 4671 """
4664 4672 Common function for generating gist related data for API
4665 4673 """
4666 4674 gist = self
4667 4675 data = {
4668 4676 'gist_id': gist.gist_id,
4669 4677 'type': gist.gist_type,
4670 4678 'access_id': gist.gist_access_id,
4671 4679 'description': gist.gist_description,
4672 4680 'url': gist.gist_url(),
4673 4681 'expires': gist.gist_expires,
4674 4682 'created_on': gist.created_on,
4675 4683 'modified_at': gist.modified_at,
4676 4684 'content': None,
4677 4685 'acl_level': gist.acl_level,
4678 4686 }
4679 4687 return data
4680 4688
4681 4689 def __json__(self):
4682 4690 data = dict(
4683 4691 )
4684 4692 data.update(self.get_api_data())
4685 4693 return data
4686 4694 # SCM functions
4687 4695
4688 4696 def scm_instance(self, **kwargs):
4689 4697 """
4690 4698 Get an instance of VCS Repository
4691 4699
4692 4700 :param kwargs:
4693 4701 """
4694 4702 from rhodecode.model.gist import GistModel
4695 4703 full_repo_path = os.path.join(self.base_path(), self.gist_access_id)
4696 4704 return get_vcs_instance(
4697 4705 repo_path=safe_str(full_repo_path), create=False,
4698 4706 _vcs_alias=GistModel.vcs_backend)
4699 4707
4700 4708
4701 4709 class ExternalIdentity(Base, BaseModel):
4702 4710 __tablename__ = 'external_identities'
4703 4711 __table_args__ = (
4704 4712 Index('local_user_id_idx', 'local_user_id'),
4705 4713 Index('external_id_idx', 'external_id'),
4706 4714 base_table_args
4707 4715 )
4708 4716
4709 4717 external_id = Column('external_id', Unicode(255), default=u'', primary_key=True)
4710 4718 external_username = Column('external_username', Unicode(1024), default=u'')
4711 4719 local_user_id = Column('local_user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
4712 4720 provider_name = Column('provider_name', Unicode(255), default=u'', primary_key=True)
4713 4721 access_token = Column('access_token', String(1024), default=u'')
4714 4722 alt_token = Column('alt_token', String(1024), default=u'')
4715 4723 token_secret = Column('token_secret', String(1024), default=u'')
4716 4724
4717 4725 @classmethod
4718 4726 def by_external_id_and_provider(cls, external_id, provider_name, local_user_id=None):
4719 4727 """
4720 4728 Returns ExternalIdentity instance based on search params
4721 4729
4722 4730 :param external_id:
4723 4731 :param provider_name:
4724 4732 :return: ExternalIdentity
4725 4733 """
4726 4734 query = cls.query()
4727 4735 query = query.filter(cls.external_id == external_id)
4728 4736 query = query.filter(cls.provider_name == provider_name)
4729 4737 if local_user_id:
4730 4738 query = query.filter(cls.local_user_id == local_user_id)
4731 4739 return query.first()
4732 4740
4733 4741 @classmethod
4734 4742 def user_by_external_id_and_provider(cls, external_id, provider_name):
4735 4743 """
4736 4744 Returns User instance based on search params
4737 4745
4738 4746 :param external_id:
4739 4747 :param provider_name:
4740 4748 :return: User
4741 4749 """
4742 4750 query = User.query()
4743 4751 query = query.filter(cls.external_id == external_id)
4744 4752 query = query.filter(cls.provider_name == provider_name)
4745 4753 query = query.filter(User.user_id == cls.local_user_id)
4746 4754 return query.first()
4747 4755
4748 4756 @classmethod
4749 4757 def by_local_user_id(cls, local_user_id):
4750 4758 """
4751 4759 Returns all tokens for user
4752 4760
4753 4761 :param local_user_id:
4754 4762 :return: ExternalIdentity
4755 4763 """
4756 4764 query = cls.query()
4757 4765 query = query.filter(cls.local_user_id == local_user_id)
4758 4766 return query
4759 4767
4760 4768 @classmethod
4761 4769 def load_provider_plugin(cls, plugin_id):
4762 4770 from rhodecode.authentication.base import loadplugin
4763 4771 _plugin_id = 'egg:rhodecode-enterprise-ee#{}'.format(plugin_id)
4764 4772 auth_plugin = loadplugin(_plugin_id)
4765 4773 return auth_plugin
4766 4774
4767 4775
4768 4776 class Integration(Base, BaseModel):
4769 4777 __tablename__ = 'integrations'
4770 4778 __table_args__ = (
4771 4779 base_table_args
4772 4780 )
4773 4781
4774 4782 integration_id = Column('integration_id', Integer(), primary_key=True)
4775 4783 integration_type = Column('integration_type', String(255))
4776 4784 enabled = Column('enabled', Boolean(), nullable=False)
4777 4785 name = Column('name', String(255), nullable=False)
4778 4786 child_repos_only = Column('child_repos_only', Boolean(), nullable=False,
4779 4787 default=False)
4780 4788
4781 4789 settings = Column(
4782 4790 'settings_json', MutationObj.as_mutable(
4783 4791 JsonType(dialect_map=dict(mysql=UnicodeText(16384)))))
4784 4792 repo_id = Column(
4785 4793 'repo_id', Integer(), ForeignKey('repositories.repo_id'),
4786 4794 nullable=True, unique=None, default=None)
4787 4795 repo = relationship('Repository', lazy='joined')
4788 4796
4789 4797 repo_group_id = Column(
4790 4798 'repo_group_id', Integer(), ForeignKey('groups.group_id'),
4791 4799 nullable=True, unique=None, default=None)
4792 4800 repo_group = relationship('RepoGroup', lazy='joined')
4793 4801
4794 4802 @property
4795 4803 def scope(self):
4796 4804 if self.repo:
4797 4805 return repr(self.repo)
4798 4806 if self.repo_group:
4799 4807 if self.child_repos_only:
4800 4808 return repr(self.repo_group) + ' (child repos only)'
4801 4809 else:
4802 4810 return repr(self.repo_group) + ' (recursive)'
4803 4811 if self.child_repos_only:
4804 4812 return 'root_repos'
4805 4813 return 'global'
4806 4814
4807 4815 def __repr__(self):
4808 4816 return '<Integration(%r, %r)>' % (self.integration_type, self.scope)
4809 4817
4810 4818
4811 4819 class RepoReviewRuleUser(Base, BaseModel):
4812 4820 __tablename__ = 'repo_review_rules_users'
4813 4821 __table_args__ = (
4814 4822 base_table_args
4815 4823 )
4816 4824
4817 4825 repo_review_rule_user_id = Column('repo_review_rule_user_id', Integer(), primary_key=True)
4818 4826 repo_review_rule_id = Column("repo_review_rule_id", Integer(), ForeignKey('repo_review_rules.repo_review_rule_id'))
4819 4827 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False)
4820 4828 mandatory = Column("mandatory", Boolean(), nullable=False, default=False)
4821 4829 user = relationship('User')
4822 4830
4823 4831 def rule_data(self):
4824 4832 return {
4825 4833 'mandatory': self.mandatory
4826 4834 }
4827 4835
4828 4836
4829 4837 class RepoReviewRuleUserGroup(Base, BaseModel):
4830 4838 __tablename__ = 'repo_review_rules_users_groups'
4831 4839 __table_args__ = (
4832 4840 base_table_args
4833 4841 )
4834 4842
4835 4843 VOTE_RULE_ALL = -1
4836 4844
4837 4845 repo_review_rule_users_group_id = Column('repo_review_rule_users_group_id', Integer(), primary_key=True)
4838 4846 repo_review_rule_id = Column("repo_review_rule_id", Integer(), ForeignKey('repo_review_rules.repo_review_rule_id'))
4839 4847 users_group_id = Column("users_group_id", Integer(),ForeignKey('users_groups.users_group_id'), nullable=False)
4840 4848 mandatory = Column("mandatory", Boolean(), nullable=False, default=False)
4841 4849 vote_rule = Column("vote_rule", Integer(), nullable=True, default=VOTE_RULE_ALL)
4842 4850 users_group = relationship('UserGroup')
4843 4851
4844 4852 def rule_data(self):
4845 4853 return {
4846 4854 'mandatory': self.mandatory,
4847 4855 'vote_rule': self.vote_rule
4848 4856 }
4849 4857
4850 4858 @property
4851 4859 def vote_rule_label(self):
4852 4860 if not self.vote_rule or self.vote_rule == self.VOTE_RULE_ALL:
4853 4861 return 'all must vote'
4854 4862 else:
4855 4863 return 'min. vote {}'.format(self.vote_rule)
4856 4864
4857 4865
4858 4866 class RepoReviewRule(Base, BaseModel):
4859 4867 __tablename__ = 'repo_review_rules'
4860 4868 __table_args__ = (
4861 4869 base_table_args
4862 4870 )
4863 4871
4864 4872 repo_review_rule_id = Column(
4865 4873 'repo_review_rule_id', Integer(), primary_key=True)
4866 4874 repo_id = Column(
4867 4875 "repo_id", Integer(), ForeignKey('repositories.repo_id'))
4868 4876 repo = relationship('Repository', backref='review_rules')
4869 4877
4870 4878 review_rule_name = Column('review_rule_name', String(255))
4871 4879 _branch_pattern = Column("branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default=u'*') # glob
4872 4880 _target_branch_pattern = Column("target_branch_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default=u'*') # glob
4873 4881 _file_pattern = Column("file_pattern", UnicodeText().with_variant(UnicodeText(255), 'mysql'), default=u'*') # glob
4874 4882
4875 4883 use_authors_for_review = Column("use_authors_for_review", Boolean(), nullable=False, default=False)
4876 4884 forbid_author_to_review = Column("forbid_author_to_review", Boolean(), nullable=False, default=False)
4877 4885 forbid_commit_author_to_review = Column("forbid_commit_author_to_review", Boolean(), nullable=False, default=False)
4878 4886 forbid_adding_reviewers = Column("forbid_adding_reviewers", Boolean(), nullable=False, default=False)
4879 4887
4880 4888 rule_users = relationship('RepoReviewRuleUser')
4881 4889 rule_user_groups = relationship('RepoReviewRuleUserGroup')
4882 4890
4883 4891 def _validate_pattern(self, value):
4884 4892 re.compile('^' + glob2re(value) + '$')
4885 4893
4886 4894 @hybrid_property
4887 4895 def source_branch_pattern(self):
4888 4896 return self._branch_pattern or '*'
4889 4897
4890 4898 @source_branch_pattern.setter
4891 4899 def source_branch_pattern(self, value):
4892 4900 self._validate_pattern(value)
4893 4901 self._branch_pattern = value or '*'
4894 4902
4895 4903 @hybrid_property
4896 4904 def target_branch_pattern(self):
4897 4905 return self._target_branch_pattern or '*'
4898 4906
4899 4907 @target_branch_pattern.setter
4900 4908 def target_branch_pattern(self, value):
4901 4909 self._validate_pattern(value)
4902 4910 self._target_branch_pattern = value or '*'
4903 4911
4904 4912 @hybrid_property
4905 4913 def file_pattern(self):
4906 4914 return self._file_pattern or '*'
4907 4915
4908 4916 @file_pattern.setter
4909 4917 def file_pattern(self, value):
4910 4918 self._validate_pattern(value)
4911 4919 self._file_pattern = value or '*'
4912 4920
4913 4921 def matches(self, source_branch, target_branch, files_changed):
4914 4922 """
4915 4923 Check if this review rule matches a branch/files in a pull request
4916 4924
4917 4925 :param source_branch: source branch name for the commit
4918 4926 :param target_branch: target branch name for the commit
4919 4927 :param files_changed: list of file paths changed in the pull request
4920 4928 """
4921 4929
4922 4930 source_branch = source_branch or ''
4923 4931 target_branch = target_branch or ''
4924 4932 files_changed = files_changed or []
4925 4933
4926 4934 branch_matches = True
4927 4935 if source_branch or target_branch:
4928 4936 if self.source_branch_pattern == '*':
4929 4937 source_branch_match = True
4930 4938 else:
4931 4939 if self.source_branch_pattern.startswith('re:'):
4932 4940 source_pattern = self.source_branch_pattern[3:]
4933 4941 else:
4934 4942 source_pattern = '^' + glob2re(self.source_branch_pattern) + '$'
4935 4943 source_branch_regex = re.compile(source_pattern)
4936 4944 source_branch_match = bool(source_branch_regex.search(source_branch))
4937 4945 if self.target_branch_pattern == '*':
4938 4946 target_branch_match = True
4939 4947 else:
4940 4948 if self.target_branch_pattern.startswith('re:'):
4941 4949 target_pattern = self.target_branch_pattern[3:]
4942 4950 else:
4943 4951 target_pattern = '^' + glob2re(self.target_branch_pattern) + '$'
4944 4952 target_branch_regex = re.compile(target_pattern)
4945 4953 target_branch_match = bool(target_branch_regex.search(target_branch))
4946 4954
4947 4955 branch_matches = source_branch_match and target_branch_match
4948 4956
4949 4957 files_matches = True
4950 4958 if self.file_pattern != '*':
4951 4959 files_matches = False
4952 4960 if self.file_pattern.startswith('re:'):
4953 4961 file_pattern = self.file_pattern[3:]
4954 4962 else:
4955 4963 file_pattern = glob2re(self.file_pattern)
4956 4964 file_regex = re.compile(file_pattern)
4957 for filename in files_changed:
4965 for file_data in files_changed:
4966 filename = file_data.get('filename')
4967
4958 4968 if file_regex.search(filename):
4959 4969 files_matches = True
4960 4970 break
4961 4971
4962 4972 return branch_matches and files_matches
4963 4973
4964 4974 @property
4965 4975 def review_users(self):
4966 4976 """ Returns the users which this rule applies to """
4967 4977
4968 4978 users = collections.OrderedDict()
4969 4979
4970 4980 for rule_user in self.rule_users:
4971 4981 if rule_user.user.active:
4972 4982 if rule_user.user not in users:
4973 4983 users[rule_user.user.username] = {
4974 4984 'user': rule_user.user,
4975 4985 'source': 'user',
4976 4986 'source_data': {},
4977 4987 'data': rule_user.rule_data()
4978 4988 }
4979 4989
4980 4990 for rule_user_group in self.rule_user_groups:
4981 4991 source_data = {
4982 4992 'user_group_id': rule_user_group.users_group.users_group_id,
4983 4993 'name': rule_user_group.users_group.users_group_name,
4984 4994 'members': len(rule_user_group.users_group.members)
4985 4995 }
4986 4996 for member in rule_user_group.users_group.members:
4987 4997 if member.user.active:
4988 4998 key = member.user.username
4989 4999 if key in users:
4990 5000 # skip this member as we have him already
4991 5001 # this prevents from override the "first" matched
4992 5002 # users with duplicates in multiple groups
4993 5003 continue
4994 5004
4995 5005 users[key] = {
4996 5006 'user': member.user,
4997 5007 'source': 'user_group',
4998 5008 'source_data': source_data,
4999 5009 'data': rule_user_group.rule_data()
5000 5010 }
5001 5011
5002 5012 return users
5003 5013
5004 5014 def user_group_vote_rule(self, user_id):
5005 5015
5006 5016 rules = []
5007 5017 if not self.rule_user_groups:
5008 5018 return rules
5009 5019
5010 5020 for user_group in self.rule_user_groups:
5011 5021 user_group_members = [x.user_id for x in user_group.users_group.members]
5012 5022 if user_id in user_group_members:
5013 5023 rules.append(user_group)
5014 5024 return rules
5015 5025
5016 5026 def __repr__(self):
5017 5027 return '<RepoReviewerRule(id=%r, repo=%r)>' % (
5018 5028 self.repo_review_rule_id, self.repo)
5019 5029
5020 5030
5021 5031 class ScheduleEntry(Base, BaseModel):
5022 5032 __tablename__ = 'schedule_entries'
5023 5033 __table_args__ = (
5024 5034 UniqueConstraint('schedule_name', name='s_schedule_name_idx'),
5025 5035 UniqueConstraint('task_uid', name='s_task_uid_idx'),
5026 5036 base_table_args,
5027 5037 )
5028 5038
5029 5039 schedule_types = ['crontab', 'timedelta', 'integer']
5030 5040 schedule_entry_id = Column('schedule_entry_id', Integer(), primary_key=True)
5031 5041
5032 5042 schedule_name = Column("schedule_name", String(255), nullable=False, unique=None, default=None)
5033 5043 schedule_description = Column("schedule_description", String(10000), nullable=True, unique=None, default=None)
5034 5044 schedule_enabled = Column("schedule_enabled", Boolean(), nullable=False, unique=None, default=True)
5035 5045
5036 5046 _schedule_type = Column("schedule_type", String(255), nullable=False, unique=None, default=None)
5037 5047 schedule_definition = Column('schedule_definition_json', MutationObj.as_mutable(JsonType(default=lambda: "", dialect_map=dict(mysql=LONGTEXT()))))
5038 5048
5039 5049 schedule_last_run = Column('schedule_last_run', DateTime(timezone=False), nullable=True, unique=None, default=None)
5040 5050 schedule_total_run_count = Column('schedule_total_run_count', Integer(), nullable=True, unique=None, default=0)
5041 5051
5042 5052 # task
5043 5053 task_uid = Column("task_uid", String(255), nullable=False, unique=None, default=None)
5044 5054 task_dot_notation = Column("task_dot_notation", String(4096), nullable=False, unique=None, default=None)
5045 5055 task_args = Column('task_args_json', MutationObj.as_mutable(JsonType(default=list, dialect_map=dict(mysql=LONGTEXT()))))
5046 5056 task_kwargs = Column('task_kwargs_json', MutationObj.as_mutable(JsonType(default=dict, dialect_map=dict(mysql=LONGTEXT()))))
5047 5057
5048 5058 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
5049 5059 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=None)
5050 5060
5051 5061 @hybrid_property
5052 5062 def schedule_type(self):
5053 5063 return self._schedule_type
5054 5064
5055 5065 @schedule_type.setter
5056 5066 def schedule_type(self, val):
5057 5067 if val not in self.schedule_types:
5058 5068 raise ValueError('Value must be on of `{}` and got `{}`'.format(
5059 5069 val, self.schedule_type))
5060 5070
5061 5071 self._schedule_type = val
5062 5072
5063 5073 @classmethod
5064 5074 def get_uid(cls, obj):
5065 5075 args = obj.task_args
5066 5076 kwargs = obj.task_kwargs
5067 5077 if isinstance(args, JsonRaw):
5068 5078 try:
5069 5079 args = json.loads(args)
5070 5080 except ValueError:
5071 5081 args = tuple()
5072 5082
5073 5083 if isinstance(kwargs, JsonRaw):
5074 5084 try:
5075 5085 kwargs = json.loads(kwargs)
5076 5086 except ValueError:
5077 5087 kwargs = dict()
5078 5088
5079 5089 dot_notation = obj.task_dot_notation
5080 5090 val = '.'.join(map(safe_str, [
5081 5091 sorted(dot_notation), args, sorted(kwargs.items())]))
5082 5092 return hashlib.sha1(val).hexdigest()
5083 5093
5084 5094 @classmethod
5085 5095 def get_by_schedule_name(cls, schedule_name):
5086 5096 return cls.query().filter(cls.schedule_name == schedule_name).scalar()
5087 5097
5088 5098 @classmethod
5089 5099 def get_by_schedule_id(cls, schedule_id):
5090 5100 return cls.query().filter(cls.schedule_entry_id == schedule_id).scalar()
5091 5101
5092 5102 @property
5093 5103 def task(self):
5094 5104 return self.task_dot_notation
5095 5105
5096 5106 @property
5097 5107 def schedule(self):
5098 5108 from rhodecode.lib.celerylib.utils import raw_2_schedule
5099 5109 schedule = raw_2_schedule(self.schedule_definition, self.schedule_type)
5100 5110 return schedule
5101 5111
5102 5112 @property
5103 5113 def args(self):
5104 5114 try:
5105 5115 return list(self.task_args or [])
5106 5116 except ValueError:
5107 5117 return list()
5108 5118
5109 5119 @property
5110 5120 def kwargs(self):
5111 5121 try:
5112 5122 return dict(self.task_kwargs or {})
5113 5123 except ValueError:
5114 5124 return dict()
5115 5125
5116 5126 def _as_raw(self, val):
5117 5127 if hasattr(val, 'de_coerce'):
5118 5128 val = val.de_coerce()
5119 5129 if val:
5120 5130 val = json.dumps(val)
5121 5131
5122 5132 return val
5123 5133
5124 5134 @property
5125 5135 def schedule_definition_raw(self):
5126 5136 return self._as_raw(self.schedule_definition)
5127 5137
5128 5138 @property
5129 5139 def args_raw(self):
5130 5140 return self._as_raw(self.task_args)
5131 5141
5132 5142 @property
5133 5143 def kwargs_raw(self):
5134 5144 return self._as_raw(self.task_kwargs)
5135 5145
5136 5146 def __repr__(self):
5137 5147 return '<DB:ScheduleEntry({}:{})>'.format(
5138 5148 self.schedule_entry_id, self.schedule_name)
5139 5149
5140 5150
5141 5151 @event.listens_for(ScheduleEntry, 'before_update')
5142 5152 def update_task_uid(mapper, connection, target):
5143 5153 target.task_uid = ScheduleEntry.get_uid(target)
5144 5154
5145 5155
5146 5156 @event.listens_for(ScheduleEntry, 'before_insert')
5147 5157 def set_task_uid(mapper, connection, target):
5148 5158 target.task_uid = ScheduleEntry.get_uid(target)
5149 5159
5150 5160
5151 5161 class _BaseBranchPerms(BaseModel):
5152 5162 @classmethod
5153 5163 def compute_hash(cls, value):
5154 5164 return sha1_safe(value)
5155 5165
5156 5166 @hybrid_property
5157 5167 def branch_pattern(self):
5158 5168 return self._branch_pattern or '*'
5159 5169
5160 5170 @hybrid_property
5161 5171 def branch_hash(self):
5162 5172 return self._branch_hash
5163 5173
5164 5174 def _validate_glob(self, value):
5165 5175 re.compile('^' + glob2re(value) + '$')
5166 5176
5167 5177 @branch_pattern.setter
5168 5178 def branch_pattern(self, value):
5169 5179 self._validate_glob(value)
5170 5180 self._branch_pattern = value or '*'
5171 5181 # set the Hash when setting the branch pattern
5172 5182 self._branch_hash = self.compute_hash(self._branch_pattern)
5173 5183
5174 5184 def matches(self, branch):
5175 5185 """
5176 5186 Check if this the branch matches entry
5177 5187
5178 5188 :param branch: branch name for the commit
5179 5189 """
5180 5190
5181 5191 branch = branch or ''
5182 5192
5183 5193 branch_matches = True
5184 5194 if branch:
5185 5195 branch_regex = re.compile('^' + glob2re(self.branch_pattern) + '$')
5186 5196 branch_matches = bool(branch_regex.search(branch))
5187 5197
5188 5198 return branch_matches
5189 5199
5190 5200
5191 5201 class UserToRepoBranchPermission(Base, _BaseBranchPerms):
5192 5202 __tablename__ = 'user_to_repo_branch_permissions'
5193 5203 __table_args__ = (
5194 5204 base_table_args
5195 5205 )
5196 5206
5197 5207 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
5198 5208
5199 5209 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
5200 5210 repo = relationship('Repository', backref='user_branch_perms')
5201 5211
5202 5212 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
5203 5213 permission = relationship('Permission')
5204 5214
5205 5215 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('repo_to_perm.repo_to_perm_id'), nullable=False, unique=None, default=None)
5206 5216 user_repo_to_perm = relationship('UserRepoToPerm')
5207 5217
5208 5218 rule_order = Column('rule_order', Integer(), nullable=False)
5209 5219 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
5210 5220 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
5211 5221
5212 5222 def __unicode__(self):
5213 5223 return u'<UserBranchPermission(%s => %r)>' % (
5214 5224 self.user_repo_to_perm, self.branch_pattern)
5215 5225
5216 5226
5217 5227 class UserGroupToRepoBranchPermission(Base, _BaseBranchPerms):
5218 5228 __tablename__ = 'user_group_to_repo_branch_permissions'
5219 5229 __table_args__ = (
5220 5230 base_table_args
5221 5231 )
5222 5232
5223 5233 branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
5224 5234
5225 5235 repository_id = Column('repository_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
5226 5236 repo = relationship('Repository', backref='user_group_branch_perms')
5227 5237
5228 5238 permission_id = Column('permission_id', Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
5229 5239 permission = relationship('Permission')
5230 5240
5231 5241 rule_to_perm_id = Column('rule_to_perm_id', Integer(), ForeignKey('users_group_repo_to_perm.users_group_to_perm_id'), nullable=False, unique=None, default=None)
5232 5242 user_group_repo_to_perm = relationship('UserGroupRepoToPerm')
5233 5243
5234 5244 rule_order = Column('rule_order', Integer(), nullable=False)
5235 5245 _branch_pattern = Column('branch_pattern', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), default=u'*') # glob
5236 5246 _branch_hash = Column('branch_hash', UnicodeText().with_variant(UnicodeText(2048), 'mysql'))
5237 5247
5238 5248 def __unicode__(self):
5239 5249 return u'<UserBranchPermission(%s => %r)>' % (
5240 5250 self.user_group_repo_to_perm, self.branch_pattern)
5241 5251
5242 5252
5243 5253 class UserBookmark(Base, BaseModel):
5244 5254 __tablename__ = 'user_bookmarks'
5245 5255 __table_args__ = (
5246 5256 UniqueConstraint('user_id', 'bookmark_repo_id'),
5247 5257 UniqueConstraint('user_id', 'bookmark_repo_group_id'),
5248 5258 UniqueConstraint('user_id', 'bookmark_position'),
5249 5259 base_table_args
5250 5260 )
5251 5261
5252 5262 user_bookmark_id = Column("user_bookmark_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
5253 5263 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
5254 5264 position = Column("bookmark_position", Integer(), nullable=False)
5255 5265 title = Column("bookmark_title", String(255), nullable=True, unique=None, default=None)
5256 5266 redirect_url = Column("bookmark_redirect_url", String(10240), nullable=True, unique=None, default=None)
5257 5267 created_on = Column("created_on", DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
5258 5268
5259 5269 bookmark_repo_id = Column("bookmark_repo_id", Integer(), ForeignKey("repositories.repo_id"), nullable=True, unique=None, default=None)
5260 5270 bookmark_repo_group_id = Column("bookmark_repo_group_id", Integer(), ForeignKey("groups.group_id"), nullable=True, unique=None, default=None)
5261 5271
5262 5272 user = relationship("User")
5263 5273
5264 5274 repository = relationship("Repository")
5265 5275 repository_group = relationship("RepoGroup")
5266 5276
5267 5277 @classmethod
5268 5278 def get_by_position_for_user(cls, position, user_id):
5269 5279 return cls.query() \
5270 5280 .filter(UserBookmark.user_id == user_id) \
5271 5281 .filter(UserBookmark.position == position).scalar()
5272 5282
5273 5283 @classmethod
5274 5284 def get_bookmarks_for_user(cls, user_id, cache=True):
5275 5285 bookmarks = cls.query() \
5276 5286 .filter(UserBookmark.user_id == user_id) \
5277 5287 .options(joinedload(UserBookmark.repository)) \
5278 5288 .options(joinedload(UserBookmark.repository_group)) \
5279 5289 .order_by(UserBookmark.position.asc())
5280 5290
5281 5291 if cache:
5282 5292 bookmarks = bookmarks.options(
5283 5293 FromCache("sql_cache_short", "get_user_{}_bookmarks".format(user_id))
5284 5294 )
5285 5295
5286 5296 return bookmarks.all()
5287 5297
5288 5298 def __unicode__(self):
5289 5299 return u'<UserBookmark(%s @ %r)>' % (self.position, self.redirect_url)
5290 5300
5291 5301
5292 5302 class FileStore(Base, BaseModel):
5293 5303 __tablename__ = 'file_store'
5294 5304 __table_args__ = (
5295 5305 base_table_args
5296 5306 )
5297 5307
5298 5308 file_store_id = Column('file_store_id', Integer(), primary_key=True)
5299 5309 file_uid = Column('file_uid', String(1024), nullable=False)
5300 5310 file_display_name = Column('file_display_name', UnicodeText().with_variant(UnicodeText(2048), 'mysql'), nullable=True)
5301 5311 file_description = Column('file_description', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=True)
5302 5312 file_org_name = Column('file_org_name', UnicodeText().with_variant(UnicodeText(10240), 'mysql'), nullable=False)
5303 5313
5304 5314 # sha256 hash
5305 5315 file_hash = Column('file_hash', String(512), nullable=False)
5306 5316 file_size = Column('file_size', BigInteger(), nullable=False)
5307 5317
5308 5318 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
5309 5319 accessed_on = Column('accessed_on', DateTime(timezone=False), nullable=True)
5310 5320 accessed_count = Column('accessed_count', Integer(), default=0)
5311 5321
5312 5322 enabled = Column('enabled', Boolean(), nullable=False, default=True)
5313 5323
5314 5324 # if repo/repo_group reference is set, check for permissions
5315 5325 check_acl = Column('check_acl', Boolean(), nullable=False, default=True)
5316 5326
5317 5327 # hidden defines an attachment that should be hidden from showing in artifact listing
5318 5328 hidden = Column('hidden', Boolean(), nullable=False, default=False)
5319 5329
5320 5330 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
5321 5331 upload_user = relationship('User', lazy='joined', primaryjoin='User.user_id==FileStore.user_id')
5322 5332
5323 5333 file_metadata = relationship('FileStoreMetadata', lazy='joined')
5324 5334
5325 5335 # scope limited to user, which requester have access to
5326 5336 scope_user_id = Column(
5327 5337 'scope_user_id', Integer(), ForeignKey('users.user_id'),
5328 5338 nullable=True, unique=None, default=None)
5329 5339 user = relationship('User', lazy='joined', primaryjoin='User.user_id==FileStore.scope_user_id')
5330 5340
5331 5341 # scope limited to user group, which requester have access to
5332 5342 scope_user_group_id = Column(
5333 5343 'scope_user_group_id', Integer(), ForeignKey('users_groups.users_group_id'),
5334 5344 nullable=True, unique=None, default=None)
5335 5345 user_group = relationship('UserGroup', lazy='joined')
5336 5346
5337 5347 # scope limited to repo, which requester have access to
5338 5348 scope_repo_id = Column(
5339 5349 'scope_repo_id', Integer(), ForeignKey('repositories.repo_id'),
5340 5350 nullable=True, unique=None, default=None)
5341 5351 repo = relationship('Repository', lazy='joined')
5342 5352
5343 5353 # scope limited to repo group, which requester have access to
5344 5354 scope_repo_group_id = Column(
5345 5355 'scope_repo_group_id', Integer(), ForeignKey('groups.group_id'),
5346 5356 nullable=True, unique=None, default=None)
5347 5357 repo_group = relationship('RepoGroup', lazy='joined')
5348 5358
5349 5359 @classmethod
5350 5360 def get_by_store_uid(cls, file_store_uid):
5351 5361 return FileStore.query().filter(FileStore.file_uid == file_store_uid).scalar()
5352 5362
5353 5363 @classmethod
5354 5364 def create(cls, file_uid, filename, file_hash, file_size, file_display_name='',
5355 5365 file_description='', enabled=True, hidden=False, check_acl=True,
5356 5366 user_id=None, scope_user_id=None, scope_repo_id=None, scope_repo_group_id=None):
5357 5367
5358 5368 store_entry = FileStore()
5359 5369 store_entry.file_uid = file_uid
5360 5370 store_entry.file_display_name = file_display_name
5361 5371 store_entry.file_org_name = filename
5362 5372 store_entry.file_size = file_size
5363 5373 store_entry.file_hash = file_hash
5364 5374 store_entry.file_description = file_description
5365 5375
5366 5376 store_entry.check_acl = check_acl
5367 5377 store_entry.enabled = enabled
5368 5378 store_entry.hidden = hidden
5369 5379
5370 5380 store_entry.user_id = user_id
5371 5381 store_entry.scope_user_id = scope_user_id
5372 5382 store_entry.scope_repo_id = scope_repo_id
5373 5383 store_entry.scope_repo_group_id = scope_repo_group_id
5374 5384
5375 5385 return store_entry
5376 5386
5377 5387 @classmethod
5378 5388 def store_metadata(cls, file_store_id, args, commit=True):
5379 5389 file_store = FileStore.get(file_store_id)
5380 5390 if file_store is None:
5381 5391 return
5382 5392
5383 5393 for section, key, value, value_type in args:
5384 5394 has_key = FileStoreMetadata().query() \
5385 5395 .filter(FileStoreMetadata.file_store_id == file_store.file_store_id) \
5386 5396 .filter(FileStoreMetadata.file_store_meta_section == section) \
5387 5397 .filter(FileStoreMetadata.file_store_meta_key == key) \
5388 5398 .scalar()
5389 5399 if has_key:
5390 5400 msg = 'key `{}` already defined under section `{}` for this file.'\
5391 5401 .format(key, section)
5392 5402 raise ArtifactMetadataDuplicate(msg, err_section=section, err_key=key)
5393 5403
5394 5404 # NOTE(marcink): raises ArtifactMetadataBadValueType
5395 5405 FileStoreMetadata.valid_value_type(value_type)
5396 5406
5397 5407 meta_entry = FileStoreMetadata()
5398 5408 meta_entry.file_store = file_store
5399 5409 meta_entry.file_store_meta_section = section
5400 5410 meta_entry.file_store_meta_key = key
5401 5411 meta_entry.file_store_meta_value_type = value_type
5402 5412 meta_entry.file_store_meta_value = value
5403 5413
5404 5414 Session().add(meta_entry)
5405 5415
5406 5416 try:
5407 5417 if commit:
5408 5418 Session().commit()
5409 5419 except IntegrityError:
5410 5420 Session().rollback()
5411 5421 raise ArtifactMetadataDuplicate('Duplicate section/key found for this file.')
5412 5422
5413 5423 @classmethod
5414 5424 def bump_access_counter(cls, file_uid, commit=True):
5415 5425 FileStore().query()\
5416 5426 .filter(FileStore.file_uid == file_uid)\
5417 5427 .update({FileStore.accessed_count: (FileStore.accessed_count + 1),
5418 5428 FileStore.accessed_on: datetime.datetime.now()})
5419 5429 if commit:
5420 5430 Session().commit()
5421 5431
5422 5432 def __json__(self):
5423 5433 data = {
5424 5434 'filename': self.file_display_name,
5425 5435 'filename_org': self.file_org_name,
5426 5436 'file_uid': self.file_uid,
5427 5437 'description': self.file_description,
5428 5438 'hidden': self.hidden,
5429 5439 'size': self.file_size,
5430 5440 'created_on': self.created_on,
5431 5441 'uploaded_by': self.upload_user.get_api_data(details='basic'),
5432 5442 'downloaded_times': self.accessed_count,
5433 5443 'sha256': self.file_hash,
5434 5444 'metadata': self.file_metadata,
5435 5445 }
5436 5446
5437 5447 return data
5438 5448
5439 5449 def __repr__(self):
5440 5450 return '<FileStore({})>'.format(self.file_store_id)
5441 5451
5442 5452
5443 5453 class FileStoreMetadata(Base, BaseModel):
5444 5454 __tablename__ = 'file_store_metadata'
5445 5455 __table_args__ = (
5446 5456 UniqueConstraint('file_store_id', 'file_store_meta_section_hash', 'file_store_meta_key_hash'),
5447 5457 Index('file_store_meta_section_idx', 'file_store_meta_section', mysql_length=255),
5448 5458 Index('file_store_meta_key_idx', 'file_store_meta_key', mysql_length=255),
5449 5459 base_table_args
5450 5460 )
5451 5461 SETTINGS_TYPES = {
5452 5462 'str': safe_str,
5453 5463 'int': safe_int,
5454 5464 'unicode': safe_unicode,
5455 5465 'bool': str2bool,
5456 5466 'list': functools.partial(aslist, sep=',')
5457 5467 }
5458 5468
5459 5469 file_store_meta_id = Column(
5460 5470 "file_store_meta_id", Integer(), nullable=False, unique=True, default=None,
5461 5471 primary_key=True)
5462 5472 _file_store_meta_section = Column(
5463 5473 "file_store_meta_section", UnicodeText().with_variant(UnicodeText(1024), 'mysql'),
5464 5474 nullable=True, unique=None, default=None)
5465 5475 _file_store_meta_section_hash = Column(
5466 5476 "file_store_meta_section_hash", String(255),
5467 5477 nullable=True, unique=None, default=None)
5468 5478 _file_store_meta_key = Column(
5469 5479 "file_store_meta_key", UnicodeText().with_variant(UnicodeText(1024), 'mysql'),
5470 5480 nullable=True, unique=None, default=None)
5471 5481 _file_store_meta_key_hash = Column(
5472 5482 "file_store_meta_key_hash", String(255), nullable=True, unique=None, default=None)
5473 5483 _file_store_meta_value = Column(
5474 5484 "file_store_meta_value", UnicodeText().with_variant(UnicodeText(20480), 'mysql'),
5475 5485 nullable=True, unique=None, default=None)
5476 5486 _file_store_meta_value_type = Column(
5477 5487 "file_store_meta_value_type", String(255), nullable=True, unique=None,
5478 5488 default='unicode')
5479 5489
5480 5490 file_store_id = Column(
5481 5491 'file_store_id', Integer(), ForeignKey('file_store.file_store_id'),
5482 5492 nullable=True, unique=None, default=None)
5483 5493
5484 5494 file_store = relationship('FileStore', lazy='joined')
5485 5495
5486 5496 @classmethod
5487 5497 def valid_value_type(cls, value):
5488 5498 if value.split('.')[0] not in cls.SETTINGS_TYPES:
5489 5499 raise ArtifactMetadataBadValueType(
5490 5500 'value_type must be one of %s got %s' % (cls.SETTINGS_TYPES.keys(), value))
5491 5501
5492 5502 @hybrid_property
5493 5503 def file_store_meta_section(self):
5494 5504 return self._file_store_meta_section
5495 5505
5496 5506 @file_store_meta_section.setter
5497 5507 def file_store_meta_section(self, value):
5498 5508 self._file_store_meta_section = value
5499 5509 self._file_store_meta_section_hash = _hash_key(value)
5500 5510
5501 5511 @hybrid_property
5502 5512 def file_store_meta_key(self):
5503 5513 return self._file_store_meta_key
5504 5514
5505 5515 @file_store_meta_key.setter
5506 5516 def file_store_meta_key(self, value):
5507 5517 self._file_store_meta_key = value
5508 5518 self._file_store_meta_key_hash = _hash_key(value)
5509 5519
5510 5520 @hybrid_property
5511 5521 def file_store_meta_value(self):
5512 5522 val = self._file_store_meta_value
5513 5523
5514 5524 if self._file_store_meta_value_type:
5515 5525 # e.g unicode.encrypted == unicode
5516 5526 _type = self._file_store_meta_value_type.split('.')[0]
5517 5527 # decode the encrypted value if it's encrypted field type
5518 5528 if '.encrypted' in self._file_store_meta_value_type:
5519 5529 cipher = EncryptedTextValue()
5520 5530 val = safe_unicode(cipher.process_result_value(val, None))
5521 5531 # do final type conversion
5522 5532 converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
5523 5533 val = converter(val)
5524 5534
5525 5535 return val
5526 5536
5527 5537 @file_store_meta_value.setter
5528 5538 def file_store_meta_value(self, val):
5529 5539 val = safe_unicode(val)
5530 5540 # encode the encrypted value
5531 5541 if '.encrypted' in self.file_store_meta_value_type:
5532 5542 cipher = EncryptedTextValue()
5533 5543 val = safe_unicode(cipher.process_bind_param(val, None))
5534 5544 self._file_store_meta_value = val
5535 5545
5536 5546 @hybrid_property
5537 5547 def file_store_meta_value_type(self):
5538 5548 return self._file_store_meta_value_type
5539 5549
5540 5550 @file_store_meta_value_type.setter
5541 5551 def file_store_meta_value_type(self, val):
5542 5552 # e.g unicode.encrypted
5543 5553 self.valid_value_type(val)
5544 5554 self._file_store_meta_value_type = val
5545 5555
5546 5556 def __json__(self):
5547 5557 data = {
5548 5558 'artifact': self.file_store.file_uid,
5549 5559 'section': self.file_store_meta_section,
5550 5560 'key': self.file_store_meta_key,
5551 5561 'value': self.file_store_meta_value,
5552 5562 }
5553 5563
5554 5564 return data
5555 5565
5556 5566 def __repr__(self):
5557 5567 return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.file_store_meta_section,
5558 5568 self.file_store_meta_key, self.file_store_meta_value)
5559 5569
5560 5570
5561 5571 class DbMigrateVersion(Base, BaseModel):
5562 5572 __tablename__ = 'db_migrate_version'
5563 5573 __table_args__ = (
5564 5574 base_table_args,
5565 5575 )
5566 5576
5567 5577 repository_id = Column('repository_id', String(250), primary_key=True)
5568 5578 repository_path = Column('repository_path', Text)
5569 5579 version = Column('version', Integer)
5570 5580
5571 5581 @classmethod
5572 5582 def set_version(cls, version):
5573 5583 """
5574 5584 Helper for forcing a different version, usually for debugging purposes via ishell.
5575 5585 """
5576 5586 ver = DbMigrateVersion.query().first()
5577 5587 ver.version = version
5578 5588 Session().commit()
5579 5589
5580 5590
5581 5591 class DbSession(Base, BaseModel):
5582 5592 __tablename__ = 'db_session'
5583 5593 __table_args__ = (
5584 5594 base_table_args,
5585 5595 )
5586 5596
5587 5597 def __repr__(self):
5588 5598 return '<DB:DbSession({})>'.format(self.id)
5589 5599
5590 5600 id = Column('id', Integer())
5591 5601 namespace = Column('namespace', String(255), primary_key=True)
5592 5602 accessed = Column('accessed', DateTime, nullable=False)
5593 5603 created = Column('created', DateTime, nullable=False)
5594 5604 data = Column('data', PickleType, nullable=False)
@@ -1,2072 +1,2072 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2012-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21
22 22 """
23 23 pull request model for RhodeCode
24 24 """
25 25
26 26
27 27 import json
28 28 import logging
29 29 import os
30 30
31 31 import datetime
32 32 import urllib
33 33 import collections
34 34
35 35 from pyramid import compat
36 36 from pyramid.threadlocal import get_current_request
37 37
38 38 from rhodecode.lib.vcs.nodes import FileNode
39 39 from rhodecode.translation import lazy_ugettext
40 40 from rhodecode.lib import helpers as h, hooks_utils, diffs
41 41 from rhodecode.lib import audit_logger
42 42 from rhodecode.lib.compat import OrderedDict
43 43 from rhodecode.lib.hooks_daemon import prepare_callback_daemon
44 44 from rhodecode.lib.markup_renderer import (
45 45 DEFAULT_COMMENTS_RENDERER, RstTemplateRenderer)
46 46 from rhodecode.lib.utils2 import (
47 47 safe_unicode, safe_str, md5_safe, AttributeDict, safe_int,
48 48 get_current_rhodecode_user)
49 49 from rhodecode.lib.vcs.backends.base import (
50 50 Reference, MergeResponse, MergeFailureReason, UpdateFailureReason,
51 51 TargetRefMissing, SourceRefMissing)
52 52 from rhodecode.lib.vcs.conf import settings as vcs_settings
53 53 from rhodecode.lib.vcs.exceptions import (
54 54 CommitDoesNotExistError, EmptyRepositoryError)
55 55 from rhodecode.model import BaseModel
56 56 from rhodecode.model.changeset_status import ChangesetStatusModel
57 57 from rhodecode.model.comment import CommentsModel
58 58 from rhodecode.model.db import (
59 59 or_, String, cast, PullRequest, PullRequestReviewers, ChangesetStatus,
60 60 PullRequestVersion, ChangesetComment, Repository, RepoReviewRule, User)
61 61 from rhodecode.model.meta import Session
62 62 from rhodecode.model.notification import NotificationModel, \
63 63 EmailNotificationModel
64 64 from rhodecode.model.scm import ScmModel
65 65 from rhodecode.model.settings import VcsSettingsModel
66 66
67 67
68 68 log = logging.getLogger(__name__)
69 69
70 70
71 71 # Data structure to hold the response data when updating commits during a pull
72 72 # request update.
73 73 class UpdateResponse(object):
74 74
75 75 def __init__(self, executed, reason, new, old, common_ancestor_id,
76 76 commit_changes, source_changed, target_changed):
77 77
78 78 self.executed = executed
79 79 self.reason = reason
80 80 self.new = new
81 81 self.old = old
82 82 self.common_ancestor_id = common_ancestor_id
83 83 self.changes = commit_changes
84 84 self.source_changed = source_changed
85 85 self.target_changed = target_changed
86 86
87 87
88 88 def get_diff_info(
89 89 source_repo, source_ref, target_repo, target_ref, get_authors=False,
90 90 get_commit_authors=True):
91 91 """
92 92 Calculates detailed diff information for usage in preview of creation of a pull-request.
93 93 This is also used for default reviewers logic
94 94 """
95 95
96 96 source_scm = source_repo.scm_instance()
97 97 target_scm = target_repo.scm_instance()
98 98
99 99 ancestor_id = target_scm.get_common_ancestor(target_ref, source_ref, source_scm)
100 100 if not ancestor_id:
101 101 raise ValueError(
102 102 'cannot calculate diff info without a common ancestor. '
103 103 'Make sure both repositories are related, and have a common forking commit.')
104 104
105 105 # case here is that want a simple diff without incoming commits,
106 106 # previewing what will be merged based only on commits in the source.
107 107 log.debug('Using ancestor %s as source_ref instead of %s',
108 108 ancestor_id, source_ref)
109 109
110 110 # source of changes now is the common ancestor
111 111 source_commit = source_scm.get_commit(commit_id=ancestor_id)
112 112 # target commit becomes the source ref as it is the last commit
113 113 # for diff generation this logic gives proper diff
114 114 target_commit = source_scm.get_commit(commit_id=source_ref)
115 115
116 116 vcs_diff = \
117 117 source_scm.get_diff(commit1=source_commit, commit2=target_commit,
118 118 ignore_whitespace=False, context=3)
119 119
120 120 diff_processor = diffs.DiffProcessor(
121 121 vcs_diff, format='newdiff', diff_limit=None,
122 122 file_limit=None, show_full_diff=True)
123 123
124 124 _parsed = diff_processor.prepare()
125 125
126 126 all_files = []
127 127 all_files_changes = []
128 128 changed_lines = {}
129 129 stats = [0, 0]
130 130 for f in _parsed:
131 131 all_files.append(f['filename'])
132 132 all_files_changes.append({
133 133 'filename': f['filename'],
134 134 'stats': f['stats']
135 135 })
136 136 stats[0] += f['stats']['added']
137 137 stats[1] += f['stats']['deleted']
138 138
139 139 changed_lines[f['filename']] = []
140 140 if len(f['chunks']) < 2:
141 141 continue
142 142 # first line is "context" information
143 143 for chunks in f['chunks'][1:]:
144 144 for chunk in chunks['lines']:
145 145 if chunk['action'] not in ('del', 'mod'):
146 146 continue
147 147 changed_lines[f['filename']].append(chunk['old_lineno'])
148 148
149 149 commit_authors = []
150 150 user_counts = {}
151 151 email_counts = {}
152 152 author_counts = {}
153 153 _commit_cache = {}
154 154
155 155 commits = []
156 156 if get_commit_authors:
157 157 commits = target_scm.compare(
158 158 target_ref, source_ref, source_scm, merge=True,
159 159 pre_load=["author"])
160 160
161 161 for commit in commits:
162 162 user = User.get_from_cs_author(commit.author)
163 163 if user and user not in commit_authors:
164 164 commit_authors.append(user)
165 165
166 166 # lines
167 167 if get_authors:
168 168 target_commit = source_repo.get_commit(ancestor_id)
169 169
170 170 for fname, lines in changed_lines.items():
171 171 try:
172 172 node = target_commit.get_node(fname)
173 173 except Exception:
174 174 continue
175 175
176 176 if not isinstance(node, FileNode):
177 177 continue
178 178
179 179 for annotation in node.annotate:
180 180 line_no, commit_id, get_commit_func, line_text = annotation
181 181 if line_no in lines:
182 182 if commit_id not in _commit_cache:
183 183 _commit_cache[commit_id] = get_commit_func()
184 184 commit = _commit_cache[commit_id]
185 185 author = commit.author
186 186 email = commit.author_email
187 187 user = User.get_from_cs_author(author)
188 188 if user:
189 user_counts[user] = user_counts.get(user, 0) + 1
189 user_counts[user.user_id] = user_counts.get(user.user_id, 0) + 1
190 190 author_counts[author] = author_counts.get(author, 0) + 1
191 191 email_counts[email] = email_counts.get(email, 0) + 1
192 192
193 193 return {
194 194 'commits': commits,
195 195 'files': all_files_changes,
196 196 'stats': stats,
197 197 'ancestor': ancestor_id,
198 198 # original authors of modified files
199 199 'original_authors': {
200 200 'users': user_counts,
201 201 'authors': author_counts,
202 202 'emails': email_counts,
203 203 },
204 204 'commit_authors': commit_authors
205 205 }
206 206
207 207
208 208 class PullRequestModel(BaseModel):
209 209
210 210 cls = PullRequest
211 211
212 212 DIFF_CONTEXT = diffs.DEFAULT_CONTEXT
213 213
214 214 UPDATE_STATUS_MESSAGES = {
215 215 UpdateFailureReason.NONE: lazy_ugettext(
216 216 'Pull request update successful.'),
217 217 UpdateFailureReason.UNKNOWN: lazy_ugettext(
218 218 'Pull request update failed because of an unknown error.'),
219 219 UpdateFailureReason.NO_CHANGE: lazy_ugettext(
220 220 'No update needed because the source and target have not changed.'),
221 221 UpdateFailureReason.WRONG_REF_TYPE: lazy_ugettext(
222 222 'Pull request cannot be updated because the reference type is '
223 223 'not supported for an update. Only Branch, Tag or Bookmark is allowed.'),
224 224 UpdateFailureReason.MISSING_TARGET_REF: lazy_ugettext(
225 225 'This pull request cannot be updated because the target '
226 226 'reference is missing.'),
227 227 UpdateFailureReason.MISSING_SOURCE_REF: lazy_ugettext(
228 228 'This pull request cannot be updated because the source '
229 229 'reference is missing.'),
230 230 }
231 231 REF_TYPES = ['bookmark', 'book', 'tag', 'branch']
232 232 UPDATABLE_REF_TYPES = ['bookmark', 'book', 'branch']
233 233
234 234 def __get_pull_request(self, pull_request):
235 235 return self._get_instance((
236 236 PullRequest, PullRequestVersion), pull_request)
237 237
238 238 def _check_perms(self, perms, pull_request, user, api=False):
239 239 if not api:
240 240 return h.HasRepoPermissionAny(*perms)(
241 241 user=user, repo_name=pull_request.target_repo.repo_name)
242 242 else:
243 243 return h.HasRepoPermissionAnyApi(*perms)(
244 244 user=user, repo_name=pull_request.target_repo.repo_name)
245 245
246 246 def check_user_read(self, pull_request, user, api=False):
247 247 _perms = ('repository.admin', 'repository.write', 'repository.read',)
248 248 return self._check_perms(_perms, pull_request, user, api)
249 249
250 250 def check_user_merge(self, pull_request, user, api=False):
251 251 _perms = ('repository.admin', 'repository.write', 'hg.admin',)
252 252 return self._check_perms(_perms, pull_request, user, api)
253 253
254 254 def check_user_update(self, pull_request, user, api=False):
255 255 owner = user.user_id == pull_request.user_id
256 256 return self.check_user_merge(pull_request, user, api) or owner
257 257
258 258 def check_user_delete(self, pull_request, user):
259 259 owner = user.user_id == pull_request.user_id
260 260 _perms = ('repository.admin',)
261 261 return self._check_perms(_perms, pull_request, user) or owner
262 262
263 263 def check_user_change_status(self, pull_request, user, api=False):
264 264 reviewer = user.user_id in [x.user_id for x in
265 265 pull_request.reviewers]
266 266 return self.check_user_update(pull_request, user, api) or reviewer
267 267
268 268 def check_user_comment(self, pull_request, user):
269 269 owner = user.user_id == pull_request.user_id
270 270 return self.check_user_read(pull_request, user) or owner
271 271
272 272 def get(self, pull_request):
273 273 return self.__get_pull_request(pull_request)
274 274
275 275 def _prepare_get_all_query(self, repo_name, search_q=None, source=False,
276 276 statuses=None, opened_by=None, order_by=None,
277 277 order_dir='desc', only_created=False):
278 278 repo = None
279 279 if repo_name:
280 280 repo = self._get_repo(repo_name)
281 281
282 282 q = PullRequest.query()
283 283
284 284 if search_q:
285 285 like_expression = u'%{}%'.format(safe_unicode(search_q))
286 286 q = q.join(User)
287 287 q = q.filter(or_(
288 288 cast(PullRequest.pull_request_id, String).ilike(like_expression),
289 289 User.username.ilike(like_expression),
290 290 PullRequest.title.ilike(like_expression),
291 291 PullRequest.description.ilike(like_expression),
292 292 ))
293 293
294 294 # source or target
295 295 if repo and source:
296 296 q = q.filter(PullRequest.source_repo == repo)
297 297 elif repo:
298 298 q = q.filter(PullRequest.target_repo == repo)
299 299
300 300 # closed,opened
301 301 if statuses:
302 302 q = q.filter(PullRequest.status.in_(statuses))
303 303
304 304 # opened by filter
305 305 if opened_by:
306 306 q = q.filter(PullRequest.user_id.in_(opened_by))
307 307
308 308 # only get those that are in "created" state
309 309 if only_created:
310 310 q = q.filter(PullRequest.pull_request_state == PullRequest.STATE_CREATED)
311 311
312 312 if order_by:
313 313 order_map = {
314 314 'name_raw': PullRequest.pull_request_id,
315 315 'id': PullRequest.pull_request_id,
316 316 'title': PullRequest.title,
317 317 'updated_on_raw': PullRequest.updated_on,
318 318 'target_repo': PullRequest.target_repo_id
319 319 }
320 320 if order_dir == 'asc':
321 321 q = q.order_by(order_map[order_by].asc())
322 322 else:
323 323 q = q.order_by(order_map[order_by].desc())
324 324
325 325 return q
326 326
327 327 def count_all(self, repo_name, search_q=None, source=False, statuses=None,
328 328 opened_by=None):
329 329 """
330 330 Count the number of pull requests for a specific repository.
331 331
332 332 :param repo_name: target or source repo
333 333 :param search_q: filter by text
334 334 :param source: boolean flag to specify if repo_name refers to source
335 335 :param statuses: list of pull request statuses
336 336 :param opened_by: author user of the pull request
337 337 :returns: int number of pull requests
338 338 """
339 339 q = self._prepare_get_all_query(
340 340 repo_name, search_q=search_q, source=source, statuses=statuses,
341 341 opened_by=opened_by)
342 342
343 343 return q.count()
344 344
345 345 def get_all(self, repo_name, search_q=None, source=False, statuses=None,
346 346 opened_by=None, offset=0, length=None, order_by=None, order_dir='desc'):
347 347 """
348 348 Get all pull requests for a specific repository.
349 349
350 350 :param repo_name: target or source repo
351 351 :param search_q: filter by text
352 352 :param source: boolean flag to specify if repo_name refers to source
353 353 :param statuses: list of pull request statuses
354 354 :param opened_by: author user of the pull request
355 355 :param offset: pagination offset
356 356 :param length: length of returned list
357 357 :param order_by: order of the returned list
358 358 :param order_dir: 'asc' or 'desc' ordering direction
359 359 :returns: list of pull requests
360 360 """
361 361 q = self._prepare_get_all_query(
362 362 repo_name, search_q=search_q, source=source, statuses=statuses,
363 363 opened_by=opened_by, order_by=order_by, order_dir=order_dir)
364 364
365 365 if length:
366 366 pull_requests = q.limit(length).offset(offset).all()
367 367 else:
368 368 pull_requests = q.all()
369 369
370 370 return pull_requests
371 371
372 372 def count_awaiting_review(self, repo_name, search_q=None, source=False, statuses=None,
373 373 opened_by=None):
374 374 """
375 375 Count the number of pull requests for a specific repository that are
376 376 awaiting review.
377 377
378 378 :param repo_name: target or source repo
379 379 :param search_q: filter by text
380 380 :param source: boolean flag to specify if repo_name refers to source
381 381 :param statuses: list of pull request statuses
382 382 :param opened_by: author user of the pull request
383 383 :returns: int number of pull requests
384 384 """
385 385 pull_requests = self.get_awaiting_review(
386 386 repo_name, search_q=search_q, source=source, statuses=statuses, opened_by=opened_by)
387 387
388 388 return len(pull_requests)
389 389
390 390 def get_awaiting_review(self, repo_name, search_q=None, source=False, statuses=None,
391 391 opened_by=None, offset=0, length=None,
392 392 order_by=None, order_dir='desc'):
393 393 """
394 394 Get all pull requests for a specific repository that are awaiting
395 395 review.
396 396
397 397 :param repo_name: target or source repo
398 398 :param search_q: filter by text
399 399 :param source: boolean flag to specify if repo_name refers to source
400 400 :param statuses: list of pull request statuses
401 401 :param opened_by: author user of the pull request
402 402 :param offset: pagination offset
403 403 :param length: length of returned list
404 404 :param order_by: order of the returned list
405 405 :param order_dir: 'asc' or 'desc' ordering direction
406 406 :returns: list of pull requests
407 407 """
408 408 pull_requests = self.get_all(
409 409 repo_name, search_q=search_q, source=source, statuses=statuses,
410 410 opened_by=opened_by, order_by=order_by, order_dir=order_dir)
411 411
412 412 _filtered_pull_requests = []
413 413 for pr in pull_requests:
414 414 status = pr.calculated_review_status()
415 415 if status in [ChangesetStatus.STATUS_NOT_REVIEWED,
416 416 ChangesetStatus.STATUS_UNDER_REVIEW]:
417 417 _filtered_pull_requests.append(pr)
418 418 if length:
419 419 return _filtered_pull_requests[offset:offset+length]
420 420 else:
421 421 return _filtered_pull_requests
422 422
423 423 def count_awaiting_my_review(self, repo_name, search_q=None, source=False, statuses=None,
424 424 opened_by=None, user_id=None):
425 425 """
426 426 Count the number of pull requests for a specific repository that are
427 427 awaiting review from a specific user.
428 428
429 429 :param repo_name: target or source repo
430 430 :param search_q: filter by text
431 431 :param source: boolean flag to specify if repo_name refers to source
432 432 :param statuses: list of pull request statuses
433 433 :param opened_by: author user of the pull request
434 434 :param user_id: reviewer user of the pull request
435 435 :returns: int number of pull requests
436 436 """
437 437 pull_requests = self.get_awaiting_my_review(
438 438 repo_name, search_q=search_q, source=source, statuses=statuses,
439 439 opened_by=opened_by, user_id=user_id)
440 440
441 441 return len(pull_requests)
442 442
443 443 def get_awaiting_my_review(self, repo_name, search_q=None, source=False, statuses=None,
444 444 opened_by=None, user_id=None, offset=0,
445 445 length=None, order_by=None, order_dir='desc'):
446 446 """
447 447 Get all pull requests for a specific repository that are awaiting
448 448 review from a specific user.
449 449
450 450 :param repo_name: target or source repo
451 451 :param search_q: filter by text
452 452 :param source: boolean flag to specify if repo_name refers to source
453 453 :param statuses: list of pull request statuses
454 454 :param opened_by: author user of the pull request
455 455 :param user_id: reviewer user of the pull request
456 456 :param offset: pagination offset
457 457 :param length: length of returned list
458 458 :param order_by: order of the returned list
459 459 :param order_dir: 'asc' or 'desc' ordering direction
460 460 :returns: list of pull requests
461 461 """
462 462 pull_requests = self.get_all(
463 463 repo_name, search_q=search_q, source=source, statuses=statuses,
464 464 opened_by=opened_by, order_by=order_by, order_dir=order_dir)
465 465
466 466 _my = PullRequestModel().get_not_reviewed(user_id)
467 467 my_participation = []
468 468 for pr in pull_requests:
469 469 if pr in _my:
470 470 my_participation.append(pr)
471 471 _filtered_pull_requests = my_participation
472 472 if length:
473 473 return _filtered_pull_requests[offset:offset+length]
474 474 else:
475 475 return _filtered_pull_requests
476 476
477 477 def get_not_reviewed(self, user_id):
478 478 return [
479 479 x.pull_request for x in PullRequestReviewers.query().filter(
480 480 PullRequestReviewers.user_id == user_id).all()
481 481 ]
482 482
483 483 def _prepare_participating_query(self, user_id=None, statuses=None, query='',
484 484 order_by=None, order_dir='desc'):
485 485 q = PullRequest.query()
486 486 if user_id:
487 487 reviewers_subquery = Session().query(
488 488 PullRequestReviewers.pull_request_id).filter(
489 489 PullRequestReviewers.user_id == user_id).subquery()
490 490 user_filter = or_(
491 491 PullRequest.user_id == user_id,
492 492 PullRequest.pull_request_id.in_(reviewers_subquery)
493 493 )
494 494 q = PullRequest.query().filter(user_filter)
495 495
496 496 # closed,opened
497 497 if statuses:
498 498 q = q.filter(PullRequest.status.in_(statuses))
499 499
500 500 if query:
501 501 like_expression = u'%{}%'.format(safe_unicode(query))
502 502 q = q.join(User)
503 503 q = q.filter(or_(
504 504 cast(PullRequest.pull_request_id, String).ilike(like_expression),
505 505 User.username.ilike(like_expression),
506 506 PullRequest.title.ilike(like_expression),
507 507 PullRequest.description.ilike(like_expression),
508 508 ))
509 509 if order_by:
510 510 order_map = {
511 511 'name_raw': PullRequest.pull_request_id,
512 512 'title': PullRequest.title,
513 513 'updated_on_raw': PullRequest.updated_on,
514 514 'target_repo': PullRequest.target_repo_id
515 515 }
516 516 if order_dir == 'asc':
517 517 q = q.order_by(order_map[order_by].asc())
518 518 else:
519 519 q = q.order_by(order_map[order_by].desc())
520 520
521 521 return q
522 522
523 523 def count_im_participating_in(self, user_id=None, statuses=None, query=''):
524 524 q = self._prepare_participating_query(user_id, statuses=statuses, query=query)
525 525 return q.count()
526 526
527 527 def get_im_participating_in(
528 528 self, user_id=None, statuses=None, query='', offset=0,
529 529 length=None, order_by=None, order_dir='desc'):
530 530 """
531 531 Get all Pull requests that i'm participating in, or i have opened
532 532 """
533 533
534 534 q = self._prepare_participating_query(
535 535 user_id, statuses=statuses, query=query, order_by=order_by,
536 536 order_dir=order_dir)
537 537
538 538 if length:
539 539 pull_requests = q.limit(length).offset(offset).all()
540 540 else:
541 541 pull_requests = q.all()
542 542
543 543 return pull_requests
544 544
545 545 def get_versions(self, pull_request):
546 546 """
547 547 returns version of pull request sorted by ID descending
548 548 """
549 549 return PullRequestVersion.query()\
550 550 .filter(PullRequestVersion.pull_request == pull_request)\
551 551 .order_by(PullRequestVersion.pull_request_version_id.asc())\
552 552 .all()
553 553
554 554 def get_pr_version(self, pull_request_id, version=None):
555 555 at_version = None
556 556
557 557 if version and version == 'latest':
558 558 pull_request_ver = PullRequest.get(pull_request_id)
559 559 pull_request_obj = pull_request_ver
560 560 _org_pull_request_obj = pull_request_obj
561 561 at_version = 'latest'
562 562 elif version:
563 563 pull_request_ver = PullRequestVersion.get_or_404(version)
564 564 pull_request_obj = pull_request_ver
565 565 _org_pull_request_obj = pull_request_ver.pull_request
566 566 at_version = pull_request_ver.pull_request_version_id
567 567 else:
568 568 _org_pull_request_obj = pull_request_obj = PullRequest.get_or_404(
569 569 pull_request_id)
570 570
571 571 pull_request_display_obj = PullRequest.get_pr_display_object(
572 572 pull_request_obj, _org_pull_request_obj)
573 573
574 574 return _org_pull_request_obj, pull_request_obj, \
575 575 pull_request_display_obj, at_version
576 576
577 577 def create(self, created_by, source_repo, source_ref, target_repo,
578 578 target_ref, revisions, reviewers, title, description=None,
579 579 common_ancestor_id=None,
580 580 description_renderer=None,
581 581 reviewer_data=None, translator=None, auth_user=None):
582 582 translator = translator or get_current_request().translate
583 583
584 584 created_by_user = self._get_user(created_by)
585 585 auth_user = auth_user or created_by_user.AuthUser()
586 586 source_repo = self._get_repo(source_repo)
587 587 target_repo = self._get_repo(target_repo)
588 588
589 589 pull_request = PullRequest()
590 590 pull_request.source_repo = source_repo
591 591 pull_request.source_ref = source_ref
592 592 pull_request.target_repo = target_repo
593 593 pull_request.target_ref = target_ref
594 594 pull_request.revisions = revisions
595 595 pull_request.title = title
596 596 pull_request.description = description
597 597 pull_request.description_renderer = description_renderer
598 598 pull_request.author = created_by_user
599 599 pull_request.reviewer_data = reviewer_data
600 600 pull_request.pull_request_state = pull_request.STATE_CREATING
601 601 pull_request.common_ancestor_id = common_ancestor_id
602 602
603 603 Session().add(pull_request)
604 604 Session().flush()
605 605
606 606 reviewer_ids = set()
607 607 # members / reviewers
608 608 for reviewer_object in reviewers:
609 609 user_id, reasons, mandatory, rules = reviewer_object
610 610 user = self._get_user(user_id)
611 611
612 612 # skip duplicates
613 613 if user.user_id in reviewer_ids:
614 614 continue
615 615
616 616 reviewer_ids.add(user.user_id)
617 617
618 618 reviewer = PullRequestReviewers()
619 619 reviewer.user = user
620 620 reviewer.pull_request = pull_request
621 621 reviewer.reasons = reasons
622 622 reviewer.mandatory = mandatory
623 623
624 624 # NOTE(marcink): pick only first rule for now
625 625 rule_id = list(rules)[0] if rules else None
626 626 rule = RepoReviewRule.get(rule_id) if rule_id else None
627 627 if rule:
628 628 review_group = rule.user_group_vote_rule(user_id)
629 629 # we check if this particular reviewer is member of a voting group
630 630 if review_group:
631 631 # NOTE(marcink):
632 632 # can be that user is member of more but we pick the first same,
633 633 # same as default reviewers algo
634 634 review_group = review_group[0]
635 635
636 636 rule_data = {
637 637 'rule_name':
638 638 rule.review_rule_name,
639 639 'rule_user_group_entry_id':
640 640 review_group.repo_review_rule_users_group_id,
641 641 'rule_user_group_name':
642 642 review_group.users_group.users_group_name,
643 643 'rule_user_group_members':
644 644 [x.user.username for x in review_group.users_group.members],
645 645 'rule_user_group_members_id':
646 646 [x.user.user_id for x in review_group.users_group.members],
647 647 }
648 648 # e.g {'vote_rule': -1, 'mandatory': True}
649 649 rule_data.update(review_group.rule_data())
650 650
651 651 reviewer.rule_data = rule_data
652 652
653 653 Session().add(reviewer)
654 654 Session().flush()
655 655
656 656 # Set approval status to "Under Review" for all commits which are
657 657 # part of this pull request.
658 658 ChangesetStatusModel().set_status(
659 659 repo=target_repo,
660 660 status=ChangesetStatus.STATUS_UNDER_REVIEW,
661 661 user=created_by_user,
662 662 pull_request=pull_request
663 663 )
664 664 # we commit early at this point. This has to do with a fact
665 665 # that before queries do some row-locking. And because of that
666 666 # we need to commit and finish transaction before below validate call
667 667 # that for large repos could be long resulting in long row locks
668 668 Session().commit()
669 669
670 670 # prepare workspace, and run initial merge simulation. Set state during that
671 671 # operation
672 672 pull_request = PullRequest.get(pull_request.pull_request_id)
673 673
674 674 # set as merging, for merge simulation, and if finished to created so we mark
675 675 # simulation is working fine
676 676 with pull_request.set_state(PullRequest.STATE_MERGING,
677 677 final_state=PullRequest.STATE_CREATED) as state_obj:
678 678 MergeCheck.validate(
679 679 pull_request, auth_user=auth_user, translator=translator)
680 680
681 681 self.notify_reviewers(pull_request, reviewer_ids)
682 682 self.trigger_pull_request_hook(pull_request, created_by_user, 'create')
683 683
684 684 creation_data = pull_request.get_api_data(with_merge_state=False)
685 685 self._log_audit_action(
686 686 'repo.pull_request.create', {'data': creation_data},
687 687 auth_user, pull_request)
688 688
689 689 return pull_request
690 690
691 691 def trigger_pull_request_hook(self, pull_request, user, action, data=None):
692 692 pull_request = self.__get_pull_request(pull_request)
693 693 target_scm = pull_request.target_repo.scm_instance()
694 694 if action == 'create':
695 695 trigger_hook = hooks_utils.trigger_create_pull_request_hook
696 696 elif action == 'merge':
697 697 trigger_hook = hooks_utils.trigger_merge_pull_request_hook
698 698 elif action == 'close':
699 699 trigger_hook = hooks_utils.trigger_close_pull_request_hook
700 700 elif action == 'review_status_change':
701 701 trigger_hook = hooks_utils.trigger_review_pull_request_hook
702 702 elif action == 'update':
703 703 trigger_hook = hooks_utils.trigger_update_pull_request_hook
704 704 elif action == 'comment':
705 705 trigger_hook = hooks_utils.trigger_comment_pull_request_hook
706 706 else:
707 707 return
708 708
709 709 log.debug('Handling pull_request %s trigger_pull_request_hook with action %s and hook: %s',
710 710 pull_request, action, trigger_hook)
711 711 trigger_hook(
712 712 username=user.username,
713 713 repo_name=pull_request.target_repo.repo_name,
714 714 repo_type=target_scm.alias,
715 715 pull_request=pull_request,
716 716 data=data)
717 717
718 718 def _get_commit_ids(self, pull_request):
719 719 """
720 720 Return the commit ids of the merged pull request.
721 721
722 722 This method is not dealing correctly yet with the lack of autoupdates
723 723 nor with the implicit target updates.
724 724 For example: if a commit in the source repo is already in the target it
725 725 will be reported anyways.
726 726 """
727 727 merge_rev = pull_request.merge_rev
728 728 if merge_rev is None:
729 729 raise ValueError('This pull request was not merged yet')
730 730
731 731 commit_ids = list(pull_request.revisions)
732 732 if merge_rev not in commit_ids:
733 733 commit_ids.append(merge_rev)
734 734
735 735 return commit_ids
736 736
737 737 def merge_repo(self, pull_request, user, extras):
738 738 log.debug("Merging pull request %s", pull_request.pull_request_id)
739 739 extras['user_agent'] = 'internal-merge'
740 740 merge_state = self._merge_pull_request(pull_request, user, extras)
741 741 if merge_state.executed:
742 742 log.debug("Merge was successful, updating the pull request comments.")
743 743 self._comment_and_close_pr(pull_request, user, merge_state)
744 744
745 745 self._log_audit_action(
746 746 'repo.pull_request.merge',
747 747 {'merge_state': merge_state.__dict__},
748 748 user, pull_request)
749 749
750 750 else:
751 751 log.warn("Merge failed, not updating the pull request.")
752 752 return merge_state
753 753
754 754 def _merge_pull_request(self, pull_request, user, extras, merge_msg=None):
755 755 target_vcs = pull_request.target_repo.scm_instance()
756 756 source_vcs = pull_request.source_repo.scm_instance()
757 757
758 758 message = safe_unicode(merge_msg or vcs_settings.MERGE_MESSAGE_TMPL).format(
759 759 pr_id=pull_request.pull_request_id,
760 760 pr_title=pull_request.title,
761 761 source_repo=source_vcs.name,
762 762 source_ref_name=pull_request.source_ref_parts.name,
763 763 target_repo=target_vcs.name,
764 764 target_ref_name=pull_request.target_ref_parts.name,
765 765 )
766 766
767 767 workspace_id = self._workspace_id(pull_request)
768 768 repo_id = pull_request.target_repo.repo_id
769 769 use_rebase = self._use_rebase_for_merging(pull_request)
770 770 close_branch = self._close_branch_before_merging(pull_request)
771 771 user_name = self._user_name_for_merging(pull_request, user)
772 772
773 773 target_ref = self._refresh_reference(
774 774 pull_request.target_ref_parts, target_vcs)
775 775
776 776 callback_daemon, extras = prepare_callback_daemon(
777 777 extras, protocol=vcs_settings.HOOKS_PROTOCOL,
778 778 host=vcs_settings.HOOKS_HOST,
779 779 use_direct_calls=vcs_settings.HOOKS_DIRECT_CALLS)
780 780
781 781 with callback_daemon:
782 782 # TODO: johbo: Implement a clean way to run a config_override
783 783 # for a single call.
784 784 target_vcs.config.set(
785 785 'rhodecode', 'RC_SCM_DATA', json.dumps(extras))
786 786
787 787 merge_state = target_vcs.merge(
788 788 repo_id, workspace_id, target_ref, source_vcs,
789 789 pull_request.source_ref_parts,
790 790 user_name=user_name, user_email=user.email,
791 791 message=message, use_rebase=use_rebase,
792 792 close_branch=close_branch)
793 793 return merge_state
794 794
795 795 def _comment_and_close_pr(self, pull_request, user, merge_state, close_msg=None):
796 796 pull_request.merge_rev = merge_state.merge_ref.commit_id
797 797 pull_request.updated_on = datetime.datetime.now()
798 798 close_msg = close_msg or 'Pull request merged and closed'
799 799
800 800 CommentsModel().create(
801 801 text=safe_unicode(close_msg),
802 802 repo=pull_request.target_repo.repo_id,
803 803 user=user.user_id,
804 804 pull_request=pull_request.pull_request_id,
805 805 f_path=None,
806 806 line_no=None,
807 807 closing_pr=True
808 808 )
809 809
810 810 Session().add(pull_request)
811 811 Session().flush()
812 812 # TODO: paris: replace invalidation with less radical solution
813 813 ScmModel().mark_for_invalidation(
814 814 pull_request.target_repo.repo_name)
815 815 self.trigger_pull_request_hook(pull_request, user, 'merge')
816 816
817 817 def has_valid_update_type(self, pull_request):
818 818 source_ref_type = pull_request.source_ref_parts.type
819 819 return source_ref_type in self.REF_TYPES
820 820
821 821 def get_flow_commits(self, pull_request):
822 822
823 823 # source repo
824 824 source_ref_name = pull_request.source_ref_parts.name
825 825 source_ref_type = pull_request.source_ref_parts.type
826 826 source_ref_id = pull_request.source_ref_parts.commit_id
827 827 source_repo = pull_request.source_repo.scm_instance()
828 828
829 829 try:
830 830 if source_ref_type in self.REF_TYPES:
831 831 source_commit = source_repo.get_commit(source_ref_name)
832 832 else:
833 833 source_commit = source_repo.get_commit(source_ref_id)
834 834 except CommitDoesNotExistError:
835 835 raise SourceRefMissing()
836 836
837 837 # target repo
838 838 target_ref_name = pull_request.target_ref_parts.name
839 839 target_ref_type = pull_request.target_ref_parts.type
840 840 target_ref_id = pull_request.target_ref_parts.commit_id
841 841 target_repo = pull_request.target_repo.scm_instance()
842 842
843 843 try:
844 844 if target_ref_type in self.REF_TYPES:
845 845 target_commit = target_repo.get_commit(target_ref_name)
846 846 else:
847 847 target_commit = target_repo.get_commit(target_ref_id)
848 848 except CommitDoesNotExistError:
849 849 raise TargetRefMissing()
850 850
851 851 return source_commit, target_commit
852 852
853 853 def update_commits(self, pull_request, updating_user):
854 854 """
855 855 Get the updated list of commits for the pull request
856 856 and return the new pull request version and the list
857 857 of commits processed by this update action
858 858
859 859 updating_user is the user_object who triggered the update
860 860 """
861 861 pull_request = self.__get_pull_request(pull_request)
862 862 source_ref_type = pull_request.source_ref_parts.type
863 863 source_ref_name = pull_request.source_ref_parts.name
864 864 source_ref_id = pull_request.source_ref_parts.commit_id
865 865
866 866 target_ref_type = pull_request.target_ref_parts.type
867 867 target_ref_name = pull_request.target_ref_parts.name
868 868 target_ref_id = pull_request.target_ref_parts.commit_id
869 869
870 870 if not self.has_valid_update_type(pull_request):
871 871 log.debug("Skipping update of pull request %s due to ref type: %s",
872 872 pull_request, source_ref_type)
873 873 return UpdateResponse(
874 874 executed=False,
875 875 reason=UpdateFailureReason.WRONG_REF_TYPE,
876 876 old=pull_request, new=None, common_ancestor_id=None, commit_changes=None,
877 877 source_changed=False, target_changed=False)
878 878
879 879 try:
880 880 source_commit, target_commit = self.get_flow_commits(pull_request)
881 881 except SourceRefMissing:
882 882 return UpdateResponse(
883 883 executed=False,
884 884 reason=UpdateFailureReason.MISSING_SOURCE_REF,
885 885 old=pull_request, new=None, common_ancestor_id=None, commit_changes=None,
886 886 source_changed=False, target_changed=False)
887 887 except TargetRefMissing:
888 888 return UpdateResponse(
889 889 executed=False,
890 890 reason=UpdateFailureReason.MISSING_TARGET_REF,
891 891 old=pull_request, new=None, common_ancestor_id=None, commit_changes=None,
892 892 source_changed=False, target_changed=False)
893 893
894 894 source_changed = source_ref_id != source_commit.raw_id
895 895 target_changed = target_ref_id != target_commit.raw_id
896 896
897 897 if not (source_changed or target_changed):
898 898 log.debug("Nothing changed in pull request %s", pull_request)
899 899 return UpdateResponse(
900 900 executed=False,
901 901 reason=UpdateFailureReason.NO_CHANGE,
902 902 old=pull_request, new=None, common_ancestor_id=None, commit_changes=None,
903 903 source_changed=target_changed, target_changed=source_changed)
904 904
905 905 change_in_found = 'target repo' if target_changed else 'source repo'
906 906 log.debug('Updating pull request because of change in %s detected',
907 907 change_in_found)
908 908
909 909 # Finally there is a need for an update, in case of source change
910 910 # we create a new version, else just an update
911 911 if source_changed:
912 912 pull_request_version = self._create_version_from_snapshot(pull_request)
913 913 self._link_comments_to_version(pull_request_version)
914 914 else:
915 915 try:
916 916 ver = pull_request.versions[-1]
917 917 except IndexError:
918 918 ver = None
919 919
920 920 pull_request.pull_request_version_id = \
921 921 ver.pull_request_version_id if ver else None
922 922 pull_request_version = pull_request
923 923
924 924 source_repo = pull_request.source_repo.scm_instance()
925 925 target_repo = pull_request.target_repo.scm_instance()
926 926
927 927 # re-compute commit ids
928 928 old_commit_ids = pull_request.revisions
929 929 pre_load = ["author", "date", "message", "branch"]
930 930 commit_ranges = target_repo.compare(
931 931 target_commit.raw_id, source_commit.raw_id, source_repo, merge=True,
932 932 pre_load=pre_load)
933 933
934 934 target_ref = target_commit.raw_id
935 935 source_ref = source_commit.raw_id
936 936 ancestor_commit_id = target_repo.get_common_ancestor(
937 937 target_ref, source_ref, source_repo)
938 938
939 939 if not ancestor_commit_id:
940 940 raise ValueError(
941 941 'cannot calculate diff info without a common ancestor. '
942 942 'Make sure both repositories are related, and have a common forking commit.')
943 943
944 944 pull_request.common_ancestor_id = ancestor_commit_id
945 945
946 946 pull_request.source_ref = '%s:%s:%s' % (
947 947 source_ref_type, source_ref_name, source_commit.raw_id)
948 948 pull_request.target_ref = '%s:%s:%s' % (
949 949 target_ref_type, target_ref_name, ancestor_commit_id)
950 950
951 951 pull_request.revisions = [
952 952 commit.raw_id for commit in reversed(commit_ranges)]
953 953 pull_request.updated_on = datetime.datetime.now()
954 954 Session().add(pull_request)
955 955 new_commit_ids = pull_request.revisions
956 956
957 957 old_diff_data, new_diff_data = self._generate_update_diffs(
958 958 pull_request, pull_request_version)
959 959
960 960 # calculate commit and file changes
961 961 commit_changes = self._calculate_commit_id_changes(
962 962 old_commit_ids, new_commit_ids)
963 963 file_changes = self._calculate_file_changes(
964 964 old_diff_data, new_diff_data)
965 965
966 966 # set comments as outdated if DIFFS changed
967 967 CommentsModel().outdate_comments(
968 968 pull_request, old_diff_data=old_diff_data,
969 969 new_diff_data=new_diff_data)
970 970
971 971 valid_commit_changes = (commit_changes.added or commit_changes.removed)
972 972 file_node_changes = (
973 973 file_changes.added or file_changes.modified or file_changes.removed)
974 974 pr_has_changes = valid_commit_changes or file_node_changes
975 975
976 976 # Add an automatic comment to the pull request, in case
977 977 # anything has changed
978 978 if pr_has_changes:
979 979 update_comment = CommentsModel().create(
980 980 text=self._render_update_message(ancestor_commit_id, commit_changes, file_changes),
981 981 repo=pull_request.target_repo,
982 982 user=pull_request.author,
983 983 pull_request=pull_request,
984 984 send_email=False, renderer=DEFAULT_COMMENTS_RENDERER)
985 985
986 986 # Update status to "Under Review" for added commits
987 987 for commit_id in commit_changes.added:
988 988 ChangesetStatusModel().set_status(
989 989 repo=pull_request.source_repo,
990 990 status=ChangesetStatus.STATUS_UNDER_REVIEW,
991 991 comment=update_comment,
992 992 user=pull_request.author,
993 993 pull_request=pull_request,
994 994 revision=commit_id)
995 995
996 996 # send update email to users
997 997 try:
998 998 self.notify_users(pull_request=pull_request, updating_user=updating_user,
999 999 ancestor_commit_id=ancestor_commit_id,
1000 1000 commit_changes=commit_changes,
1001 1001 file_changes=file_changes)
1002 1002 except Exception:
1003 1003 log.exception('Failed to send email notification to users')
1004 1004
1005 1005 log.debug(
1006 1006 'Updated pull request %s, added_ids: %s, common_ids: %s, '
1007 1007 'removed_ids: %s', pull_request.pull_request_id,
1008 1008 commit_changes.added, commit_changes.common, commit_changes.removed)
1009 1009 log.debug(
1010 1010 'Updated pull request with the following file changes: %s',
1011 1011 file_changes)
1012 1012
1013 1013 log.info(
1014 1014 "Updated pull request %s from commit %s to commit %s, "
1015 1015 "stored new version %s of this pull request.",
1016 1016 pull_request.pull_request_id, source_ref_id,
1017 1017 pull_request.source_ref_parts.commit_id,
1018 1018 pull_request_version.pull_request_version_id)
1019 1019 Session().commit()
1020 1020 self.trigger_pull_request_hook(pull_request, pull_request.author, 'update')
1021 1021
1022 1022 return UpdateResponse(
1023 1023 executed=True, reason=UpdateFailureReason.NONE,
1024 1024 old=pull_request, new=pull_request_version,
1025 1025 common_ancestor_id=ancestor_commit_id, commit_changes=commit_changes,
1026 1026 source_changed=source_changed, target_changed=target_changed)
1027 1027
1028 1028 def _create_version_from_snapshot(self, pull_request):
1029 1029 version = PullRequestVersion()
1030 1030 version.title = pull_request.title
1031 1031 version.description = pull_request.description
1032 1032 version.status = pull_request.status
1033 1033 version.pull_request_state = pull_request.pull_request_state
1034 1034 version.created_on = datetime.datetime.now()
1035 1035 version.updated_on = pull_request.updated_on
1036 1036 version.user_id = pull_request.user_id
1037 1037 version.source_repo = pull_request.source_repo
1038 1038 version.source_ref = pull_request.source_ref
1039 1039 version.target_repo = pull_request.target_repo
1040 1040 version.target_ref = pull_request.target_ref
1041 1041
1042 1042 version._last_merge_source_rev = pull_request._last_merge_source_rev
1043 1043 version._last_merge_target_rev = pull_request._last_merge_target_rev
1044 1044 version.last_merge_status = pull_request.last_merge_status
1045 1045 version.last_merge_metadata = pull_request.last_merge_metadata
1046 1046 version.shadow_merge_ref = pull_request.shadow_merge_ref
1047 1047 version.merge_rev = pull_request.merge_rev
1048 1048 version.reviewer_data = pull_request.reviewer_data
1049 1049
1050 1050 version.revisions = pull_request.revisions
1051 1051 version.common_ancestor_id = pull_request.common_ancestor_id
1052 1052 version.pull_request = pull_request
1053 1053 Session().add(version)
1054 1054 Session().flush()
1055 1055
1056 1056 return version
1057 1057
1058 1058 def _generate_update_diffs(self, pull_request, pull_request_version):
1059 1059
1060 1060 diff_context = (
1061 1061 self.DIFF_CONTEXT +
1062 1062 CommentsModel.needed_extra_diff_context())
1063 1063 hide_whitespace_changes = False
1064 1064 source_repo = pull_request_version.source_repo
1065 1065 source_ref_id = pull_request_version.source_ref_parts.commit_id
1066 1066 target_ref_id = pull_request_version.target_ref_parts.commit_id
1067 1067 old_diff = self._get_diff_from_pr_or_version(
1068 1068 source_repo, source_ref_id, target_ref_id,
1069 1069 hide_whitespace_changes=hide_whitespace_changes, diff_context=diff_context)
1070 1070
1071 1071 source_repo = pull_request.source_repo
1072 1072 source_ref_id = pull_request.source_ref_parts.commit_id
1073 1073 target_ref_id = pull_request.target_ref_parts.commit_id
1074 1074
1075 1075 new_diff = self._get_diff_from_pr_or_version(
1076 1076 source_repo, source_ref_id, target_ref_id,
1077 1077 hide_whitespace_changes=hide_whitespace_changes, diff_context=diff_context)
1078 1078
1079 1079 old_diff_data = diffs.DiffProcessor(old_diff)
1080 1080 old_diff_data.prepare()
1081 1081 new_diff_data = diffs.DiffProcessor(new_diff)
1082 1082 new_diff_data.prepare()
1083 1083
1084 1084 return old_diff_data, new_diff_data
1085 1085
1086 1086 def _link_comments_to_version(self, pull_request_version):
1087 1087 """
1088 1088 Link all unlinked comments of this pull request to the given version.
1089 1089
1090 1090 :param pull_request_version: The `PullRequestVersion` to which
1091 1091 the comments shall be linked.
1092 1092
1093 1093 """
1094 1094 pull_request = pull_request_version.pull_request
1095 1095 comments = ChangesetComment.query()\
1096 1096 .filter(
1097 1097 # TODO: johbo: Should we query for the repo at all here?
1098 1098 # Pending decision on how comments of PRs are to be related
1099 1099 # to either the source repo, the target repo or no repo at all.
1100 1100 ChangesetComment.repo_id == pull_request.target_repo.repo_id,
1101 1101 ChangesetComment.pull_request == pull_request,
1102 1102 ChangesetComment.pull_request_version == None)\
1103 1103 .order_by(ChangesetComment.comment_id.asc())
1104 1104
1105 1105 # TODO: johbo: Find out why this breaks if it is done in a bulk
1106 1106 # operation.
1107 1107 for comment in comments:
1108 1108 comment.pull_request_version_id = (
1109 1109 pull_request_version.pull_request_version_id)
1110 1110 Session().add(comment)
1111 1111
1112 1112 def _calculate_commit_id_changes(self, old_ids, new_ids):
1113 1113 added = [x for x in new_ids if x not in old_ids]
1114 1114 common = [x for x in new_ids if x in old_ids]
1115 1115 removed = [x for x in old_ids if x not in new_ids]
1116 1116 total = new_ids
1117 1117 return ChangeTuple(added, common, removed, total)
1118 1118
1119 1119 def _calculate_file_changes(self, old_diff_data, new_diff_data):
1120 1120
1121 1121 old_files = OrderedDict()
1122 1122 for diff_data in old_diff_data.parsed_diff:
1123 1123 old_files[diff_data['filename']] = md5_safe(diff_data['raw_diff'])
1124 1124
1125 1125 added_files = []
1126 1126 modified_files = []
1127 1127 removed_files = []
1128 1128 for diff_data in new_diff_data.parsed_diff:
1129 1129 new_filename = diff_data['filename']
1130 1130 new_hash = md5_safe(diff_data['raw_diff'])
1131 1131
1132 1132 old_hash = old_files.get(new_filename)
1133 1133 if not old_hash:
1134 1134 # file is not present in old diff, we have to figure out from parsed diff
1135 1135 # operation ADD/REMOVE
1136 1136 operations_dict = diff_data['stats']['ops']
1137 1137 if diffs.DEL_FILENODE in operations_dict:
1138 1138 removed_files.append(new_filename)
1139 1139 else:
1140 1140 added_files.append(new_filename)
1141 1141 else:
1142 1142 if new_hash != old_hash:
1143 1143 modified_files.append(new_filename)
1144 1144 # now remove a file from old, since we have seen it already
1145 1145 del old_files[new_filename]
1146 1146
1147 1147 # removed files is when there are present in old, but not in NEW,
1148 1148 # since we remove old files that are present in new diff, left-overs
1149 1149 # if any should be the removed files
1150 1150 removed_files.extend(old_files.keys())
1151 1151
1152 1152 return FileChangeTuple(added_files, modified_files, removed_files)
1153 1153
1154 1154 def _render_update_message(self, ancestor_commit_id, changes, file_changes):
1155 1155 """
1156 1156 render the message using DEFAULT_COMMENTS_RENDERER (RST renderer),
1157 1157 so it's always looking the same disregarding on which default
1158 1158 renderer system is using.
1159 1159
1160 1160 :param ancestor_commit_id: ancestor raw_id
1161 1161 :param changes: changes named tuple
1162 1162 :param file_changes: file changes named tuple
1163 1163
1164 1164 """
1165 1165 new_status = ChangesetStatus.get_status_lbl(
1166 1166 ChangesetStatus.STATUS_UNDER_REVIEW)
1167 1167
1168 1168 changed_files = (
1169 1169 file_changes.added + file_changes.modified + file_changes.removed)
1170 1170
1171 1171 params = {
1172 1172 'under_review_label': new_status,
1173 1173 'added_commits': changes.added,
1174 1174 'removed_commits': changes.removed,
1175 1175 'changed_files': changed_files,
1176 1176 'added_files': file_changes.added,
1177 1177 'modified_files': file_changes.modified,
1178 1178 'removed_files': file_changes.removed,
1179 1179 'ancestor_commit_id': ancestor_commit_id
1180 1180 }
1181 1181 renderer = RstTemplateRenderer()
1182 1182 return renderer.render('pull_request_update.mako', **params)
1183 1183
1184 1184 def edit(self, pull_request, title, description, description_renderer, user):
1185 1185 pull_request = self.__get_pull_request(pull_request)
1186 1186 old_data = pull_request.get_api_data(with_merge_state=False)
1187 1187 if pull_request.is_closed():
1188 1188 raise ValueError('This pull request is closed')
1189 1189 if title:
1190 1190 pull_request.title = title
1191 1191 pull_request.description = description
1192 1192 pull_request.updated_on = datetime.datetime.now()
1193 1193 pull_request.description_renderer = description_renderer
1194 1194 Session().add(pull_request)
1195 1195 self._log_audit_action(
1196 1196 'repo.pull_request.edit', {'old_data': old_data},
1197 1197 user, pull_request)
1198 1198
1199 1199 def update_reviewers(self, pull_request, reviewer_data, user):
1200 1200 """
1201 1201 Update the reviewers in the pull request
1202 1202
1203 1203 :param pull_request: the pr to update
1204 1204 :param reviewer_data: list of tuples
1205 1205 [(user, ['reason1', 'reason2'], mandatory_flag, [rules])]
1206 1206 """
1207 1207 pull_request = self.__get_pull_request(pull_request)
1208 1208 if pull_request.is_closed():
1209 1209 raise ValueError('This pull request is closed')
1210 1210
1211 1211 reviewers = {}
1212 1212 for user_id, reasons, mandatory, rules in reviewer_data:
1213 1213 if isinstance(user_id, (int, compat.string_types)):
1214 1214 user_id = self._get_user(user_id).user_id
1215 1215 reviewers[user_id] = {
1216 1216 'reasons': reasons, 'mandatory': mandatory}
1217 1217
1218 1218 reviewers_ids = set(reviewers.keys())
1219 1219 current_reviewers = PullRequestReviewers.query()\
1220 1220 .filter(PullRequestReviewers.pull_request ==
1221 1221 pull_request).all()
1222 1222 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
1223 1223
1224 1224 ids_to_add = reviewers_ids.difference(current_reviewers_ids)
1225 1225 ids_to_remove = current_reviewers_ids.difference(reviewers_ids)
1226 1226
1227 1227 log.debug("Adding %s reviewers", ids_to_add)
1228 1228 log.debug("Removing %s reviewers", ids_to_remove)
1229 1229 changed = False
1230 1230 added_audit_reviewers = []
1231 1231 removed_audit_reviewers = []
1232 1232
1233 1233 for uid in ids_to_add:
1234 1234 changed = True
1235 1235 _usr = self._get_user(uid)
1236 1236 reviewer = PullRequestReviewers()
1237 1237 reviewer.user = _usr
1238 1238 reviewer.pull_request = pull_request
1239 1239 reviewer.reasons = reviewers[uid]['reasons']
1240 1240 # NOTE(marcink): mandatory shouldn't be changed now
1241 1241 # reviewer.mandatory = reviewers[uid]['reasons']
1242 1242 Session().add(reviewer)
1243 1243 added_audit_reviewers.append(reviewer.get_dict())
1244 1244
1245 1245 for uid in ids_to_remove:
1246 1246 changed = True
1247 1247 # NOTE(marcink): we fetch "ALL" reviewers using .all(). This is an edge case
1248 1248 # that prevents and fixes cases that we added the same reviewer twice.
1249 1249 # this CAN happen due to the lack of DB checks
1250 1250 reviewers = PullRequestReviewers.query()\
1251 1251 .filter(PullRequestReviewers.user_id == uid,
1252 1252 PullRequestReviewers.pull_request == pull_request)\
1253 1253 .all()
1254 1254
1255 1255 for obj in reviewers:
1256 1256 added_audit_reviewers.append(obj.get_dict())
1257 1257 Session().delete(obj)
1258 1258
1259 1259 if changed:
1260 1260 Session().expire_all()
1261 1261 pull_request.updated_on = datetime.datetime.now()
1262 1262 Session().add(pull_request)
1263 1263
1264 1264 # finally store audit logs
1265 1265 for user_data in added_audit_reviewers:
1266 1266 self._log_audit_action(
1267 1267 'repo.pull_request.reviewer.add', {'data': user_data},
1268 1268 user, pull_request)
1269 1269 for user_data in removed_audit_reviewers:
1270 1270 self._log_audit_action(
1271 1271 'repo.pull_request.reviewer.delete', {'old_data': user_data},
1272 1272 user, pull_request)
1273 1273
1274 1274 self.notify_reviewers(pull_request, ids_to_add)
1275 1275 return ids_to_add, ids_to_remove
1276 1276
1277 1277 def get_url(self, pull_request, request=None, permalink=False):
1278 1278 if not request:
1279 1279 request = get_current_request()
1280 1280
1281 1281 if permalink:
1282 1282 return request.route_url(
1283 1283 'pull_requests_global',
1284 1284 pull_request_id=pull_request.pull_request_id,)
1285 1285 else:
1286 1286 return request.route_url('pullrequest_show',
1287 1287 repo_name=safe_str(pull_request.target_repo.repo_name),
1288 1288 pull_request_id=pull_request.pull_request_id,)
1289 1289
1290 1290 def get_shadow_clone_url(self, pull_request, request=None):
1291 1291 """
1292 1292 Returns qualified url pointing to the shadow repository. If this pull
1293 1293 request is closed there is no shadow repository and ``None`` will be
1294 1294 returned.
1295 1295 """
1296 1296 if pull_request.is_closed():
1297 1297 return None
1298 1298 else:
1299 1299 pr_url = urllib.unquote(self.get_url(pull_request, request=request))
1300 1300 return safe_unicode('{pr_url}/repository'.format(pr_url=pr_url))
1301 1301
1302 1302 def notify_reviewers(self, pull_request, reviewers_ids):
1303 1303 # notification to reviewers
1304 1304 if not reviewers_ids:
1305 1305 return
1306 1306
1307 1307 log.debug('Notify following reviewers about pull-request %s', reviewers_ids)
1308 1308
1309 1309 pull_request_obj = pull_request
1310 1310 # get the current participants of this pull request
1311 1311 recipients = reviewers_ids
1312 1312 notification_type = EmailNotificationModel.TYPE_PULL_REQUEST
1313 1313
1314 1314 pr_source_repo = pull_request_obj.source_repo
1315 1315 pr_target_repo = pull_request_obj.target_repo
1316 1316
1317 1317 pr_url = h.route_url('pullrequest_show',
1318 1318 repo_name=pr_target_repo.repo_name,
1319 1319 pull_request_id=pull_request_obj.pull_request_id,)
1320 1320
1321 1321 # set some variables for email notification
1322 1322 pr_target_repo_url = h.route_url(
1323 1323 'repo_summary', repo_name=pr_target_repo.repo_name)
1324 1324
1325 1325 pr_source_repo_url = h.route_url(
1326 1326 'repo_summary', repo_name=pr_source_repo.repo_name)
1327 1327
1328 1328 # pull request specifics
1329 1329 pull_request_commits = [
1330 1330 (x.raw_id, x.message)
1331 1331 for x in map(pr_source_repo.get_commit, pull_request.revisions)]
1332 1332
1333 1333 kwargs = {
1334 1334 'user': pull_request.author,
1335 1335 'pull_request': pull_request_obj,
1336 1336 'pull_request_commits': pull_request_commits,
1337 1337
1338 1338 'pull_request_target_repo': pr_target_repo,
1339 1339 'pull_request_target_repo_url': pr_target_repo_url,
1340 1340
1341 1341 'pull_request_source_repo': pr_source_repo,
1342 1342 'pull_request_source_repo_url': pr_source_repo_url,
1343 1343
1344 1344 'pull_request_url': pr_url,
1345 1345 }
1346 1346
1347 1347 # pre-generate the subject for notification itself
1348 1348 (subject,
1349 1349 _h, _e, # we don't care about those
1350 1350 body_plaintext) = EmailNotificationModel().render_email(
1351 1351 notification_type, **kwargs)
1352 1352
1353 1353 # create notification objects, and emails
1354 1354 NotificationModel().create(
1355 1355 created_by=pull_request.author,
1356 1356 notification_subject=subject,
1357 1357 notification_body=body_plaintext,
1358 1358 notification_type=notification_type,
1359 1359 recipients=recipients,
1360 1360 email_kwargs=kwargs,
1361 1361 )
1362 1362
1363 1363 def notify_users(self, pull_request, updating_user, ancestor_commit_id,
1364 1364 commit_changes, file_changes):
1365 1365
1366 1366 updating_user_id = updating_user.user_id
1367 1367 reviewers = set([x.user.user_id for x in pull_request.reviewers])
1368 1368 # NOTE(marcink): send notification to all other users except to
1369 1369 # person who updated the PR
1370 1370 recipients = reviewers.difference(set([updating_user_id]))
1371 1371
1372 1372 log.debug('Notify following recipients about pull-request update %s', recipients)
1373 1373
1374 1374 pull_request_obj = pull_request
1375 1375
1376 1376 # send email about the update
1377 1377 changed_files = (
1378 1378 file_changes.added + file_changes.modified + file_changes.removed)
1379 1379
1380 1380 pr_source_repo = pull_request_obj.source_repo
1381 1381 pr_target_repo = pull_request_obj.target_repo
1382 1382
1383 1383 pr_url = h.route_url('pullrequest_show',
1384 1384 repo_name=pr_target_repo.repo_name,
1385 1385 pull_request_id=pull_request_obj.pull_request_id,)
1386 1386
1387 1387 # set some variables for email notification
1388 1388 pr_target_repo_url = h.route_url(
1389 1389 'repo_summary', repo_name=pr_target_repo.repo_name)
1390 1390
1391 1391 pr_source_repo_url = h.route_url(
1392 1392 'repo_summary', repo_name=pr_source_repo.repo_name)
1393 1393
1394 1394 email_kwargs = {
1395 1395 'date': datetime.datetime.now(),
1396 1396 'updating_user': updating_user,
1397 1397
1398 1398 'pull_request': pull_request_obj,
1399 1399
1400 1400 'pull_request_target_repo': pr_target_repo,
1401 1401 'pull_request_target_repo_url': pr_target_repo_url,
1402 1402
1403 1403 'pull_request_source_repo': pr_source_repo,
1404 1404 'pull_request_source_repo_url': pr_source_repo_url,
1405 1405
1406 1406 'pull_request_url': pr_url,
1407 1407
1408 1408 'ancestor_commit_id': ancestor_commit_id,
1409 1409 'added_commits': commit_changes.added,
1410 1410 'removed_commits': commit_changes.removed,
1411 1411 'changed_files': changed_files,
1412 1412 'added_files': file_changes.added,
1413 1413 'modified_files': file_changes.modified,
1414 1414 'removed_files': file_changes.removed,
1415 1415 }
1416 1416
1417 1417 (subject,
1418 1418 _h, _e, # we don't care about those
1419 1419 body_plaintext) = EmailNotificationModel().render_email(
1420 1420 EmailNotificationModel.TYPE_PULL_REQUEST_UPDATE, **email_kwargs)
1421 1421
1422 1422 # create notification objects, and emails
1423 1423 NotificationModel().create(
1424 1424 created_by=updating_user,
1425 1425 notification_subject=subject,
1426 1426 notification_body=body_plaintext,
1427 1427 notification_type=EmailNotificationModel.TYPE_PULL_REQUEST_UPDATE,
1428 1428 recipients=recipients,
1429 1429 email_kwargs=email_kwargs,
1430 1430 )
1431 1431
1432 1432 def delete(self, pull_request, user=None):
1433 1433 if not user:
1434 1434 user = getattr(get_current_rhodecode_user(), 'username', None)
1435 1435
1436 1436 pull_request = self.__get_pull_request(pull_request)
1437 1437 old_data = pull_request.get_api_data(with_merge_state=False)
1438 1438 self._cleanup_merge_workspace(pull_request)
1439 1439 self._log_audit_action(
1440 1440 'repo.pull_request.delete', {'old_data': old_data},
1441 1441 user, pull_request)
1442 1442 Session().delete(pull_request)
1443 1443
1444 1444 def close_pull_request(self, pull_request, user):
1445 1445 pull_request = self.__get_pull_request(pull_request)
1446 1446 self._cleanup_merge_workspace(pull_request)
1447 1447 pull_request.status = PullRequest.STATUS_CLOSED
1448 1448 pull_request.updated_on = datetime.datetime.now()
1449 1449 Session().add(pull_request)
1450 1450 self.trigger_pull_request_hook(pull_request, pull_request.author, 'close')
1451 1451
1452 1452 pr_data = pull_request.get_api_data(with_merge_state=False)
1453 1453 self._log_audit_action(
1454 1454 'repo.pull_request.close', {'data': pr_data}, user, pull_request)
1455 1455
1456 1456 def close_pull_request_with_comment(
1457 1457 self, pull_request, user, repo, message=None, auth_user=None):
1458 1458
1459 1459 pull_request_review_status = pull_request.calculated_review_status()
1460 1460
1461 1461 if pull_request_review_status == ChangesetStatus.STATUS_APPROVED:
1462 1462 # approved only if we have voting consent
1463 1463 status = ChangesetStatus.STATUS_APPROVED
1464 1464 else:
1465 1465 status = ChangesetStatus.STATUS_REJECTED
1466 1466 status_lbl = ChangesetStatus.get_status_lbl(status)
1467 1467
1468 1468 default_message = (
1469 1469 'Closing with status change {transition_icon} {status}.'
1470 1470 ).format(transition_icon='>', status=status_lbl)
1471 1471 text = message or default_message
1472 1472
1473 1473 # create a comment, and link it to new status
1474 1474 comment = CommentsModel().create(
1475 1475 text=text,
1476 1476 repo=repo.repo_id,
1477 1477 user=user.user_id,
1478 1478 pull_request=pull_request.pull_request_id,
1479 1479 status_change=status_lbl,
1480 1480 status_change_type=status,
1481 1481 closing_pr=True,
1482 1482 auth_user=auth_user,
1483 1483 )
1484 1484
1485 1485 # calculate old status before we change it
1486 1486 old_calculated_status = pull_request.calculated_review_status()
1487 1487 ChangesetStatusModel().set_status(
1488 1488 repo.repo_id,
1489 1489 status,
1490 1490 user.user_id,
1491 1491 comment=comment,
1492 1492 pull_request=pull_request.pull_request_id
1493 1493 )
1494 1494
1495 1495 Session().flush()
1496 1496
1497 1497 self.trigger_pull_request_hook(pull_request, user, 'comment',
1498 1498 data={'comment': comment})
1499 1499
1500 1500 # we now calculate the status of pull request again, and based on that
1501 1501 # calculation trigger status change. This might happen in cases
1502 1502 # that non-reviewer admin closes a pr, which means his vote doesn't
1503 1503 # change the status, while if he's a reviewer this might change it.
1504 1504 calculated_status = pull_request.calculated_review_status()
1505 1505 if old_calculated_status != calculated_status:
1506 1506 self.trigger_pull_request_hook(pull_request, user, 'review_status_change',
1507 1507 data={'status': calculated_status})
1508 1508
1509 1509 # finally close the PR
1510 1510 PullRequestModel().close_pull_request(pull_request.pull_request_id, user)
1511 1511
1512 1512 return comment, status
1513 1513
1514 1514 def merge_status(self, pull_request, translator=None, force_shadow_repo_refresh=False):
1515 1515 _ = translator or get_current_request().translate
1516 1516
1517 1517 if not self._is_merge_enabled(pull_request):
1518 1518 return None, False, _('Server-side pull request merging is disabled.')
1519 1519
1520 1520 if pull_request.is_closed():
1521 1521 return None, False, _('This pull request is closed.')
1522 1522
1523 1523 merge_possible, msg = self._check_repo_requirements(
1524 1524 target=pull_request.target_repo, source=pull_request.source_repo,
1525 1525 translator=_)
1526 1526 if not merge_possible:
1527 1527 return None, merge_possible, msg
1528 1528
1529 1529 try:
1530 1530 merge_response = self._try_merge(
1531 1531 pull_request, force_shadow_repo_refresh=force_shadow_repo_refresh)
1532 1532 log.debug("Merge response: %s", merge_response)
1533 1533 return merge_response, merge_response.possible, merge_response.merge_status_message
1534 1534 except NotImplementedError:
1535 1535 return None, False, _('Pull request merging is not supported.')
1536 1536
1537 1537 def _check_repo_requirements(self, target, source, translator):
1538 1538 """
1539 1539 Check if `target` and `source` have compatible requirements.
1540 1540
1541 1541 Currently this is just checking for largefiles.
1542 1542 """
1543 1543 _ = translator
1544 1544 target_has_largefiles = self._has_largefiles(target)
1545 1545 source_has_largefiles = self._has_largefiles(source)
1546 1546 merge_possible = True
1547 1547 message = u''
1548 1548
1549 1549 if target_has_largefiles != source_has_largefiles:
1550 1550 merge_possible = False
1551 1551 if source_has_largefiles:
1552 1552 message = _(
1553 1553 'Target repository large files support is disabled.')
1554 1554 else:
1555 1555 message = _(
1556 1556 'Source repository large files support is disabled.')
1557 1557
1558 1558 return merge_possible, message
1559 1559
1560 1560 def _has_largefiles(self, repo):
1561 1561 largefiles_ui = VcsSettingsModel(repo=repo).get_ui_settings(
1562 1562 'extensions', 'largefiles')
1563 1563 return largefiles_ui and largefiles_ui[0].active
1564 1564
1565 1565 def _try_merge(self, pull_request, force_shadow_repo_refresh=False):
1566 1566 """
1567 1567 Try to merge the pull request and return the merge status.
1568 1568 """
1569 1569 log.debug(
1570 1570 "Trying out if the pull request %s can be merged. Force_refresh=%s",
1571 1571 pull_request.pull_request_id, force_shadow_repo_refresh)
1572 1572 target_vcs = pull_request.target_repo.scm_instance()
1573 1573 # Refresh the target reference.
1574 1574 try:
1575 1575 target_ref = self._refresh_reference(
1576 1576 pull_request.target_ref_parts, target_vcs)
1577 1577 except CommitDoesNotExistError:
1578 1578 merge_state = MergeResponse(
1579 1579 False, False, None, MergeFailureReason.MISSING_TARGET_REF,
1580 1580 metadata={'target_ref': pull_request.target_ref_parts})
1581 1581 return merge_state
1582 1582
1583 1583 target_locked = pull_request.target_repo.locked
1584 1584 if target_locked and target_locked[0]:
1585 1585 locked_by = 'user:{}'.format(target_locked[0])
1586 1586 log.debug("The target repository is locked by %s.", locked_by)
1587 1587 merge_state = MergeResponse(
1588 1588 False, False, None, MergeFailureReason.TARGET_IS_LOCKED,
1589 1589 metadata={'locked_by': locked_by})
1590 1590 elif force_shadow_repo_refresh or self._needs_merge_state_refresh(
1591 1591 pull_request, target_ref):
1592 1592 log.debug("Refreshing the merge status of the repository.")
1593 1593 merge_state = self._refresh_merge_state(
1594 1594 pull_request, target_vcs, target_ref)
1595 1595 else:
1596 1596 possible = pull_request.last_merge_status == MergeFailureReason.NONE
1597 1597 metadata = {
1598 1598 'unresolved_files': '',
1599 1599 'target_ref': pull_request.target_ref_parts,
1600 1600 'source_ref': pull_request.source_ref_parts,
1601 1601 }
1602 1602 if pull_request.last_merge_metadata:
1603 1603 metadata.update(pull_request.last_merge_metadata)
1604 1604
1605 1605 if not possible and target_ref.type == 'branch':
1606 1606 # NOTE(marcink): case for mercurial multiple heads on branch
1607 1607 heads = target_vcs._heads(target_ref.name)
1608 1608 if len(heads) != 1:
1609 1609 heads = '\n,'.join(target_vcs._heads(target_ref.name))
1610 1610 metadata.update({
1611 1611 'heads': heads
1612 1612 })
1613 1613
1614 1614 merge_state = MergeResponse(
1615 1615 possible, False, None, pull_request.last_merge_status, metadata=metadata)
1616 1616
1617 1617 return merge_state
1618 1618
1619 1619 def _refresh_reference(self, reference, vcs_repository):
1620 1620 if reference.type in self.UPDATABLE_REF_TYPES:
1621 1621 name_or_id = reference.name
1622 1622 else:
1623 1623 name_or_id = reference.commit_id
1624 1624
1625 1625 refreshed_commit = vcs_repository.get_commit(name_or_id)
1626 1626 refreshed_reference = Reference(
1627 1627 reference.type, reference.name, refreshed_commit.raw_id)
1628 1628 return refreshed_reference
1629 1629
1630 1630 def _needs_merge_state_refresh(self, pull_request, target_reference):
1631 1631 return not(
1632 1632 pull_request.revisions and
1633 1633 pull_request.revisions[0] == pull_request._last_merge_source_rev and
1634 1634 target_reference.commit_id == pull_request._last_merge_target_rev)
1635 1635
1636 1636 def _refresh_merge_state(self, pull_request, target_vcs, target_reference):
1637 1637 workspace_id = self._workspace_id(pull_request)
1638 1638 source_vcs = pull_request.source_repo.scm_instance()
1639 1639 repo_id = pull_request.target_repo.repo_id
1640 1640 use_rebase = self._use_rebase_for_merging(pull_request)
1641 1641 close_branch = self._close_branch_before_merging(pull_request)
1642 1642 merge_state = target_vcs.merge(
1643 1643 repo_id, workspace_id,
1644 1644 target_reference, source_vcs, pull_request.source_ref_parts,
1645 1645 dry_run=True, use_rebase=use_rebase,
1646 1646 close_branch=close_branch)
1647 1647
1648 1648 # Do not store the response if there was an unknown error.
1649 1649 if merge_state.failure_reason != MergeFailureReason.UNKNOWN:
1650 1650 pull_request._last_merge_source_rev = \
1651 1651 pull_request.source_ref_parts.commit_id
1652 1652 pull_request._last_merge_target_rev = target_reference.commit_id
1653 1653 pull_request.last_merge_status = merge_state.failure_reason
1654 1654 pull_request.last_merge_metadata = merge_state.metadata
1655 1655
1656 1656 pull_request.shadow_merge_ref = merge_state.merge_ref
1657 1657 Session().add(pull_request)
1658 1658 Session().commit()
1659 1659
1660 1660 return merge_state
1661 1661
1662 1662 def _workspace_id(self, pull_request):
1663 1663 workspace_id = 'pr-%s' % pull_request.pull_request_id
1664 1664 return workspace_id
1665 1665
1666 1666 def generate_repo_data(self, repo, commit_id=None, branch=None,
1667 1667 bookmark=None, translator=None):
1668 1668 from rhodecode.model.repo import RepoModel
1669 1669
1670 1670 all_refs, selected_ref = \
1671 1671 self._get_repo_pullrequest_sources(
1672 1672 repo.scm_instance(), commit_id=commit_id,
1673 1673 branch=branch, bookmark=bookmark, translator=translator)
1674 1674
1675 1675 refs_select2 = []
1676 1676 for element in all_refs:
1677 1677 children = [{'id': x[0], 'text': x[1]} for x in element[0]]
1678 1678 refs_select2.append({'text': element[1], 'children': children})
1679 1679
1680 1680 return {
1681 1681 'user': {
1682 1682 'user_id': repo.user.user_id,
1683 1683 'username': repo.user.username,
1684 1684 'firstname': repo.user.first_name,
1685 1685 'lastname': repo.user.last_name,
1686 1686 'gravatar_link': h.gravatar_url(repo.user.email, 14),
1687 1687 },
1688 1688 'name': repo.repo_name,
1689 1689 'link': RepoModel().get_url(repo),
1690 1690 'description': h.chop_at_smart(repo.description_safe, '\n'),
1691 1691 'refs': {
1692 1692 'all_refs': all_refs,
1693 1693 'selected_ref': selected_ref,
1694 1694 'select2_refs': refs_select2
1695 1695 }
1696 1696 }
1697 1697
1698 1698 def generate_pullrequest_title(self, source, source_ref, target):
1699 1699 return u'{source}#{at_ref} to {target}'.format(
1700 1700 source=source,
1701 1701 at_ref=source_ref,
1702 1702 target=target,
1703 1703 )
1704 1704
1705 1705 def _cleanup_merge_workspace(self, pull_request):
1706 1706 # Merging related cleanup
1707 1707 repo_id = pull_request.target_repo.repo_id
1708 1708 target_scm = pull_request.target_repo.scm_instance()
1709 1709 workspace_id = self._workspace_id(pull_request)
1710 1710
1711 1711 try:
1712 1712 target_scm.cleanup_merge_workspace(repo_id, workspace_id)
1713 1713 except NotImplementedError:
1714 1714 pass
1715 1715
1716 1716 def _get_repo_pullrequest_sources(
1717 1717 self, repo, commit_id=None, branch=None, bookmark=None,
1718 1718 translator=None):
1719 1719 """
1720 1720 Return a structure with repo's interesting commits, suitable for
1721 1721 the selectors in pullrequest controller
1722 1722
1723 1723 :param commit_id: a commit that must be in the list somehow
1724 1724 and selected by default
1725 1725 :param branch: a branch that must be in the list and selected
1726 1726 by default - even if closed
1727 1727 :param bookmark: a bookmark that must be in the list and selected
1728 1728 """
1729 1729 _ = translator or get_current_request().translate
1730 1730
1731 1731 commit_id = safe_str(commit_id) if commit_id else None
1732 1732 branch = safe_unicode(branch) if branch else None
1733 1733 bookmark = safe_unicode(bookmark) if bookmark else None
1734 1734
1735 1735 selected = None
1736 1736
1737 1737 # order matters: first source that has commit_id in it will be selected
1738 1738 sources = []
1739 1739 sources.append(('book', repo.bookmarks.items(), _('Bookmarks'), bookmark))
1740 1740 sources.append(('branch', repo.branches.items(), _('Branches'), branch))
1741 1741
1742 1742 if commit_id:
1743 1743 ref_commit = (h.short_id(commit_id), commit_id)
1744 1744 sources.append(('rev', [ref_commit], _('Commit IDs'), commit_id))
1745 1745
1746 1746 sources.append(
1747 1747 ('branch', repo.branches_closed.items(), _('Closed Branches'), branch),
1748 1748 )
1749 1749
1750 1750 groups = []
1751 1751
1752 1752 for group_key, ref_list, group_name, match in sources:
1753 1753 group_refs = []
1754 1754 for ref_name, ref_id in ref_list:
1755 1755 ref_key = u'{}:{}:{}'.format(group_key, ref_name, ref_id)
1756 1756 group_refs.append((ref_key, ref_name))
1757 1757
1758 1758 if not selected:
1759 1759 if set([commit_id, match]) & set([ref_id, ref_name]):
1760 1760 selected = ref_key
1761 1761
1762 1762 if group_refs:
1763 1763 groups.append((group_refs, group_name))
1764 1764
1765 1765 if not selected:
1766 1766 ref = commit_id or branch or bookmark
1767 1767 if ref:
1768 1768 raise CommitDoesNotExistError(
1769 1769 u'No commit refs could be found matching: {}'.format(ref))
1770 1770 elif repo.DEFAULT_BRANCH_NAME in repo.branches:
1771 1771 selected = u'branch:{}:{}'.format(
1772 1772 safe_unicode(repo.DEFAULT_BRANCH_NAME),
1773 1773 safe_unicode(repo.branches[repo.DEFAULT_BRANCH_NAME])
1774 1774 )
1775 1775 elif repo.commit_ids:
1776 1776 # make the user select in this case
1777 1777 selected = None
1778 1778 else:
1779 1779 raise EmptyRepositoryError()
1780 1780 return groups, selected
1781 1781
1782 1782 def get_diff(self, source_repo, source_ref_id, target_ref_id,
1783 1783 hide_whitespace_changes, diff_context):
1784 1784
1785 1785 return self._get_diff_from_pr_or_version(
1786 1786 source_repo, source_ref_id, target_ref_id,
1787 1787 hide_whitespace_changes=hide_whitespace_changes, diff_context=diff_context)
1788 1788
1789 1789 def _get_diff_from_pr_or_version(
1790 1790 self, source_repo, source_ref_id, target_ref_id,
1791 1791 hide_whitespace_changes, diff_context):
1792 1792
1793 1793 target_commit = source_repo.get_commit(
1794 1794 commit_id=safe_str(target_ref_id))
1795 1795 source_commit = source_repo.get_commit(
1796 1796 commit_id=safe_str(source_ref_id), maybe_unreachable=True)
1797 1797 if isinstance(source_repo, Repository):
1798 1798 vcs_repo = source_repo.scm_instance()
1799 1799 else:
1800 1800 vcs_repo = source_repo
1801 1801
1802 1802 # TODO: johbo: In the context of an update, we cannot reach
1803 1803 # the old commit anymore with our normal mechanisms. It needs
1804 1804 # some sort of special support in the vcs layer to avoid this
1805 1805 # workaround.
1806 1806 if (source_commit.raw_id == vcs_repo.EMPTY_COMMIT_ID and
1807 1807 vcs_repo.alias == 'git'):
1808 1808 source_commit.raw_id = safe_str(source_ref_id)
1809 1809
1810 1810 log.debug('calculating diff between '
1811 1811 'source_ref:%s and target_ref:%s for repo `%s`',
1812 1812 target_ref_id, source_ref_id,
1813 1813 safe_unicode(vcs_repo.path))
1814 1814
1815 1815 vcs_diff = vcs_repo.get_diff(
1816 1816 commit1=target_commit, commit2=source_commit,
1817 1817 ignore_whitespace=hide_whitespace_changes, context=diff_context)
1818 1818 return vcs_diff
1819 1819
1820 1820 def _is_merge_enabled(self, pull_request):
1821 1821 return self._get_general_setting(
1822 1822 pull_request, 'rhodecode_pr_merge_enabled')
1823 1823
1824 1824 def _use_rebase_for_merging(self, pull_request):
1825 1825 repo_type = pull_request.target_repo.repo_type
1826 1826 if repo_type == 'hg':
1827 1827 return self._get_general_setting(
1828 1828 pull_request, 'rhodecode_hg_use_rebase_for_merging')
1829 1829 elif repo_type == 'git':
1830 1830 return self._get_general_setting(
1831 1831 pull_request, 'rhodecode_git_use_rebase_for_merging')
1832 1832
1833 1833 return False
1834 1834
1835 1835 def _user_name_for_merging(self, pull_request, user):
1836 1836 env_user_name_attr = os.environ.get('RC_MERGE_USER_NAME_ATTR', '')
1837 1837 if env_user_name_attr and hasattr(user, env_user_name_attr):
1838 1838 user_name_attr = env_user_name_attr
1839 1839 else:
1840 1840 user_name_attr = 'short_contact'
1841 1841
1842 1842 user_name = getattr(user, user_name_attr)
1843 1843 return user_name
1844 1844
1845 1845 def _close_branch_before_merging(self, pull_request):
1846 1846 repo_type = pull_request.target_repo.repo_type
1847 1847 if repo_type == 'hg':
1848 1848 return self._get_general_setting(
1849 1849 pull_request, 'rhodecode_hg_close_branch_before_merging')
1850 1850 elif repo_type == 'git':
1851 1851 return self._get_general_setting(
1852 1852 pull_request, 'rhodecode_git_close_branch_before_merging')
1853 1853
1854 1854 return False
1855 1855
1856 1856 def _get_general_setting(self, pull_request, settings_key, default=False):
1857 1857 settings_model = VcsSettingsModel(repo=pull_request.target_repo)
1858 1858 settings = settings_model.get_general_settings()
1859 1859 return settings.get(settings_key, default)
1860 1860
1861 1861 def _log_audit_action(self, action, action_data, user, pull_request):
1862 1862 audit_logger.store(
1863 1863 action=action,
1864 1864 action_data=action_data,
1865 1865 user=user,
1866 1866 repo=pull_request.target_repo)
1867 1867
1868 1868 def get_reviewer_functions(self):
1869 1869 """
1870 1870 Fetches functions for validation and fetching default reviewers.
1871 1871 If available we use the EE package, else we fallback to CE
1872 1872 package functions
1873 1873 """
1874 1874 try:
1875 1875 from rc_reviewers.utils import get_default_reviewers_data
1876 1876 from rc_reviewers.utils import validate_default_reviewers
1877 1877 except ImportError:
1878 1878 from rhodecode.apps.repository.utils import get_default_reviewers_data
1879 1879 from rhodecode.apps.repository.utils import validate_default_reviewers
1880 1880
1881 1881 return get_default_reviewers_data, validate_default_reviewers
1882 1882
1883 1883
1884 1884 class MergeCheck(object):
1885 1885 """
1886 1886 Perform Merge Checks and returns a check object which stores information
1887 1887 about merge errors, and merge conditions
1888 1888 """
1889 1889 TODO_CHECK = 'todo'
1890 1890 PERM_CHECK = 'perm'
1891 1891 REVIEW_CHECK = 'review'
1892 1892 MERGE_CHECK = 'merge'
1893 1893 WIP_CHECK = 'wip'
1894 1894
1895 1895 def __init__(self):
1896 1896 self.review_status = None
1897 1897 self.merge_possible = None
1898 1898 self.merge_msg = ''
1899 1899 self.merge_response = None
1900 1900 self.failed = None
1901 1901 self.errors = []
1902 1902 self.error_details = OrderedDict()
1903 1903 self.source_commit = AttributeDict()
1904 1904 self.target_commit = AttributeDict()
1905 1905
1906 1906 def __repr__(self):
1907 1907 return '<MergeCheck(possible:{}, failed:{}, errors:{})>'.format(
1908 1908 self.merge_possible, self.failed, self.errors)
1909 1909
1910 1910 def push_error(self, error_type, message, error_key, details):
1911 1911 self.failed = True
1912 1912 self.errors.append([error_type, message])
1913 1913 self.error_details[error_key] = dict(
1914 1914 details=details,
1915 1915 error_type=error_type,
1916 1916 message=message
1917 1917 )
1918 1918
1919 1919 @classmethod
1920 1920 def validate(cls, pull_request, auth_user, translator, fail_early=False,
1921 1921 force_shadow_repo_refresh=False):
1922 1922 _ = translator
1923 1923 merge_check = cls()
1924 1924
1925 1925 # title has WIP:
1926 1926 if pull_request.work_in_progress:
1927 1927 log.debug("MergeCheck: cannot merge, title has wip: marker.")
1928 1928
1929 1929 msg = _('WIP marker in title prevents from accidental merge.')
1930 1930 merge_check.push_error('error', msg, cls.WIP_CHECK, pull_request.title)
1931 1931 if fail_early:
1932 1932 return merge_check
1933 1933
1934 1934 # permissions to merge
1935 1935 user_allowed_to_merge = PullRequestModel().check_user_merge(pull_request, auth_user)
1936 1936 if not user_allowed_to_merge:
1937 1937 log.debug("MergeCheck: cannot merge, approval is pending.")
1938 1938
1939 1939 msg = _('User `{}` not allowed to perform merge.').format(auth_user.username)
1940 1940 merge_check.push_error('error', msg, cls.PERM_CHECK, auth_user.username)
1941 1941 if fail_early:
1942 1942 return merge_check
1943 1943
1944 1944 # permission to merge into the target branch
1945 1945 target_commit_id = pull_request.target_ref_parts.commit_id
1946 1946 if pull_request.target_ref_parts.type == 'branch':
1947 1947 branch_name = pull_request.target_ref_parts.name
1948 1948 else:
1949 1949 # for mercurial we can always figure out the branch from the commit
1950 1950 # in case of bookmark
1951 1951 target_commit = pull_request.target_repo.get_commit(target_commit_id)
1952 1952 branch_name = target_commit.branch
1953 1953
1954 1954 rule, branch_perm = auth_user.get_rule_and_branch_permission(
1955 1955 pull_request.target_repo.repo_name, branch_name)
1956 1956 if branch_perm and branch_perm == 'branch.none':
1957 1957 msg = _('Target branch `{}` changes rejected by rule {}.').format(
1958 1958 branch_name, rule)
1959 1959 merge_check.push_error('error', msg, cls.PERM_CHECK, auth_user.username)
1960 1960 if fail_early:
1961 1961 return merge_check
1962 1962
1963 1963 # review status, must be always present
1964 1964 review_status = pull_request.calculated_review_status()
1965 1965 merge_check.review_status = review_status
1966 1966
1967 1967 status_approved = review_status == ChangesetStatus.STATUS_APPROVED
1968 1968 if not status_approved:
1969 1969 log.debug("MergeCheck: cannot merge, approval is pending.")
1970 1970
1971 1971 msg = _('Pull request reviewer approval is pending.')
1972 1972
1973 1973 merge_check.push_error('warning', msg, cls.REVIEW_CHECK, review_status)
1974 1974
1975 1975 if fail_early:
1976 1976 return merge_check
1977 1977
1978 1978 # left over TODOs
1979 1979 todos = CommentsModel().get_pull_request_unresolved_todos(pull_request)
1980 1980 if todos:
1981 1981 log.debug("MergeCheck: cannot merge, {} "
1982 1982 "unresolved TODOs left.".format(len(todos)))
1983 1983
1984 1984 if len(todos) == 1:
1985 1985 msg = _('Cannot merge, {} TODO still not resolved.').format(
1986 1986 len(todos))
1987 1987 else:
1988 1988 msg = _('Cannot merge, {} TODOs still not resolved.').format(
1989 1989 len(todos))
1990 1990
1991 1991 merge_check.push_error('warning', msg, cls.TODO_CHECK, todos)
1992 1992
1993 1993 if fail_early:
1994 1994 return merge_check
1995 1995
1996 1996 # merge possible, here is the filesystem simulation + shadow repo
1997 1997 merge_response, merge_status, msg = PullRequestModel().merge_status(
1998 1998 pull_request, translator=translator,
1999 1999 force_shadow_repo_refresh=force_shadow_repo_refresh)
2000 2000
2001 2001 merge_check.merge_possible = merge_status
2002 2002 merge_check.merge_msg = msg
2003 2003 merge_check.merge_response = merge_response
2004 2004
2005 2005 source_ref_id = pull_request.source_ref_parts.commit_id
2006 2006 target_ref_id = pull_request.target_ref_parts.commit_id
2007 2007
2008 2008 try:
2009 2009 source_commit, target_commit = PullRequestModel().get_flow_commits(pull_request)
2010 2010 merge_check.source_commit.changed = source_ref_id != source_commit.raw_id
2011 2011 merge_check.source_commit.ref_spec = pull_request.source_ref_parts
2012 2012 merge_check.source_commit.current_raw_id = source_commit.raw_id
2013 2013 merge_check.source_commit.previous_raw_id = source_ref_id
2014 2014
2015 2015 merge_check.target_commit.changed = target_ref_id != target_commit.raw_id
2016 2016 merge_check.target_commit.ref_spec = pull_request.target_ref_parts
2017 2017 merge_check.target_commit.current_raw_id = target_commit.raw_id
2018 2018 merge_check.target_commit.previous_raw_id = target_ref_id
2019 2019 except (SourceRefMissing, TargetRefMissing):
2020 2020 pass
2021 2021
2022 2022 if not merge_status:
2023 2023 log.debug("MergeCheck: cannot merge, pull request merge not possible.")
2024 2024 merge_check.push_error('warning', msg, cls.MERGE_CHECK, None)
2025 2025
2026 2026 if fail_early:
2027 2027 return merge_check
2028 2028
2029 2029 log.debug('MergeCheck: is failed: %s', merge_check.failed)
2030 2030 return merge_check
2031 2031
2032 2032 @classmethod
2033 2033 def get_merge_conditions(cls, pull_request, translator):
2034 2034 _ = translator
2035 2035 merge_details = {}
2036 2036
2037 2037 model = PullRequestModel()
2038 2038 use_rebase = model._use_rebase_for_merging(pull_request)
2039 2039
2040 2040 if use_rebase:
2041 2041 merge_details['merge_strategy'] = dict(
2042 2042 details={},
2043 2043 message=_('Merge strategy: rebase')
2044 2044 )
2045 2045 else:
2046 2046 merge_details['merge_strategy'] = dict(
2047 2047 details={},
2048 2048 message=_('Merge strategy: explicit merge commit')
2049 2049 )
2050 2050
2051 2051 close_branch = model._close_branch_before_merging(pull_request)
2052 2052 if close_branch:
2053 2053 repo_type = pull_request.target_repo.repo_type
2054 2054 close_msg = ''
2055 2055 if repo_type == 'hg':
2056 2056 close_msg = _('Source branch will be closed after merge.')
2057 2057 elif repo_type == 'git':
2058 2058 close_msg = _('Source branch will be deleted after merge.')
2059 2059
2060 2060 merge_details['close_branch'] = dict(
2061 2061 details={},
2062 2062 message=close_msg
2063 2063 )
2064 2064
2065 2065 return merge_details
2066 2066
2067 2067
2068 2068 ChangeTuple = collections.namedtuple(
2069 2069 'ChangeTuple', ['added', 'common', 'removed', 'total'])
2070 2070
2071 2071 FileChangeTuple = collections.namedtuple(
2072 2072 'FileChangeTuple', ['added', 'modified', 'removed'])
@@ -1,1314 +1,1322 b''
1 1 // Default styles
2 2
3 3 .diff-collapse {
4 4 margin: @padding 0;
5 5 text-align: right;
6 6 }
7 7
8 8 .diff-container {
9 9 margin-bottom: @space;
10 10
11 11 .diffblock {
12 12 margin-bottom: @space;
13 13 }
14 14
15 15 &.hidden {
16 16 display: none;
17 17 overflow: hidden;
18 18 }
19 19 }
20 20
21 21
22 22 div.diffblock .sidebyside {
23 23 background: #ffffff;
24 24 }
25 25
26 26 div.diffblock {
27 27 overflow-x: auto;
28 28 overflow-y: hidden;
29 29 clear: both;
30 30 padding: 0px;
31 31 background: @grey6;
32 32 border: @border-thickness solid @grey5;
33 33 -webkit-border-radius: @border-radius @border-radius 0px 0px;
34 34 border-radius: @border-radius @border-radius 0px 0px;
35 35
36 36
37 37 .comments-number {
38 38 float: right;
39 39 }
40 40
41 41 // BEGIN CODE-HEADER STYLES
42 42
43 43 .code-header {
44 44 background: @grey6;
45 45 padding: 10px 0 10px 0;
46 46 height: auto;
47 47 width: 100%;
48 48
49 49 .hash {
50 50 float: left;
51 51 padding: 2px 0 0 2px;
52 52 }
53 53
54 54 .date {
55 55 float: left;
56 56 text-transform: uppercase;
57 57 padding: 4px 0px 0px 2px;
58 58 }
59 59
60 60 div {
61 61 margin-left: 4px;
62 62 }
63 63
64 64 div.compare_header {
65 65 min-height: 40px;
66 66 margin: 0;
67 67 padding: 0 @padding;
68 68
69 69 .drop-menu {
70 70 float:left;
71 71 display: block;
72 72 margin:0 0 @padding 0;
73 73 }
74 74
75 75 .compare-label {
76 76 float: left;
77 77 clear: both;
78 78 display: inline-block;
79 79 min-width: 5em;
80 80 margin: 0;
81 81 padding: @button-padding @button-padding @button-padding 0;
82 82 font-weight: @text-semibold-weight;
83 83 font-family: @text-semibold;
84 84 }
85 85
86 86 .compare-buttons {
87 87 float: left;
88 88 margin: 0;
89 89 padding: 0 0 @padding;
90 90
91 91 .btn {
92 92 margin: 0 @padding 0 0;
93 93 }
94 94 }
95 95 }
96 96
97 97 }
98 98
99 99 .parents {
100 100 float: left;
101 101 width: 100px;
102 102 font-weight: 400;
103 103 vertical-align: middle;
104 104 padding: 0px 2px 0px 2px;
105 105 background-color: @grey6;
106 106
107 107 #parent_link {
108 108 margin: 00px 2px;
109 109
110 110 &.double {
111 111 margin: 0px 2px;
112 112 }
113 113
114 114 &.disabled{
115 115 margin-right: @padding;
116 116 }
117 117 }
118 118 }
119 119
120 120 .children {
121 121 float: right;
122 122 width: 100px;
123 123 font-weight: 400;
124 124 vertical-align: middle;
125 125 text-align: right;
126 126 padding: 0px 2px 0px 2px;
127 127 background-color: @grey6;
128 128
129 129 #child_link {
130 130 margin: 0px 2px;
131 131
132 132 &.double {
133 133 margin: 0px 2px;
134 134 }
135 135
136 136 &.disabled{
137 137 margin-right: @padding;
138 138 }
139 139 }
140 140 }
141 141
142 142 .changeset_header {
143 143 height: 16px;
144 144
145 145 & > div{
146 146 margin-right: @padding;
147 147 }
148 148 }
149 149
150 150 .changeset_file {
151 151 text-align: left;
152 152 float: left;
153 153 padding: 0;
154 154
155 155 a{
156 156 display: inline-block;
157 157 margin-right: 0.5em;
158 158 }
159 159
160 160 #selected_mode{
161 161 margin-left: 0;
162 162 }
163 163 }
164 164
165 165 .diff-menu-wrapper {
166 166 float: left;
167 167 }
168 168
169 169 .diff-menu {
170 170 position: absolute;
171 171 background: none repeat scroll 0 0 #FFFFFF;
172 172 border-color: #003367 @grey3 @grey3;
173 173 border-right: 1px solid @grey3;
174 174 border-style: solid solid solid;
175 175 border-width: @border-thickness;
176 176 box-shadow: 2px 8px 4px rgba(0, 0, 0, 0.2);
177 177 margin-top: 5px;
178 178 margin-left: 1px;
179 179 }
180 180
181 181 .diff-actions, .editor-actions {
182 182 float: left;
183 183
184 184 input{
185 185 margin: 0 0.5em 0 0;
186 186 }
187 187 }
188 188
189 189 // END CODE-HEADER STYLES
190 190
191 191 // BEGIN CODE-BODY STYLES
192 192
193 193 .code-body {
194 194 padding: 0;
195 195 background-color: #ffffff;
196 196 position: relative;
197 197 max-width: none;
198 198 box-sizing: border-box;
199 199 // TODO: johbo: Parent has overflow: auto, this forces the child here
200 200 // to have the intended size and to scroll. Should be simplified.
201 201 width: 100%;
202 202 overflow-x: auto;
203 203 }
204 204
205 205 pre.raw {
206 206 background: white;
207 207 color: @grey1;
208 208 }
209 209 // END CODE-BODY STYLES
210 210
211 211 }
212 212
213 213
214 214 table.code-difftable {
215 215 border-collapse: collapse;
216 216 width: 99%;
217 217 border-radius: 0px !important;
218 218
219 219 td {
220 220 padding: 0 !important;
221 221 background: none !important;
222 222 border: 0 !important;
223 223 }
224 224
225 225 .context {
226 226 background: none repeat scroll 0 0 #DDE7EF;
227 227 }
228 228
229 229 .add {
230 230 background: none repeat scroll 0 0 #DDFFDD;
231 231
232 232 ins {
233 233 background: none repeat scroll 0 0 #AAFFAA;
234 234 text-decoration: none;
235 235 }
236 236 }
237 237
238 238 .del {
239 239 background: none repeat scroll 0 0 #FFDDDD;
240 240
241 241 del {
242 242 background: none repeat scroll 0 0 #FFAAAA;
243 243 text-decoration: none;
244 244 }
245 245 }
246 246
247 247 /** LINE NUMBERS **/
248 248 .lineno {
249 249 padding-left: 2px !important;
250 250 padding-right: 2px;
251 251 text-align: right;
252 252 width: 32px;
253 253 -moz-user-select: none;
254 254 -webkit-user-select: none;
255 255 border-right: @border-thickness solid @grey5 !important;
256 256 border-left: 0px solid #CCC !important;
257 257 border-top: 0px solid #CCC !important;
258 258 border-bottom: none !important;
259 259
260 260 a {
261 261 &:extend(pre);
262 262 text-align: right;
263 263 padding-right: 2px;
264 264 cursor: pointer;
265 265 display: block;
266 266 width: 32px;
267 267 }
268 268 }
269 269
270 270 .context {
271 271 cursor: auto;
272 272 &:extend(pre);
273 273 }
274 274
275 275 .lineno-inline {
276 276 background: none repeat scroll 0 0 #FFF !important;
277 277 padding-left: 2px;
278 278 padding-right: 2px;
279 279 text-align: right;
280 280 width: 30px;
281 281 -moz-user-select: none;
282 282 -webkit-user-select: none;
283 283 }
284 284
285 285 /** CODE **/
286 286 .code {
287 287 display: block;
288 288 width: 100%;
289 289
290 290 td {
291 291 margin: 0;
292 292 padding: 0;
293 293 }
294 294
295 295 pre {
296 296 margin: 0;
297 297 padding: 0;
298 298 margin-left: .5em;
299 299 }
300 300 }
301 301 }
302 302
303 303
304 304 // Comments
305 305 .comment-selected-hl {
306 306 border-left: 6px solid @comment-highlight-color !important;
307 307 padding-left: 3px !important;
308 308 margin-left: -7px !important;
309 309 }
310 310
311 311 div.comment:target,
312 312 div.comment-outdated:target {
313 313 .comment-selected-hl;
314 314 }
315 315
316 316 //TODO: anderson: can't get an absolute number out of anything, so had to put the
317 317 //current values that might change. But to make it clear I put as a calculation
318 318 @comment-max-width: 1065px;
319 319 @pr-extra-margin: 34px;
320 320 @pr-border-spacing: 4px;
321 321 @pr-comment-width: @comment-max-width - @pr-extra-margin - @pr-border-spacing;
322 322
323 323 // Pull Request
324 324 .cs_files .code-difftable {
325 325 border: @border-thickness solid @grey5; //borders only on PRs
326 326
327 327 .comment-inline-form,
328 328 div.comment {
329 329 width: @pr-comment-width;
330 330 }
331 331 }
332 332
333 333 // Changeset
334 334 .code-difftable {
335 335 .comment-inline-form,
336 336 div.comment {
337 337 width: @comment-max-width;
338 338 }
339 339 }
340 340
341 341 //Style page
342 342 @style-extra-margin: @sidebar-width + (@sidebarpadding * 3) + @padding;
343 343 #style-page .code-difftable{
344 344 .comment-inline-form,
345 345 div.comment {
346 346 width: @comment-max-width - @style-extra-margin;
347 347 }
348 348 }
349 349
350 350 #context-bar > h2 {
351 351 font-size: 20px;
352 352 }
353 353
354 354 #context-bar > h2> a {
355 355 font-size: 20px;
356 356 }
357 357 // end of defaults
358 358
359 359 .file_diff_buttons {
360 360 padding: 0 0 @padding;
361 361
362 362 .drop-menu {
363 363 float: left;
364 364 margin: 0 @padding 0 0;
365 365 }
366 366 .btn {
367 367 margin: 0 @padding 0 0;
368 368 }
369 369 }
370 370
371 371 .code-body.textarea.editor {
372 372 max-width: none;
373 373 padding: 15px;
374 374 }
375 375
376 376 td.injected_diff{
377 377 max-width: 1178px;
378 378 overflow-x: auto;
379 379 overflow-y: hidden;
380 380
381 381 div.diff-container,
382 382 div.diffblock{
383 383 max-width: 100%;
384 384 }
385 385
386 386 div.code-body {
387 387 max-width: 1124px;
388 388 overflow-x: auto;
389 389 overflow-y: hidden;
390 390 padding: 0;
391 391 }
392 392 div.diffblock {
393 393 border: none;
394 394 }
395 395
396 396 &.inline-form {
397 397 width: 99%
398 398 }
399 399 }
400 400
401 401
402 402 table.code-difftable {
403 403 width: 100%;
404 404 }
405 405
406 406 /** PYGMENTS COLORING **/
407 407 div.codeblock {
408 408
409 409 // TODO: johbo: Added interim to get rid of the margin around
410 410 // Select2 widgets. This needs further cleanup.
411 411 overflow: auto;
412 412 padding: 0px;
413 413 border: @border-thickness solid @grey6;
414 414 .border-radius(@border-radius);
415 415
416 416 #remove_gist {
417 417 float: right;
418 418 }
419 419
420 420 .gist_url {
421 421 padding: 0px 0px 35px 0px;
422 422 }
423 423
424 424 .gist-desc {
425 425 clear: both;
426 426 margin: 0 0 10px 0;
427 427 code {
428 428 white-space: pre-line;
429 429 line-height: inherit
430 430 }
431 431 }
432 432
433 433 .author {
434 434 clear: both;
435 435 vertical-align: middle;
436 436 font-weight: @text-bold-weight;
437 437 font-family: @text-bold;
438 438 }
439 439
440 440 .btn-mini {
441 441 float: left;
442 442 margin: 0 5px 0 0;
443 443 }
444 444
445 445 .code-header {
446 446 padding: @padding;
447 447 border-bottom: @border-thickness solid @grey5;
448 448
449 449 .rc-user {
450 450 min-width: 0;
451 451 margin-right: .5em;
452 452 }
453 453
454 454 .stats {
455 455 clear: both;
456 456 margin: 0 0 @padding 0;
457 457 padding: 0;
458 458 .left {
459 459 float: left;
460 460 clear: left;
461 461 max-width: 75%;
462 462 margin: 0 0 @padding 0;
463 463
464 464 &.item {
465 465 margin-right: @padding;
466 466 &.last { border-right: none; }
467 467 }
468 468 }
469 469 .buttons { float: right; }
470 470 .author {
471 471 height: 25px; margin-left: 15px; font-weight: bold;
472 472 }
473 473 }
474 474
475 475 .commit {
476 476 margin: 5px 0 0 26px;
477 477 font-weight: normal;
478 478 white-space: pre-wrap;
479 479 }
480 480 }
481 481
482 482 .message {
483 483 position: relative;
484 484 margin: @padding;
485 485
486 486 .codeblock-label {
487 487 margin: 0 0 1em 0;
488 488 }
489 489 }
490 490
491 491 .code-body {
492 492 padding: 0.8em 1em;
493 493 background-color: #ffffff;
494 494 min-width: 100%;
495 495 box-sizing: border-box;
496 496 // TODO: johbo: Parent has overflow: auto, this forces the child here
497 497 // to have the intended size and to scroll. Should be simplified.
498 498 width: 100%;
499 499 overflow-x: auto;
500 500
501 501 img.rendered-binary {
502 502 height: auto;
503 503 width: auto;
504 504 }
505 505
506 506 .markdown-block {
507 507 padding: 1em 0;
508 508 }
509 509 }
510 510
511 511 .codeblock-header {
512 512 background: @grey7;
513 513 height: 36px;
514 514 }
515 515
516 516 .path {
517 517 border-bottom: 1px solid @grey6;
518 518 padding: .65em 1em;
519 519 height: 18px;
520 520 }
521 521 }
522 522
523 523 .code-highlighttable,
524 524 div.codeblock {
525 525
526 526 &.readme {
527 527 background-color: white;
528 528 }
529 529
530 530 .markdown-block table {
531 531 border-collapse: collapse;
532 532
533 533 th,
534 534 td {
535 535 padding: .5em;
536 536 border: @border-thickness solid @border-default-color;
537 537 }
538 538 }
539 539
540 540 table {
541 541 border: 0px;
542 542 margin: 0;
543 543 letter-spacing: normal;
544 544
545 545
546 546 td {
547 547 border: 0px;
548 548 vertical-align: top;
549 549 }
550 550 }
551 551 }
552 552
553 553 div.codeblock .code-header .search-path { padding: 0 0 0 10px; }
554 554 div.search-code-body {
555 555 background-color: #ffffff; padding: 5px 0 5px 10px;
556 556 pre {
557 557 .match { background-color: #faffa6;}
558 558 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
559 559 }
560 560 .code-highlighttable {
561 561 border-collapse: collapse;
562 562
563 563 tr:hover {
564 564 background: #fafafa;
565 565 }
566 566 td.code {
567 567 padding-left: 10px;
568 568 }
569 569 td.line {
570 570 border-right: 1px solid #ccc !important;
571 571 padding-right: 10px;
572 572 text-align: right;
573 573 font-family: @text-monospace;
574 574 span {
575 575 white-space: pre-wrap;
576 576 color: #666666;
577 577 }
578 578 }
579 579 }
580 580 }
581 581
582 582 div.annotatediv { margin-left: 2px; margin-right: 4px; }
583 583 .code-highlight {
584 584 margin: 0; padding: 0; border-left: @border-thickness solid @grey5;
585 585 pre, .linenodiv pre { padding: 0 5px; margin: 0; }
586 586 pre div:target {background-color: @comment-highlight-color !important;}
587 587 }
588 588
589 589 .linenos a { text-decoration: none; }
590 590
591 591 .CodeMirror-selected { background: @rchighlightblue; }
592 592 .CodeMirror-focused .CodeMirror-selected { background: @rchighlightblue; }
593 593 .CodeMirror ::selection { background: @rchighlightblue; }
594 594 .CodeMirror ::-moz-selection { background: @rchighlightblue; }
595 595
596 596 .code { display: block; border:0px !important; }
597 597
598 598 .code-highlight, /* TODO: dan: merge codehilite into code-highlight */
599 599 .codehilite {
600 600 /*ElasticMatch is custom RhodeCode TAG*/
601 601
602 602 .c-ElasticMatch {
603 603 background-color: #faffa6;
604 604 padding: 0.2em;
605 605 }
606 606 }
607 607
608 608 /* This can be generated with `pygmentize -S default -f html` */
609 609 .code-highlight,
610 610 .codehilite {
611 611 /*ElasticMatch is custom RhodeCode TAG*/
612 612 .c-ElasticMatch { background-color: #faffa6; padding: 0.2em;}
613 613 .hll { background-color: #ffffcc }
614 614 .c { color: #408080; font-style: italic } /* Comment */
615 615 .err, .codehilite .err { border: none } /* Error */
616 616 .k { color: #008000; font-weight: bold } /* Keyword */
617 617 .o { color: #666666 } /* Operator */
618 618 .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
619 619 .cm { color: #408080; font-style: italic } /* Comment.Multiline */
620 620 .cp { color: #BC7A00 } /* Comment.Preproc */
621 621 .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
622 622 .c1 { color: #408080; font-style: italic } /* Comment.Single */
623 623 .cs { color: #408080; font-style: italic } /* Comment.Special */
624 624 .gd { color: #A00000 } /* Generic.Deleted */
625 625 .ge { font-style: italic } /* Generic.Emph */
626 626 .gr { color: #FF0000 } /* Generic.Error */
627 627 .gh { color: #000080; font-weight: bold } /* Generic.Heading */
628 628 .gi { color: #00A000 } /* Generic.Inserted */
629 629 .go { color: #888888 } /* Generic.Output */
630 630 .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
631 631 .gs { font-weight: bold } /* Generic.Strong */
632 632 .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
633 633 .gt { color: #0044DD } /* Generic.Traceback */
634 634 .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
635 635 .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
636 636 .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
637 637 .kp { color: #008000 } /* Keyword.Pseudo */
638 638 .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
639 639 .kt { color: #B00040 } /* Keyword.Type */
640 640 .m { color: #666666 } /* Literal.Number */
641 641 .s { color: #BA2121 } /* Literal.String */
642 642 .na { color: #7D9029 } /* Name.Attribute */
643 643 .nb { color: #008000 } /* Name.Builtin */
644 644 .nc { color: #0000FF; font-weight: bold } /* Name.Class */
645 645 .no { color: #880000 } /* Name.Constant */
646 646 .nd { color: #AA22FF } /* Name.Decorator */
647 647 .ni { color: #999999; font-weight: bold } /* Name.Entity */
648 648 .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
649 649 .nf { color: #0000FF } /* Name.Function */
650 650 .nl { color: #A0A000 } /* Name.Label */
651 651 .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
652 652 .nt { color: #008000; font-weight: bold } /* Name.Tag */
653 653 .nv { color: #19177C } /* Name.Variable */
654 654 .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
655 655 .w { color: #bbbbbb } /* Text.Whitespace */
656 656 .mb { color: #666666 } /* Literal.Number.Bin */
657 657 .mf { color: #666666 } /* Literal.Number.Float */
658 658 .mh { color: #666666 } /* Literal.Number.Hex */
659 659 .mi { color: #666666 } /* Literal.Number.Integer */
660 660 .mo { color: #666666 } /* Literal.Number.Oct */
661 661 .sa { color: #BA2121 } /* Literal.String.Affix */
662 662 .sb { color: #BA2121 } /* Literal.String.Backtick */
663 663 .sc { color: #BA2121 } /* Literal.String.Char */
664 664 .dl { color: #BA2121 } /* Literal.String.Delimiter */
665 665 .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
666 666 .s2 { color: #BA2121 } /* Literal.String.Double */
667 667 .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
668 668 .sh { color: #BA2121 } /* Literal.String.Heredoc */
669 669 .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
670 670 .sx { color: #008000 } /* Literal.String.Other */
671 671 .sr { color: #BB6688 } /* Literal.String.Regex */
672 672 .s1 { color: #BA2121 } /* Literal.String.Single */
673 673 .ss { color: #19177C } /* Literal.String.Symbol */
674 674 .bp { color: #008000 } /* Name.Builtin.Pseudo */
675 675 .fm { color: #0000FF } /* Name.Function.Magic */
676 676 .vc { color: #19177C } /* Name.Variable.Class */
677 677 .vg { color: #19177C } /* Name.Variable.Global */
678 678 .vi { color: #19177C } /* Name.Variable.Instance */
679 679 .vm { color: #19177C } /* Name.Variable.Magic */
680 680 .il { color: #666666 } /* Literal.Number.Integer.Long */
681 681
682 682 }
683 683
684 684 /* customized pre blocks for markdown/rst */
685 685 pre.literal-block, .codehilite pre{
686 686 padding: @padding;
687 687 border: 1px solid @grey6;
688 688 .border-radius(@border-radius);
689 689 background-color: @grey7;
690 690 }
691 691
692 692
693 693 /* START NEW CODE BLOCK CSS */
694 694
695 695 @cb-line-height: 18px;
696 696 @cb-line-code-padding: 10px;
697 697 @cb-text-padding: 5px;
698 698
699 699 @pill-padding: 2px 7px;
700 700 @pill-padding-small: 2px 2px 1px 2px;
701 701
702 702 input.filediff-collapse-state {
703 703 display: none;
704 704
705 705 &:checked + .filediff { /* file diff is collapsed */
706 706 .cb {
707 707 display: none
708 708 }
709 709 .filediff-collapse-indicator {
710 710 float: left;
711 711 cursor: pointer;
712 712 margin: 1px -5px;
713 713 }
714 714 .filediff-collapse-indicator:before {
715 715 content: '\f105';
716 716 }
717 717
718 718 .filediff-menu {
719 719 display: none;
720 720 }
721 721
722 722 }
723 723
724 724 &+ .filediff { /* file diff is expanded */
725 725
726 726 .filediff-collapse-indicator {
727 727 float: left;
728 728 cursor: pointer;
729 729 margin: 1px -5px;
730 730 }
731 731 .filediff-collapse-indicator:before {
732 732 content: '\f107';
733 733 }
734 734
735 735 .filediff-menu {
736 736 display: block;
737 737 }
738 738
739 739 margin: 10px 0;
740 740 &:nth-child(2) {
741 741 margin: 0;
742 742 }
743 743 }
744 744 }
745 745
746 746 .filediffs .anchor {
747 747 display: block;
748 748 height: 40px;
749 749 margin-top: -40px;
750 750 visibility: hidden;
751 751 }
752 752
753 753 .filediffs .anchor:nth-of-type(1) {
754 754 display: block;
755 755 height: 80px;
756 756 margin-top: -80px;
757 757 visibility: hidden;
758 758 }
759 759
760 760 .cs_files {
761 761 clear: both;
762 762 }
763 763
764 764 #diff-file-sticky{
765 765 will-change: min-height;
766 766 height: 80px;
767 767 }
768 768
769 769 .sidebar__inner{
770 770 transform: translate(0, 0); /* For browsers don't support translate3d. */
771 771 transform: translate3d(0, 0, 0);
772 772 will-change: position, transform;
773 773 height: 65px;
774 774 background-color: #fff;
775 775 padding: 5px 0px;
776 776 }
777 777
778 778 .sidebar__bar {
779 779 padding: 5px 0px 0px 0px
780 780 }
781 781
782 782 .fpath-placeholder {
783 783 clear: both;
784 784 visibility: hidden
785 785 }
786 786
787 787 .is-affixed {
788 788
789 789 .sidebar__inner {
790 790 z-index: 30;
791 791 }
792 792
793 793 .sidebar_inner_shadow {
794 794 position: fixed;
795 795 top: 75px;
796 796 right: -100%;
797 797 left: -100%;
798 798 z-index: 30;
799 799 display: block;
800 800 height: 5px;
801 801 content: "";
802 802 background: linear-gradient(rgba(0, 0, 0, 0.075), rgba(0, 0, 0, 0.001)) repeat-x 0 0;
803 803 border-top: 1px solid rgba(0, 0, 0, 0.15);
804 804 }
805 805
806 806 .fpath-placeholder {
807 807 visibility: visible !important;
808 808 }
809 809 }
810 810
811 811 .diffset-menu {
812 812
813 813 }
814 814
815 815 #todo-box {
816 816 clear:both;
817 817 display: none;
818 818 text-align: right
819 819 }
820 820
821 821 .diffset {
822 822 margin: 0px auto;
823 823 .diffset-heading {
824 824 border: 1px solid @grey5;
825 825 margin-bottom: -1px;
826 826 // margin-top: 20px;
827 827 h2 {
828 828 margin: 0;
829 829 line-height: 38px;
830 830 padding-left: 10px;
831 831 }
832 832 .btn {
833 833 margin: 0;
834 834 }
835 835 background: @grey6;
836 836 display: block;
837 837 padding: 5px;
838 838 }
839 839 .diffset-heading-warning {
840 840 background: @alert3-inner;
841 841 border: 1px solid @alert3;
842 842 }
843 843 &.diffset-comments-disabled {
844 844 .cb-comment-box-opener, .comment-inline-form, .cb-comment-add-button {
845 845 display: none !important;
846 846 }
847 847 }
848 848 }
849 849
850 850 .filelist {
851 851 .pill {
852 852 display: block;
853 853 float: left;
854 854 padding: @pill-padding-small;
855 855 }
856 856 }
857 857
858 858 .pill {
859 859 display: block;
860 860 float: left;
861 861 padding: @pill-padding;
862 862 }
863 863
864 864 .pill-group {
865 865 .pill {
866 866 opacity: .8;
867 867 margin-right: 3px;
868 868 font-size: 12px;
869 869 font-weight: normal;
870 870 min-width: 30px;
871 871 text-align: center;
872 872
873 873 &:first-child {
874 874 border-radius: @border-radius 0 0 @border-radius;
875 875 }
876 876 &:last-child {
877 877 border-radius: 0 @border-radius @border-radius 0;
878 878 }
879 879 &:only-child {
880 880 border-radius: @border-radius;
881 881 margin-right: 0;
882 882 }
883 883 }
884 884 }
885 885
886 886 /* Main comments*/
887 887 #comments {
888 888 .comment-selected {
889 889 border-left: 6px solid @comment-highlight-color;
890 890 padding-left: 3px;
891 891 margin-left: -9px;
892 892 }
893 893 }
894 894
895 895 .filediff {
896 896 border: 1px solid @grey5;
897 897
898 898 /* START OVERRIDES */
899 899 .code-highlight {
900 900 border: none; // TODO: remove this border from the global
901 901 // .code-highlight, it doesn't belong there
902 902 }
903 903 label {
904 904 margin: 0; // TODO: remove this margin definition from global label
905 905 // it doesn't belong there - if margin on labels
906 906 // are needed for a form they should be defined
907 907 // in the form's class
908 908 }
909 909 /* END OVERRIDES */
910 910
911 911 * {
912 912 box-sizing: border-box;
913 913 }
914
915 .on-hover-icon {
916 visibility: hidden;
917 }
918
914 919 .filediff-anchor {
915 920 visibility: hidden;
916 921 }
917 922 &:hover {
918 923 .filediff-anchor {
919 924 visibility: visible;
920 925 }
926 .on-hover-icon {
927 visibility: visible;
928 }
921 929 }
922 930
923 931 .filediff-heading {
924 932 cursor: pointer;
925 933 display: block;
926 934 padding: 10px 10px;
927 935 }
928 936 .filediff-heading:after {
929 937 content: "";
930 938 display: table;
931 939 clear: both;
932 940 }
933 941 .filediff-heading:hover {
934 942 background: #e1e9f4 !important;
935 943 }
936 944
937 945 .filediff-menu {
938 946 text-align: right;
939 947 padding: 5px 5px 5px 0px;
940 948 background: @grey7;
941 949
942 950 &> a,
943 951 &> span {
944 952 padding: 1px;
945 953 }
946 954 }
947 955
948 956 .filediff-collapse-button, .filediff-expand-button {
949 957 cursor: pointer;
950 958 }
951 959 .filediff-collapse-button {
952 960 display: inline;
953 961 }
954 962 .filediff-expand-button {
955 963 display: none;
956 964 }
957 965 .filediff-collapsed .filediff-collapse-button {
958 966 display: none;
959 967 }
960 968 .filediff-collapsed .filediff-expand-button {
961 969 display: inline;
962 970 }
963 971
964 972 /**** COMMENTS ****/
965 973
966 974 .filediff-menu {
967 975 .show-comment-button {
968 976 display: none;
969 977 }
970 978 }
971 979 &.hide-comments {
972 980 .inline-comments {
973 981 display: none;
974 982 }
975 983 .filediff-menu {
976 984 .show-comment-button {
977 985 display: inline;
978 986 }
979 987 .hide-comment-button {
980 988 display: none;
981 989 }
982 990 }
983 991 }
984 992
985 993 .hide-line-comments {
986 994 .inline-comments {
987 995 display: none;
988 996 }
989 997 }
990 998
991 999 /**** END COMMENTS ****/
992 1000
993 1001 }
994 1002
995 1003
996 1004 .op-added {
997 1005 color: @alert1;
998 1006 }
999 1007
1000 1008 .op-deleted {
1001 1009 color: @alert2;
1002 1010 }
1003 1011
1004 1012 .filediff, .filelist {
1005 1013
1006 1014 .pill {
1007 1015 &[op="name"] {
1008 1016 background: none;
1009 1017 opacity: 1;
1010 1018 color: white;
1011 1019 }
1012 1020 &[op="limited"] {
1013 1021 background: @grey2;
1014 1022 color: white;
1015 1023 }
1016 1024 &[op="binary"] {
1017 1025 background: @color7;
1018 1026 color: white;
1019 1027 }
1020 1028 &[op="modified"] {
1021 1029 background: @alert1;
1022 1030 color: white;
1023 1031 }
1024 1032 &[op="renamed"] {
1025 1033 background: @color4;
1026 1034 color: white;
1027 1035 }
1028 1036 &[op="copied"] {
1029 1037 background: @color4;
1030 1038 color: white;
1031 1039 }
1032 1040 &[op="mode"] {
1033 1041 background: @grey3;
1034 1042 color: white;
1035 1043 }
1036 1044 &[op="symlink"] {
1037 1045 background: @color8;
1038 1046 color: white;
1039 1047 }
1040 1048
1041 1049 &[op="added"] { /* added lines */
1042 1050 background: @alert1;
1043 1051 color: white;
1044 1052 }
1045 1053 &[op="deleted"] { /* deleted lines */
1046 1054 background: @alert2;
1047 1055 color: white;
1048 1056 }
1049 1057
1050 1058 &[op="created"] { /* created file */
1051 1059 background: @alert1;
1052 1060 color: white;
1053 1061 }
1054 1062 &[op="removed"] { /* deleted file */
1055 1063 background: @color5;
1056 1064 color: white;
1057 1065 }
1058 1066 }
1059 1067 }
1060 1068
1061 1069
1062 1070 .filediff-outdated {
1063 1071 padding: 8px 0;
1064 1072
1065 1073 .filediff-heading {
1066 1074 opacity: .5;
1067 1075 }
1068 1076 }
1069 1077
1070 1078 table.cb {
1071 1079 width: 100%;
1072 1080 border-collapse: collapse;
1073 1081
1074 1082 .cb-text {
1075 1083 padding: @cb-text-padding;
1076 1084 }
1077 1085 .cb-hunk {
1078 1086 padding: @cb-text-padding;
1079 1087 }
1080 1088 .cb-expand {
1081 1089 display: none;
1082 1090 }
1083 1091 .cb-collapse {
1084 1092 display: inline;
1085 1093 }
1086 1094 &.cb-collapsed {
1087 1095 .cb-line {
1088 1096 display: none;
1089 1097 }
1090 1098 .cb-expand {
1091 1099 display: inline;
1092 1100 }
1093 1101 .cb-collapse {
1094 1102 display: none;
1095 1103 }
1096 1104 .cb-hunk {
1097 1105 display: none;
1098 1106 }
1099 1107 }
1100 1108
1101 1109 /* intentionally general selector since .cb-line-selected must override it
1102 1110 and they both use !important since the td itself may have a random color
1103 1111 generated by annotation blocks. TLDR: if you change it, make sure
1104 1112 annotated block selection and line selection in file view still work */
1105 1113 .cb-line-fresh .cb-content {
1106 1114 background: white !important;
1107 1115 }
1108 1116 .cb-warning {
1109 1117 background: #fff4dd;
1110 1118 }
1111 1119
1112 1120 &.cb-diff-sideside {
1113 1121 td {
1114 1122 &.cb-content {
1115 1123 width: 50%;
1116 1124 }
1117 1125 }
1118 1126 }
1119 1127
1120 1128 tr {
1121 1129 &.cb-annotate {
1122 1130 border-top: 1px solid #eee;
1123 1131 }
1124 1132
1125 1133 &.cb-comment-info {
1126 1134 border-top: 1px solid #eee;
1127 1135 color: rgba(0, 0, 0, 0.3);
1128 1136 background: #edf2f9;
1129 1137
1130 1138 td {
1131 1139
1132 1140 }
1133 1141 }
1134 1142
1135 1143 &.cb-hunk {
1136 1144 font-family: @text-monospace;
1137 1145 color: rgba(0, 0, 0, 0.3);
1138 1146
1139 1147 td {
1140 1148 &:first-child {
1141 1149 background: #edf2f9;
1142 1150 }
1143 1151 &:last-child {
1144 1152 background: #f4f7fb;
1145 1153 }
1146 1154 }
1147 1155 }
1148 1156 }
1149 1157
1150 1158
1151 1159 td {
1152 1160 vertical-align: top;
1153 1161 padding: 0;
1154 1162
1155 1163 &.cb-content {
1156 1164 font-size: 12.35px;
1157 1165
1158 1166 &.cb-line-selected .cb-code {
1159 1167 background: @comment-highlight-color !important;
1160 1168 }
1161 1169
1162 1170 span.cb-code {
1163 1171 line-height: @cb-line-height;
1164 1172 padding-left: @cb-line-code-padding;
1165 1173 padding-right: @cb-line-code-padding;
1166 1174 display: block;
1167 1175 white-space: pre-wrap;
1168 1176 font-family: @text-monospace;
1169 1177 word-break: break-all;
1170 1178 .nonl {
1171 1179 color: @color5;
1172 1180 }
1173 1181 .cb-action {
1174 1182 &:before {
1175 1183 content: " ";
1176 1184 }
1177 1185 &.cb-deletion:before {
1178 1186 content: "- ";
1179 1187 }
1180 1188 &.cb-addition:before {
1181 1189 content: "+ ";
1182 1190 }
1183 1191 }
1184 1192 }
1185 1193
1186 1194 &> button.cb-comment-box-opener {
1187 1195
1188 1196 padding: 2px 2px 1px 3px;
1189 1197 margin-left: -6px;
1190 1198 margin-top: -1px;
1191 1199
1192 1200 border-radius: @border-radius;
1193 1201 position: absolute;
1194 1202 display: none;
1195 1203 }
1196 1204 .cb-comment {
1197 1205 margin-top: 10px;
1198 1206 white-space: normal;
1199 1207 }
1200 1208 }
1201 1209 &:hover {
1202 1210 button.cb-comment-box-opener {
1203 1211 display: block;
1204 1212 }
1205 1213 &+ td button.cb-comment-box-opener {
1206 1214 display: block
1207 1215 }
1208 1216 }
1209 1217
1210 1218 &.cb-data {
1211 1219 text-align: right;
1212 1220 width: 30px;
1213 1221 font-family: @text-monospace;
1214 1222
1215 1223 .icon-comment {
1216 1224 cursor: pointer;
1217 1225 }
1218 1226 &.cb-line-selected {
1219 1227 background: @comment-highlight-color !important;
1220 1228 }
1221 1229 &.cb-line-selected > div {
1222 1230 display: block;
1223 1231 background: @comment-highlight-color !important;
1224 1232 line-height: @cb-line-height;
1225 1233 color: rgba(0, 0, 0, 0.3);
1226 1234 }
1227 1235 }
1228 1236
1229 1237 &.cb-lineno {
1230 1238 padding: 0;
1231 1239 width: 50px;
1232 1240 color: rgba(0, 0, 0, 0.3);
1233 1241 text-align: right;
1234 1242 border-right: 1px solid #eee;
1235 1243 font-family: @text-monospace;
1236 1244 -webkit-user-select: none;
1237 1245 -moz-user-select: none;
1238 1246 user-select: none;
1239 1247
1240 1248 a::before {
1241 1249 content: attr(data-line-no);
1242 1250 }
1243 1251 &.cb-line-selected {
1244 1252 background: @comment-highlight-color !important;
1245 1253 }
1246 1254
1247 1255 a {
1248 1256 display: block;
1249 1257 padding-right: @cb-line-code-padding;
1250 1258 padding-left: @cb-line-code-padding;
1251 1259 line-height: @cb-line-height;
1252 1260 color: rgba(0, 0, 0, 0.3);
1253 1261 }
1254 1262 }
1255 1263
1256 1264 &.cb-empty {
1257 1265 background: @grey7;
1258 1266 }
1259 1267
1260 1268 ins {
1261 1269 color: black;
1262 1270 background: #a6f3a6;
1263 1271 text-decoration: none;
1264 1272 }
1265 1273 del {
1266 1274 color: black;
1267 1275 background: #f8cbcb;
1268 1276 text-decoration: none;
1269 1277 }
1270 1278 &.cb-addition {
1271 1279 background: #ecffec;
1272 1280
1273 1281 &.blob-lineno {
1274 1282 background: #ddffdd;
1275 1283 }
1276 1284 }
1277 1285 &.cb-deletion {
1278 1286 background: #ffecec;
1279 1287
1280 1288 &.blob-lineno {
1281 1289 background: #ffdddd;
1282 1290 }
1283 1291 }
1284 1292 &.cb-annotate-message-spacer {
1285 1293 width:8px;
1286 1294 padding: 1px 0px 0px 3px;
1287 1295 }
1288 1296 &.cb-annotate-info {
1289 1297 width: 320px;
1290 1298 min-width: 320px;
1291 1299 max-width: 320px;
1292 1300 padding: 5px 2px;
1293 1301 font-size: 13px;
1294 1302
1295 1303 .cb-annotate-message {
1296 1304 padding: 2px 0px 0px 0px;
1297 1305 white-space: pre-line;
1298 1306 overflow: hidden;
1299 1307 }
1300 1308 .rc-user {
1301 1309 float: none;
1302 1310 padding: 0 6px 0 17px;
1303 1311 min-width: unset;
1304 1312 min-height: unset;
1305 1313 }
1306 1314 }
1307 1315
1308 1316 &.cb-annotate-revision {
1309 1317 cursor: pointer;
1310 1318 text-align: right;
1311 1319 padding: 1px 3px 0px 3px;
1312 1320 }
1313 1321 }
1314 1322 }
@@ -1,3060 +1,3067 b''
1 1 //Primary CSS
2 2
3 3 //--- IMPORTS ------------------//
4 4
5 5 @import 'helpers';
6 6 @import 'mixins';
7 7 @import 'rcicons';
8 8 @import 'variables';
9 9 @import 'bootstrap-variables';
10 10 @import 'form-bootstrap';
11 11 @import 'codemirror';
12 12 @import 'legacy_code_styles';
13 13 @import 'readme-box';
14 14 @import 'progress-bar';
15 15
16 16 @import 'type';
17 17 @import 'alerts';
18 18 @import 'buttons';
19 19 @import 'tags';
20 20 @import 'code-block';
21 21 @import 'examples';
22 22 @import 'login';
23 23 @import 'main-content';
24 24 @import 'select2';
25 25 @import 'comments';
26 26 @import 'panels-bootstrap';
27 27 @import 'panels';
28 28 @import 'deform';
29 29 @import 'tooltips';
30 30 @import 'sweetalert2';
31 31
32 32
33 33 //--- BASE ------------------//
34 34 .noscript-error {
35 35 top: 0;
36 36 left: 0;
37 37 width: 100%;
38 38 z-index: 101;
39 39 text-align: center;
40 40 font-size: 120%;
41 41 color: white;
42 42 background-color: @alert2;
43 43 padding: 5px 0 5px 0;
44 44 font-weight: @text-semibold-weight;
45 45 font-family: @text-semibold;
46 46 }
47 47
48 48 html {
49 49 display: table;
50 50 height: 100%;
51 51 width: 100%;
52 52 }
53 53
54 54 body {
55 55 display: table-cell;
56 56 width: 100%;
57 57 }
58 58
59 59 //--- LAYOUT ------------------//
60 60
61 61 .hidden{
62 62 display: none !important;
63 63 }
64 64
65 65 .box{
66 66 float: left;
67 67 width: 100%;
68 68 }
69 69
70 70 .browser-header {
71 71 clear: both;
72 72 }
73 73 .main {
74 74 clear: both;
75 75 padding:0 0 @pagepadding;
76 76 height: auto;
77 77
78 78 &:after { //clearfix
79 79 content:"";
80 80 clear:both;
81 81 width:100%;
82 82 display:block;
83 83 }
84 84 }
85 85
86 86 .action-link{
87 87 margin-left: @padding;
88 88 padding-left: @padding;
89 89 border-left: @border-thickness solid @border-default-color;
90 90 }
91 91
92 92 .cursor-pointer {
93 93 cursor: pointer;
94 94 }
95 95
96 96 input + .action-link, .action-link.first{
97 97 border-left: none;
98 98 }
99 99
100 100 .action-link.last{
101 101 margin-right: @padding;
102 102 padding-right: @padding;
103 103 }
104 104
105 105 .action-link.active,
106 106 .action-link.active a{
107 107 color: @grey4;
108 108 }
109 109
110 110 .action-link.disabled {
111 111 color: @grey4;
112 112 cursor: inherit;
113 113 }
114 114
115 .grey-link-action {
116 cursor: pointer;
117 &:hover {
118 color: @grey2;
119 }
120 color: @grey4;
121 }
115 122
116 123 .clipboard-action {
117 124 cursor: pointer;
118 125 margin-left: 5px;
119 126
120 127 &:not(.no-grey) {
121 128
122 129 &:hover {
123 130 color: @grey2;
124 131 }
125 132 color: @grey4;
126 133 }
127 134 }
128 135
129 136 ul.simple-list{
130 137 list-style: none;
131 138 margin: 0;
132 139 padding: 0;
133 140 }
134 141
135 142 .main-content {
136 143 padding-bottom: @pagepadding;
137 144 }
138 145
139 146 .wide-mode-wrapper {
140 147 max-width:4000px !important;
141 148 }
142 149
143 150 .wrapper {
144 151 position: relative;
145 152 max-width: @wrapper-maxwidth;
146 153 margin: 0 auto;
147 154 }
148 155
149 156 #content {
150 157 clear: both;
151 158 padding: 0 @contentpadding;
152 159 }
153 160
154 161 .advanced-settings-fields{
155 162 input{
156 163 margin-left: @textmargin;
157 164 margin-right: @padding/2;
158 165 }
159 166 }
160 167
161 168 .cs_files_title {
162 169 margin: @pagepadding 0 0;
163 170 }
164 171
165 172 input.inline[type="file"] {
166 173 display: inline;
167 174 }
168 175
169 176 .error_page {
170 177 margin: 10% auto;
171 178
172 179 h1 {
173 180 color: @grey2;
174 181 }
175 182
176 183 .alert {
177 184 margin: @padding 0;
178 185 }
179 186
180 187 .error-branding {
181 188 color: @grey4;
182 189 font-weight: @text-semibold-weight;
183 190 font-family: @text-semibold;
184 191 }
185 192
186 193 .error_message {
187 194 font-family: @text-regular;
188 195 }
189 196
190 197 .sidebar {
191 198 min-height: 275px;
192 199 margin: 0;
193 200 padding: 0 0 @sidebarpadding @sidebarpadding;
194 201 border: none;
195 202 }
196 203
197 204 .main-content {
198 205 position: relative;
199 206 margin: 0 @sidebarpadding @sidebarpadding;
200 207 padding: 0 0 0 @sidebarpadding;
201 208 border-left: @border-thickness solid @grey5;
202 209
203 210 @media (max-width:767px) {
204 211 clear: both;
205 212 width: 100%;
206 213 margin: 0;
207 214 border: none;
208 215 }
209 216 }
210 217
211 218 .inner-column {
212 219 float: left;
213 220 width: 29.75%;
214 221 min-height: 150px;
215 222 margin: @sidebarpadding 2% 0 0;
216 223 padding: 0 2% 0 0;
217 224 border-right: @border-thickness solid @grey5;
218 225
219 226 @media (max-width:767px) {
220 227 clear: both;
221 228 width: 100%;
222 229 border: none;
223 230 }
224 231
225 232 ul {
226 233 padding-left: 1.25em;
227 234 }
228 235
229 236 &:last-child {
230 237 margin: @sidebarpadding 0 0;
231 238 border: none;
232 239 }
233 240
234 241 h4 {
235 242 margin: 0 0 @padding;
236 243 font-weight: @text-semibold-weight;
237 244 font-family: @text-semibold;
238 245 }
239 246 }
240 247 }
241 248 .error-page-logo {
242 249 width: 130px;
243 250 height: 160px;
244 251 }
245 252
246 253 // HEADER
247 254 .header {
248 255
249 256 // TODO: johbo: Fix login pages, so that they work without a min-height
250 257 // for the header and then remove the min-height. I chose a smaller value
251 258 // intentionally here to avoid rendering issues in the main navigation.
252 259 min-height: 49px;
253 260 min-width: 1024px;
254 261
255 262 position: relative;
256 263 vertical-align: bottom;
257 264 padding: 0 @header-padding;
258 265 background-color: @grey1;
259 266 color: @grey5;
260 267
261 268 .title {
262 269 overflow: visible;
263 270 }
264 271
265 272 &:before,
266 273 &:after {
267 274 content: "";
268 275 clear: both;
269 276 width: 100%;
270 277 }
271 278
272 279 // TODO: johbo: Avoids breaking "Repositories" chooser
273 280 .select2-container .select2-choice .select2-arrow {
274 281 display: none;
275 282 }
276 283 }
277 284
278 285 #header-inner {
279 286 &.title {
280 287 margin: 0;
281 288 }
282 289 &:before,
283 290 &:after {
284 291 content: "";
285 292 clear: both;
286 293 }
287 294 }
288 295
289 296 // Gists
290 297 #files_data {
291 298 clear: both; //for firefox
292 299 padding-top: 10px;
293 300 }
294 301
295 302 #gistid {
296 303 margin-right: @padding;
297 304 }
298 305
299 306 // Global Settings Editor
300 307 .textarea.editor {
301 308 float: left;
302 309 position: relative;
303 310 max-width: @texteditor-width;
304 311
305 312 select {
306 313 position: absolute;
307 314 top:10px;
308 315 right:0;
309 316 }
310 317
311 318 .CodeMirror {
312 319 margin: 0;
313 320 }
314 321
315 322 .help-block {
316 323 margin: 0 0 @padding;
317 324 padding:.5em;
318 325 background-color: @grey6;
319 326 &.pre-formatting {
320 327 white-space: pre;
321 328 }
322 329 }
323 330 }
324 331
325 332 ul.auth_plugins {
326 333 margin: @padding 0 @padding @legend-width;
327 334 padding: 0;
328 335
329 336 li {
330 337 margin-bottom: @padding;
331 338 line-height: 1em;
332 339 list-style-type: none;
333 340
334 341 .auth_buttons .btn {
335 342 margin-right: @padding;
336 343 }
337 344
338 345 }
339 346 }
340 347
341 348
342 349 // My Account PR list
343 350
344 351 #show_closed {
345 352 margin: 0 1em 0 0;
346 353 }
347 354
348 355 #pull_request_list_table {
349 356 .closed {
350 357 background-color: @grey6;
351 358 }
352 359
353 360 .state-creating,
354 361 .state-updating,
355 362 .state-merging
356 363 {
357 364 background-color: @grey6;
358 365 }
359 366
360 367 .td-status {
361 368 padding-left: .5em;
362 369 }
363 370 .log-container .truncate {
364 371 height: 2.75em;
365 372 white-space: pre-line;
366 373 }
367 374 table.rctable .user {
368 375 padding-left: 0;
369 376 }
370 377 table.rctable {
371 378 td.td-description,
372 379 .rc-user {
373 380 min-width: auto;
374 381 }
375 382 }
376 383 }
377 384
378 385 // Pull Requests
379 386
380 387 .pullrequests_section_head {
381 388 display: block;
382 389 clear: both;
383 390 margin: @padding 0;
384 391 font-weight: @text-bold-weight;
385 392 font-family: @text-bold;
386 393 }
387 394
388 395 .pr-commit-flow {
389 396 position: relative;
390 397 font-weight: 600;
391 398
392 399 .tag {
393 400 display: inline-block;
394 401 margin: 0 1em .5em 0;
395 402 }
396 403
397 404 .clone-url {
398 405 display: inline-block;
399 406 margin: 0 0 .5em 0;
400 407 padding: 0;
401 408 line-height: 1.2em;
402 409 }
403 410 }
404 411
405 412 .pr-mergeinfo {
406 413 min-width: 95% !important;
407 414 padding: 0 !important;
408 415 border: 0;
409 416 }
410 417 .pr-mergeinfo-copy {
411 418 padding: 0 0;
412 419 }
413 420
414 421 .pr-pullinfo {
415 422 min-width: 95% !important;
416 423 padding: 0 !important;
417 424 border: 0;
418 425 }
419 426 .pr-pullinfo-copy {
420 427 padding: 0 0;
421 428 }
422 429
423 430 .pr-title-input {
424 431 width: 100%;
425 432 font-size: 18px;
426 433 margin: 0 0 4px 0;
427 434 padding: 0;
428 435 line-height: 1.7em;
429 436 color: @text-color;
430 437 letter-spacing: .02em;
431 438 font-weight: @text-bold-weight;
432 439 font-family: @text-bold;
433 440
434 441 &:hover {
435 442 box-shadow: none;
436 443 }
437 444 }
438 445
439 446 #pr-title {
440 447 input {
441 448 border: 1px transparent;
442 449 color: black;
443 450 opacity: 1;
444 451 background: #fff;
445 452 font-size: 18px;
446 453 }
447 454 }
448 455
449 456 .pr-title-closed-tag {
450 457 font-size: 16px;
451 458 }
452 459
453 460 #pr-desc {
454 461 padding: 10px 0;
455 462
456 463 .markdown-block {
457 464 padding: 0;
458 465 margin-bottom: -30px;
459 466 }
460 467 }
461 468
462 469 #pullrequest_title {
463 470 width: 100%;
464 471 box-sizing: border-box;
465 472 }
466 473
467 474 #pr_open_message {
468 475 border: @border-thickness solid #fff;
469 476 border-radius: @border-radius;
470 477 text-align: left;
471 478 overflow: hidden;
472 479 white-space: pre-line;
473 480 }
474 481
475 482 .pr-details-title {
476 483 height: 16px
477 484 }
478 485
479 486 .pr-details-title-author-pref {
480 487 padding-right: 10px
481 488 }
482 489
483 490 .label-pr-detail {
484 491 display: table-cell;
485 492 width: 120px;
486 493 padding-top: 7.5px;
487 494 padding-bottom: 7.5px;
488 495 padding-right: 7.5px;
489 496 }
490 497
491 498 .source-details ul {
492 499 padding: 10px 16px;
493 500 }
494 501
495 502 .source-details-action {
496 503 color: @grey4;
497 504 font-size: 11px
498 505 }
499 506
500 507 .pr-submit-button {
501 508 float: right;
502 509 margin: 0 0 0 5px;
503 510 }
504 511
505 512 .pr-spacing-container {
506 513 padding: 20px;
507 514 clear: both
508 515 }
509 516
510 517 #pr-description-input {
511 518 margin-bottom: 0;
512 519 }
513 520
514 521 .pr-description-label {
515 522 vertical-align: top;
516 523 }
517 524
518 525 #open_edit_pullrequest {
519 526 padding: 0;
520 527 }
521 528
522 529 #close_edit_pullrequest {
523 530
524 531 }
525 532
526 533 #delete_pullrequest {
527 534 clear: inherit;
528 535
529 536 form {
530 537 display: inline;
531 538 }
532 539
533 540 }
534 541
535 542 .perms_section_head {
536 543 min-width: 625px;
537 544
538 545 h2 {
539 546 margin-bottom: 0;
540 547 }
541 548
542 549 .label-checkbox {
543 550 float: left;
544 551 }
545 552
546 553 &.field {
547 554 margin: @space 0 @padding;
548 555 }
549 556
550 557 &:first-child.field {
551 558 margin-top: 0;
552 559
553 560 .label {
554 561 margin-top: 0;
555 562 padding-top: 0;
556 563 }
557 564
558 565 .radios {
559 566 padding-top: 0;
560 567 }
561 568 }
562 569
563 570 .radios {
564 571 position: relative;
565 572 width: 505px;
566 573 }
567 574 }
568 575
569 576 //--- MODULES ------------------//
570 577
571 578
572 579 // Server Announcement
573 580 #server-announcement {
574 581 width: 95%;
575 582 margin: @padding auto;
576 583 padding: @padding;
577 584 border-width: 2px;
578 585 border-style: solid;
579 586 .border-radius(2px);
580 587 font-weight: @text-bold-weight;
581 588 font-family: @text-bold;
582 589
583 590 &.info { border-color: @alert4; background-color: @alert4-inner; }
584 591 &.warning { border-color: @alert3; background-color: @alert3-inner; }
585 592 &.error { border-color: @alert2; background-color: @alert2-inner; }
586 593 &.success { border-color: @alert1; background-color: @alert1-inner; }
587 594 &.neutral { border-color: @grey3; background-color: @grey6; }
588 595 }
589 596
590 597 // Fixed Sidebar Column
591 598 .sidebar-col-wrapper {
592 599 padding-left: @sidebar-all-width;
593 600
594 601 .sidebar {
595 602 width: @sidebar-width;
596 603 margin-left: -@sidebar-all-width;
597 604 }
598 605 }
599 606
600 607 .sidebar-col-wrapper.scw-small {
601 608 padding-left: @sidebar-small-all-width;
602 609
603 610 .sidebar {
604 611 width: @sidebar-small-width;
605 612 margin-left: -@sidebar-small-all-width;
606 613 }
607 614 }
608 615
609 616
610 617 // FOOTER
611 618 #footer {
612 619 padding: 0;
613 620 text-align: center;
614 621 vertical-align: middle;
615 622 color: @grey2;
616 623 font-size: 11px;
617 624
618 625 p {
619 626 margin: 0;
620 627 padding: 1em;
621 628 line-height: 1em;
622 629 }
623 630
624 631 .server-instance { //server instance
625 632 display: none;
626 633 }
627 634
628 635 .title {
629 636 float: none;
630 637 margin: 0 auto;
631 638 }
632 639 }
633 640
634 641 button.close {
635 642 padding: 0;
636 643 cursor: pointer;
637 644 background: transparent;
638 645 border: 0;
639 646 .box-shadow(none);
640 647 -webkit-appearance: none;
641 648 }
642 649
643 650 .close {
644 651 float: right;
645 652 font-size: 21px;
646 653 font-family: @text-bootstrap;
647 654 line-height: 1em;
648 655 font-weight: bold;
649 656 color: @grey2;
650 657
651 658 &:hover,
652 659 &:focus {
653 660 color: @grey1;
654 661 text-decoration: none;
655 662 cursor: pointer;
656 663 }
657 664 }
658 665
659 666 // GRID
660 667 .sorting,
661 668 .sorting_desc,
662 669 .sorting_asc {
663 670 cursor: pointer;
664 671 }
665 672 .sorting_desc:after {
666 673 content: "\00A0\25B2";
667 674 font-size: .75em;
668 675 }
669 676 .sorting_asc:after {
670 677 content: "\00A0\25BC";
671 678 font-size: .68em;
672 679 }
673 680
674 681
675 682 .user_auth_tokens {
676 683
677 684 &.truncate {
678 685 white-space: nowrap;
679 686 overflow: hidden;
680 687 text-overflow: ellipsis;
681 688 }
682 689
683 690 .fields .field .input {
684 691 margin: 0;
685 692 }
686 693
687 694 input#description {
688 695 width: 100px;
689 696 margin: 0;
690 697 }
691 698
692 699 .drop-menu {
693 700 // TODO: johbo: Remove this, should work out of the box when
694 701 // having multiple inputs inline
695 702 margin: 0 0 0 5px;
696 703 }
697 704 }
698 705 #user_list_table {
699 706 .closed {
700 707 background-color: @grey6;
701 708 }
702 709 }
703 710
704 711
705 712 input, textarea {
706 713 &.disabled {
707 714 opacity: .5;
708 715 }
709 716
710 717 &:hover {
711 718 border-color: @grey3;
712 719 box-shadow: @button-shadow;
713 720 }
714 721
715 722 &:focus {
716 723 border-color: @rcblue;
717 724 box-shadow: @button-shadow;
718 725 }
719 726 }
720 727
721 728 // remove extra padding in firefox
722 729 input::-moz-focus-inner { border:0; padding:0 }
723 730
724 731 .adjacent input {
725 732 margin-bottom: @padding;
726 733 }
727 734
728 735 .permissions_boxes {
729 736 display: block;
730 737 }
731 738
732 739 //FORMS
733 740
734 741 .medium-inline,
735 742 input#description.medium-inline {
736 743 display: inline;
737 744 width: @medium-inline-input-width;
738 745 min-width: 100px;
739 746 }
740 747
741 748 select {
742 749 //reset
743 750 -webkit-appearance: none;
744 751 -moz-appearance: none;
745 752
746 753 display: inline-block;
747 754 height: 28px;
748 755 width: auto;
749 756 margin: 0 @padding @padding 0;
750 757 padding: 0 18px 0 8px;
751 758 line-height:1em;
752 759 font-size: @basefontsize;
753 760 border: @border-thickness solid @grey5;
754 761 border-radius: @border-radius;
755 762 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
756 763 color: @grey4;
757 764 box-shadow: @button-shadow;
758 765
759 766 &:after {
760 767 content: "\00A0\25BE";
761 768 }
762 769
763 770 &:focus, &:hover {
764 771 outline: none;
765 772 border-color: @grey4;
766 773 color: @rcdarkblue;
767 774 }
768 775 }
769 776
770 777 option {
771 778 &:focus {
772 779 outline: none;
773 780 }
774 781 }
775 782
776 783 input,
777 784 textarea {
778 785 padding: @input-padding;
779 786 border: @input-border-thickness solid @border-highlight-color;
780 787 .border-radius (@border-radius);
781 788 font-family: @text-light;
782 789 font-size: @basefontsize;
783 790
784 791 &.input-sm {
785 792 padding: 5px;
786 793 }
787 794
788 795 &#description {
789 796 min-width: @input-description-minwidth;
790 797 min-height: 1em;
791 798 padding: 10px;
792 799 }
793 800 }
794 801
795 802 .field-sm {
796 803 input,
797 804 textarea {
798 805 padding: 5px;
799 806 }
800 807 }
801 808
802 809 textarea {
803 810 display: block;
804 811 clear: both;
805 812 width: 100%;
806 813 min-height: 100px;
807 814 margin-bottom: @padding;
808 815 .box-sizing(border-box);
809 816 overflow: auto;
810 817 }
811 818
812 819 label {
813 820 font-family: @text-light;
814 821 }
815 822
816 823 // GRAVATARS
817 824 // centers gravatar on username to the right
818 825
819 826 .gravatar {
820 827 display: inline;
821 828 min-width: 16px;
822 829 min-height: 16px;
823 830 margin: -5px 0;
824 831 padding: 0;
825 832 line-height: 1em;
826 833 box-sizing: content-box;
827 834 border-radius: 50%;
828 835
829 836 &.gravatar-large {
830 837 margin: -0.5em .25em -0.5em 0;
831 838 }
832 839
833 840 & + .user {
834 841 display: inline;
835 842 margin: 0;
836 843 padding: 0 0 0 .17em;
837 844 line-height: 1em;
838 845 }
839 846
840 847 & + .no-margin {
841 848 margin: 0
842 849 }
843 850
844 851 }
845 852
846 853 .user-inline-data {
847 854 display: inline-block;
848 855 float: left;
849 856 padding-left: .5em;
850 857 line-height: 1.3em;
851 858 }
852 859
853 860 .rc-user { // gravatar + user wrapper
854 861 float: left;
855 862 position: relative;
856 863 min-width: 100px;
857 864 max-width: 200px;
858 865 min-height: (@gravatar-size + @border-thickness * 2); // account for border
859 866 display: block;
860 867 padding: 0 0 0 (@gravatar-size + @basefontsize/4);
861 868
862 869
863 870 .gravatar {
864 871 display: block;
865 872 position: absolute;
866 873 top: 0;
867 874 left: 0;
868 875 min-width: @gravatar-size;
869 876 min-height: @gravatar-size;
870 877 margin: 0;
871 878 }
872 879
873 880 .user {
874 881 display: block;
875 882 max-width: 175px;
876 883 padding-top: 2px;
877 884 overflow: hidden;
878 885 text-overflow: ellipsis;
879 886 }
880 887 }
881 888
882 889 .gist-gravatar,
883 890 .journal_container {
884 891 .gravatar-large {
885 892 margin: 0 .5em -10px 0;
886 893 }
887 894 }
888 895
889 896 .gist-type-fields {
890 897 line-height: 30px;
891 898 height: 30px;
892 899
893 900 .gist-type-fields-wrapper {
894 901 vertical-align: middle;
895 902 display: inline-block;
896 903 line-height: 25px;
897 904 }
898 905 }
899 906
900 907 // ADMIN SETTINGS
901 908
902 909 // Tag Patterns
903 910 .tag_patterns {
904 911 .tag_input {
905 912 margin-bottom: @padding;
906 913 }
907 914 }
908 915
909 916 .locked_input {
910 917 position: relative;
911 918
912 919 input {
913 920 display: inline;
914 921 margin: 3px 5px 0px 0px;
915 922 }
916 923
917 924 br {
918 925 display: none;
919 926 }
920 927
921 928 .error-message {
922 929 float: left;
923 930 width: 100%;
924 931 }
925 932
926 933 .lock_input_button {
927 934 display: inline;
928 935 }
929 936
930 937 .help-block {
931 938 clear: both;
932 939 }
933 940 }
934 941
935 942 // Notifications
936 943
937 944 .notifications_buttons {
938 945 margin: 0 0 @space 0;
939 946 padding: 0;
940 947
941 948 .btn {
942 949 display: inline-block;
943 950 }
944 951 }
945 952
946 953 .notification-list {
947 954
948 955 div {
949 956 vertical-align: middle;
950 957 }
951 958
952 959 .container {
953 960 display: block;
954 961 margin: 0 0 @padding 0;
955 962 }
956 963
957 964 .delete-notifications {
958 965 margin-left: @padding;
959 966 text-align: right;
960 967 cursor: pointer;
961 968 }
962 969
963 970 .read-notifications {
964 971 margin-left: @padding/2;
965 972 text-align: right;
966 973 width: 35px;
967 974 cursor: pointer;
968 975 }
969 976
970 977 .icon-minus-sign {
971 978 color: @alert2;
972 979 }
973 980
974 981 .icon-ok-sign {
975 982 color: @alert1;
976 983 }
977 984 }
978 985
979 986 .user_settings {
980 987 float: left;
981 988 clear: both;
982 989 display: block;
983 990 width: 100%;
984 991
985 992 .gravatar_box {
986 993 margin-bottom: @padding;
987 994
988 995 &:after {
989 996 content: " ";
990 997 clear: both;
991 998 width: 100%;
992 999 }
993 1000 }
994 1001
995 1002 .fields .field {
996 1003 clear: both;
997 1004 }
998 1005 }
999 1006
1000 1007 .advanced_settings {
1001 1008 margin-bottom: @space;
1002 1009
1003 1010 .help-block {
1004 1011 margin-left: 0;
1005 1012 }
1006 1013
1007 1014 button + .help-block {
1008 1015 margin-top: @padding;
1009 1016 }
1010 1017 }
1011 1018
1012 1019 // admin settings radio buttons and labels
1013 1020 .label-2 {
1014 1021 float: left;
1015 1022 width: @label2-width;
1016 1023
1017 1024 label {
1018 1025 color: @grey1;
1019 1026 }
1020 1027 }
1021 1028 .checkboxes {
1022 1029 float: left;
1023 1030 width: @checkboxes-width;
1024 1031 margin-bottom: @padding;
1025 1032
1026 1033 .checkbox {
1027 1034 width: 100%;
1028 1035
1029 1036 label {
1030 1037 margin: 0;
1031 1038 padding: 0;
1032 1039 }
1033 1040 }
1034 1041
1035 1042 .checkbox + .checkbox {
1036 1043 display: inline-block;
1037 1044 }
1038 1045
1039 1046 label {
1040 1047 margin-right: 1em;
1041 1048 }
1042 1049 }
1043 1050
1044 1051 // CHANGELOG
1045 1052 .container_header {
1046 1053 float: left;
1047 1054 display: block;
1048 1055 width: 100%;
1049 1056 margin: @padding 0 @padding;
1050 1057
1051 1058 #filter_changelog {
1052 1059 float: left;
1053 1060 margin-right: @padding;
1054 1061 }
1055 1062
1056 1063 .breadcrumbs_light {
1057 1064 display: inline-block;
1058 1065 }
1059 1066 }
1060 1067
1061 1068 .info_box {
1062 1069 float: right;
1063 1070 }
1064 1071
1065 1072
1066 1073
1067 1074 #graph_content{
1068 1075
1069 1076 // adjust for table headers so that graph renders properly
1070 1077 // #graph_nodes padding - table cell padding
1071 1078 padding-top: (@space - (@basefontsize * 2.4));
1072 1079
1073 1080 &.graph_full_width {
1074 1081 width: 100%;
1075 1082 max-width: 100%;
1076 1083 }
1077 1084 }
1078 1085
1079 1086 #graph {
1080 1087
1081 1088 .pagination-left {
1082 1089 float: left;
1083 1090 clear: both;
1084 1091 }
1085 1092
1086 1093 .log-container {
1087 1094 max-width: 345px;
1088 1095
1089 1096 .message{
1090 1097 max-width: 340px;
1091 1098 }
1092 1099 }
1093 1100
1094 1101 .graph-col-wrapper {
1095 1102
1096 1103 #graph_nodes {
1097 1104 width: 100px;
1098 1105 position: absolute;
1099 1106 left: 70px;
1100 1107 z-index: -1;
1101 1108 }
1102 1109 }
1103 1110
1104 1111 .load-more-commits {
1105 1112 text-align: center;
1106 1113 }
1107 1114 .load-more-commits:hover {
1108 1115 background-color: @grey7;
1109 1116 }
1110 1117 .load-more-commits {
1111 1118 a {
1112 1119 display: block;
1113 1120 }
1114 1121 }
1115 1122 }
1116 1123
1117 1124 .obsolete-toggle {
1118 1125 line-height: 30px;
1119 1126 margin-left: -15px;
1120 1127 }
1121 1128
1122 1129 #rev_range_container, #rev_range_clear, #rev_range_more {
1123 1130 margin-top: -5px;
1124 1131 margin-bottom: -5px;
1125 1132 }
1126 1133
1127 1134 #filter_changelog {
1128 1135 float: left;
1129 1136 }
1130 1137
1131 1138
1132 1139 //--- THEME ------------------//
1133 1140
1134 1141 #logo {
1135 1142 float: left;
1136 1143 margin: 9px 0 0 0;
1137 1144
1138 1145 .header {
1139 1146 background-color: transparent;
1140 1147 }
1141 1148
1142 1149 a {
1143 1150 display: inline-block;
1144 1151 }
1145 1152
1146 1153 img {
1147 1154 height:30px;
1148 1155 }
1149 1156 }
1150 1157
1151 1158 .logo-wrapper {
1152 1159 float:left;
1153 1160 }
1154 1161
1155 1162 .branding {
1156 1163 float: left;
1157 1164 padding: 9px 2px;
1158 1165 line-height: 1em;
1159 1166 font-size: @navigation-fontsize;
1160 1167
1161 1168 a {
1162 1169 color: @grey5
1163 1170 }
1164 1171 @media screen and (max-width: 1200px) {
1165 1172 display: none;
1166 1173 }
1167 1174 }
1168 1175
1169 1176 img {
1170 1177 border: none;
1171 1178 outline: none;
1172 1179 }
1173 1180 user-profile-header
1174 1181 label {
1175 1182
1176 1183 input[type="checkbox"] {
1177 1184 margin-right: 1em;
1178 1185 }
1179 1186 input[type="radio"] {
1180 1187 margin-right: 1em;
1181 1188 }
1182 1189 }
1183 1190
1184 1191 .review-status {
1185 1192 &.under_review {
1186 1193 color: @alert3;
1187 1194 }
1188 1195 &.approved {
1189 1196 color: @alert1;
1190 1197 }
1191 1198 &.rejected,
1192 1199 &.forced_closed{
1193 1200 color: @alert2;
1194 1201 }
1195 1202 &.not_reviewed {
1196 1203 color: @grey5;
1197 1204 }
1198 1205 }
1199 1206
1200 1207 .review-status-under_review {
1201 1208 color: @alert3;
1202 1209 }
1203 1210 .status-tag-under_review {
1204 1211 border-color: @alert3;
1205 1212 }
1206 1213
1207 1214 .review-status-approved {
1208 1215 color: @alert1;
1209 1216 }
1210 1217 .status-tag-approved {
1211 1218 border-color: @alert1;
1212 1219 }
1213 1220
1214 1221 .review-status-rejected,
1215 1222 .review-status-forced_closed {
1216 1223 color: @alert2;
1217 1224 }
1218 1225 .status-tag-rejected,
1219 1226 .status-tag-forced_closed {
1220 1227 border-color: @alert2;
1221 1228 }
1222 1229
1223 1230 .review-status-not_reviewed {
1224 1231 color: @grey5;
1225 1232 }
1226 1233 .status-tag-not_reviewed {
1227 1234 border-color: @grey5;
1228 1235 }
1229 1236
1230 1237 .test_pattern_preview {
1231 1238 margin: @space 0;
1232 1239
1233 1240 p {
1234 1241 margin-bottom: 0;
1235 1242 border-bottom: @border-thickness solid @border-default-color;
1236 1243 color: @grey3;
1237 1244 }
1238 1245
1239 1246 .btn {
1240 1247 margin-bottom: @padding;
1241 1248 }
1242 1249 }
1243 1250 #test_pattern_result {
1244 1251 display: none;
1245 1252 &:extend(pre);
1246 1253 padding: .9em;
1247 1254 color: @grey3;
1248 1255 background-color: @grey7;
1249 1256 border-right: @border-thickness solid @border-default-color;
1250 1257 border-bottom: @border-thickness solid @border-default-color;
1251 1258 border-left: @border-thickness solid @border-default-color;
1252 1259 }
1253 1260
1254 1261 #repo_vcs_settings {
1255 1262 #inherit_overlay_vcs_default {
1256 1263 display: none;
1257 1264 }
1258 1265 #inherit_overlay_vcs_custom {
1259 1266 display: custom;
1260 1267 }
1261 1268 &.inherited {
1262 1269 #inherit_overlay_vcs_default {
1263 1270 display: block;
1264 1271 }
1265 1272 #inherit_overlay_vcs_custom {
1266 1273 display: none;
1267 1274 }
1268 1275 }
1269 1276 }
1270 1277
1271 1278 .issue-tracker-link {
1272 1279 color: @rcblue;
1273 1280 }
1274 1281
1275 1282 // Issue Tracker Table Show/Hide
1276 1283 #repo_issue_tracker {
1277 1284 #inherit_overlay {
1278 1285 display: none;
1279 1286 }
1280 1287 #custom_overlay {
1281 1288 display: custom;
1282 1289 }
1283 1290 &.inherited {
1284 1291 #inherit_overlay {
1285 1292 display: block;
1286 1293 }
1287 1294 #custom_overlay {
1288 1295 display: none;
1289 1296 }
1290 1297 }
1291 1298 }
1292 1299 table.issuetracker {
1293 1300 &.readonly {
1294 1301 tr, td {
1295 1302 color: @grey3;
1296 1303 }
1297 1304 }
1298 1305 .edit {
1299 1306 display: none;
1300 1307 }
1301 1308 .editopen {
1302 1309 .edit {
1303 1310 display: inline;
1304 1311 }
1305 1312 .entry {
1306 1313 display: none;
1307 1314 }
1308 1315 }
1309 1316 tr td.td-action {
1310 1317 min-width: 117px;
1311 1318 }
1312 1319 td input {
1313 1320 max-width: none;
1314 1321 min-width: 30px;
1315 1322 width: 80%;
1316 1323 }
1317 1324 .issuetracker_pref input {
1318 1325 width: 40%;
1319 1326 }
1320 1327 input.edit_issuetracker_update {
1321 1328 margin-right: 0;
1322 1329 width: auto;
1323 1330 }
1324 1331 }
1325 1332
1326 1333 table.integrations {
1327 1334 .td-icon {
1328 1335 width: 20px;
1329 1336 .integration-icon {
1330 1337 height: 20px;
1331 1338 width: 20px;
1332 1339 }
1333 1340 }
1334 1341 }
1335 1342
1336 1343 .integrations {
1337 1344 a.integration-box {
1338 1345 color: @text-color;
1339 1346 &:hover {
1340 1347 .panel {
1341 1348 background: #fbfbfb;
1342 1349 }
1343 1350 }
1344 1351 .integration-icon {
1345 1352 width: 30px;
1346 1353 height: 30px;
1347 1354 margin-right: 20px;
1348 1355 float: left;
1349 1356 }
1350 1357
1351 1358 .panel-body {
1352 1359 padding: 10px;
1353 1360 }
1354 1361 .panel {
1355 1362 margin-bottom: 10px;
1356 1363 }
1357 1364 h2 {
1358 1365 display: inline-block;
1359 1366 margin: 0;
1360 1367 min-width: 140px;
1361 1368 }
1362 1369 }
1363 1370 a.integration-box.dummy-integration {
1364 1371 color: @grey4
1365 1372 }
1366 1373 }
1367 1374
1368 1375 //Permissions Settings
1369 1376 #add_perm {
1370 1377 margin: 0 0 @padding;
1371 1378 cursor: pointer;
1372 1379 }
1373 1380
1374 1381 .perm_ac {
1375 1382 input {
1376 1383 width: 95%;
1377 1384 }
1378 1385 }
1379 1386
1380 1387 .autocomplete-suggestions {
1381 1388 width: auto !important; // overrides autocomplete.js
1382 1389 min-width: 278px;
1383 1390 margin: 0;
1384 1391 border: @border-thickness solid @grey5;
1385 1392 border-radius: @border-radius;
1386 1393 color: @grey2;
1387 1394 background-color: white;
1388 1395 }
1389 1396
1390 1397 .autocomplete-qfilter-suggestions {
1391 1398 width: auto !important; // overrides autocomplete.js
1392 1399 max-height: 100% !important;
1393 1400 min-width: 376px;
1394 1401 margin: 0;
1395 1402 border: @border-thickness solid @grey5;
1396 1403 color: @grey2;
1397 1404 background-color: white;
1398 1405 }
1399 1406
1400 1407 .autocomplete-selected {
1401 1408 background: #F0F0F0;
1402 1409 }
1403 1410
1404 1411 .ac-container-wrap {
1405 1412 margin: 0;
1406 1413 padding: 8px;
1407 1414 border-bottom: @border-thickness solid @grey5;
1408 1415 list-style-type: none;
1409 1416 cursor: pointer;
1410 1417
1411 1418 &:hover {
1412 1419 background-color: @grey7;
1413 1420 }
1414 1421
1415 1422 img {
1416 1423 height: @gravatar-size;
1417 1424 width: @gravatar-size;
1418 1425 margin-right: 1em;
1419 1426 }
1420 1427
1421 1428 strong {
1422 1429 font-weight: normal;
1423 1430 }
1424 1431 }
1425 1432
1426 1433 // Settings Dropdown
1427 1434 .user-menu .container {
1428 1435 padding: 0 4px;
1429 1436 margin: 0;
1430 1437 }
1431 1438
1432 1439 .user-menu .gravatar {
1433 1440 cursor: pointer;
1434 1441 }
1435 1442
1436 1443 .codeblock {
1437 1444 margin-bottom: @padding;
1438 1445 clear: both;
1439 1446
1440 1447 .stats {
1441 1448 overflow: hidden;
1442 1449 }
1443 1450
1444 1451 .message{
1445 1452 textarea{
1446 1453 margin: 0;
1447 1454 }
1448 1455 }
1449 1456
1450 1457 .code-header {
1451 1458 .stats {
1452 1459 line-height: 2em;
1453 1460
1454 1461 .revision_id {
1455 1462 margin-left: 0;
1456 1463 }
1457 1464 .buttons {
1458 1465 padding-right: 0;
1459 1466 }
1460 1467 }
1461 1468
1462 1469 .item{
1463 1470 margin-right: 0.5em;
1464 1471 }
1465 1472 }
1466 1473
1467 1474 #editor_container {
1468 1475 position: relative;
1469 1476 margin: @padding 10px;
1470 1477 }
1471 1478 }
1472 1479
1473 1480 #file_history_container {
1474 1481 display: none;
1475 1482 }
1476 1483
1477 1484 .file-history-inner {
1478 1485 margin-bottom: 10px;
1479 1486 }
1480 1487
1481 1488 // Pull Requests
1482 1489 .summary-details {
1483 1490 width: 72%;
1484 1491 }
1485 1492 .pr-summary {
1486 1493 border-bottom: @border-thickness solid @grey5;
1487 1494 margin-bottom: @space;
1488 1495 }
1489 1496
1490 1497 .reviewers-title {
1491 1498 width: 25%;
1492 1499 min-width: 200px;
1493 1500
1494 1501 &.first-panel {
1495 1502 margin-top: 34px;
1496 1503 }
1497 1504 }
1498 1505
1499 1506 .reviewers {
1500 1507 width: 25%;
1501 1508 min-width: 200px;
1502 1509 }
1503 1510 .reviewers ul li {
1504 1511 position: relative;
1505 1512 width: 100%;
1506 1513 padding-bottom: 8px;
1507 1514 list-style-type: none;
1508 1515 }
1509 1516
1510 1517 .reviewer_entry {
1511 1518 min-height: 55px;
1512 1519 }
1513 1520
1514 1521 .reviewers_member {
1515 1522 width: 100%;
1516 1523 overflow: auto;
1517 1524 }
1518 1525 .reviewer_reason {
1519 1526 padding-left: 20px;
1520 1527 line-height: 1.5em;
1521 1528 }
1522 1529 .reviewer_status {
1523 1530 display: inline-block;
1524 1531 width: 25px;
1525 1532 min-width: 25px;
1526 1533 height: 1.2em;
1527 1534 line-height: 1em;
1528 1535 }
1529 1536
1530 1537 .reviewer_name {
1531 1538 display: inline-block;
1532 1539 max-width: 83%;
1533 1540 padding-right: 20px;
1534 1541 vertical-align: middle;
1535 1542 line-height: 1;
1536 1543
1537 1544 .rc-user {
1538 1545 min-width: 0;
1539 1546 margin: -2px 1em 0 0;
1540 1547 }
1541 1548
1542 1549 .reviewer {
1543 1550 float: left;
1544 1551 }
1545 1552 }
1546 1553
1547 1554 .reviewer_member_mandatory {
1548 1555 position: absolute;
1549 1556 left: 15px;
1550 1557 top: 8px;
1551 1558 width: 16px;
1552 1559 font-size: 11px;
1553 1560 margin: 0;
1554 1561 padding: 0;
1555 1562 color: black;
1556 1563 }
1557 1564
1558 1565 .reviewer_member_mandatory_remove,
1559 1566 .reviewer_member_remove {
1560 1567 position: absolute;
1561 1568 right: 0;
1562 1569 top: 0;
1563 1570 width: 16px;
1564 1571 margin-bottom: 10px;
1565 1572 padding: 0;
1566 1573 color: black;
1567 1574 }
1568 1575
1569 1576 .reviewer_member_mandatory_remove {
1570 1577 color: @grey4;
1571 1578 }
1572 1579
1573 1580 .reviewer_member_status {
1574 1581 margin-top: 5px;
1575 1582 }
1576 1583 .pr-summary #summary{
1577 1584 width: 100%;
1578 1585 }
1579 1586 .pr-summary .action_button:hover {
1580 1587 border: 0;
1581 1588 cursor: pointer;
1582 1589 }
1583 1590 .pr-details-title {
1584 1591 padding-bottom: 8px;
1585 1592 border-bottom: @border-thickness solid @grey5;
1586 1593
1587 1594 .action_button.disabled {
1588 1595 color: @grey4;
1589 1596 cursor: inherit;
1590 1597 }
1591 1598 .action_button {
1592 1599 color: @rcblue;
1593 1600 }
1594 1601 }
1595 1602 .pr-details-content {
1596 1603 margin-top: @textmargin - 5;
1597 1604 margin-bottom: @textmargin - 5;
1598 1605 }
1599 1606
1600 1607 .pr-reviewer-rules {
1601 1608 padding: 10px 0px 20px 0px;
1602 1609 }
1603 1610
1604 1611 .todo-resolved {
1605 1612 text-decoration: line-through;
1606 1613 }
1607 1614
1608 1615 .todo-table {
1609 1616 width: 100%;
1610 1617
1611 1618 td {
1612 1619 padding: 5px 0px;
1613 1620 }
1614 1621
1615 1622 .td-todo-number {
1616 1623 text-align: left;
1617 1624 white-space: nowrap;
1618 1625 width: 15%;
1619 1626 }
1620 1627
1621 1628 .td-todo-gravatar {
1622 1629 width: 5%;
1623 1630
1624 1631 img {
1625 1632 margin: -3px 0;
1626 1633 }
1627 1634 }
1628 1635
1629 1636 }
1630 1637
1631 1638 .todo-comment-text-wrapper {
1632 1639 display: inline-grid;
1633 1640 }
1634 1641
1635 1642 .todo-comment-text {
1636 1643 margin-left: 5px;
1637 1644 white-space: nowrap;
1638 1645 overflow: hidden;
1639 1646 text-overflow: ellipsis;
1640 1647 }
1641 1648
1642 1649 .group_members {
1643 1650 margin-top: 0;
1644 1651 padding: 0;
1645 1652 list-style: outside none none;
1646 1653
1647 1654 img {
1648 1655 height: @gravatar-size;
1649 1656 width: @gravatar-size;
1650 1657 margin-right: .5em;
1651 1658 margin-left: 3px;
1652 1659 }
1653 1660
1654 1661 .to-delete {
1655 1662 .user {
1656 1663 text-decoration: line-through;
1657 1664 }
1658 1665 }
1659 1666 }
1660 1667
1661 1668 .compare_view_commits_title {
1662 1669 .disabled {
1663 1670 cursor: inherit;
1664 1671 &:hover{
1665 1672 background-color: inherit;
1666 1673 color: inherit;
1667 1674 }
1668 1675 }
1669 1676 }
1670 1677
1671 1678 .subtitle-compare {
1672 1679 margin: -15px 0px 0px 0px;
1673 1680 }
1674 1681
1675 1682 // new entry in group_members
1676 1683 .td-author-new-entry {
1677 1684 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1678 1685 }
1679 1686
1680 1687 .usergroup_member_remove {
1681 1688 width: 16px;
1682 1689 margin-bottom: 10px;
1683 1690 padding: 0;
1684 1691 color: black !important;
1685 1692 cursor: pointer;
1686 1693 }
1687 1694
1688 1695 .reviewer_ac .ac-input {
1689 1696 width: 92%;
1690 1697 margin-bottom: 1em;
1691 1698 }
1692 1699
1693 1700 .compare_view_commits tr{
1694 1701 height: 20px;
1695 1702 }
1696 1703 .compare_view_commits td {
1697 1704 vertical-align: top;
1698 1705 padding-top: 10px;
1699 1706 }
1700 1707 .compare_view_commits .author {
1701 1708 margin-left: 5px;
1702 1709 }
1703 1710
1704 1711 .compare_view_commits {
1705 1712 .color-a {
1706 1713 color: @alert1;
1707 1714 }
1708 1715
1709 1716 .color-c {
1710 1717 color: @color3;
1711 1718 }
1712 1719
1713 1720 .color-r {
1714 1721 color: @color5;
1715 1722 }
1716 1723
1717 1724 .color-a-bg {
1718 1725 background-color: @alert1;
1719 1726 }
1720 1727
1721 1728 .color-c-bg {
1722 1729 background-color: @alert3;
1723 1730 }
1724 1731
1725 1732 .color-r-bg {
1726 1733 background-color: @alert2;
1727 1734 }
1728 1735
1729 1736 .color-a-border {
1730 1737 border: 1px solid @alert1;
1731 1738 }
1732 1739
1733 1740 .color-c-border {
1734 1741 border: 1px solid @alert3;
1735 1742 }
1736 1743
1737 1744 .color-r-border {
1738 1745 border: 1px solid @alert2;
1739 1746 }
1740 1747
1741 1748 .commit-change-indicator {
1742 1749 width: 15px;
1743 1750 height: 15px;
1744 1751 position: relative;
1745 1752 left: 15px;
1746 1753 }
1747 1754
1748 1755 .commit-change-content {
1749 1756 text-align: center;
1750 1757 vertical-align: middle;
1751 1758 line-height: 15px;
1752 1759 }
1753 1760 }
1754 1761
1755 1762 .compare_view_filepath {
1756 1763 color: @grey1;
1757 1764 }
1758 1765
1759 1766 .show_more {
1760 1767 display: inline-block;
1761 1768 width: 0;
1762 1769 height: 0;
1763 1770 vertical-align: middle;
1764 1771 content: "";
1765 1772 border: 4px solid;
1766 1773 border-right-color: transparent;
1767 1774 border-bottom-color: transparent;
1768 1775 border-left-color: transparent;
1769 1776 font-size: 0;
1770 1777 }
1771 1778
1772 1779 .journal_more .show_more {
1773 1780 display: inline;
1774 1781
1775 1782 &:after {
1776 1783 content: none;
1777 1784 }
1778 1785 }
1779 1786
1780 1787 .compare_view_commits .collapse_commit:after {
1781 1788 cursor: pointer;
1782 1789 content: "\00A0\25B4";
1783 1790 margin-left: -3px;
1784 1791 font-size: 17px;
1785 1792 color: @grey4;
1786 1793 }
1787 1794
1788 1795 .diff_links {
1789 1796 margin-left: 8px;
1790 1797 }
1791 1798
1792 1799 #pull_request_overview {
1793 1800 div.ancestor {
1794 1801 margin: -33px 0;
1795 1802 }
1796 1803 }
1797 1804
1798 1805 div.ancestor {
1799 1806
1800 1807 }
1801 1808
1802 1809 .cs_icon_td input[type="checkbox"] {
1803 1810 display: none;
1804 1811 }
1805 1812
1806 1813 .cs_icon_td .expand_file_icon:after {
1807 1814 cursor: pointer;
1808 1815 content: "\00A0\25B6";
1809 1816 font-size: 12px;
1810 1817 color: @grey4;
1811 1818 }
1812 1819
1813 1820 .cs_icon_td .collapse_file_icon:after {
1814 1821 cursor: pointer;
1815 1822 content: "\00A0\25BC";
1816 1823 font-size: 12px;
1817 1824 color: @grey4;
1818 1825 }
1819 1826
1820 1827 /*new binary
1821 1828 NEW_FILENODE = 1
1822 1829 DEL_FILENODE = 2
1823 1830 MOD_FILENODE = 3
1824 1831 RENAMED_FILENODE = 4
1825 1832 COPIED_FILENODE = 5
1826 1833 CHMOD_FILENODE = 6
1827 1834 BIN_FILENODE = 7
1828 1835 */
1829 1836 .cs_files_expand {
1830 1837 font-size: @basefontsize + 5px;
1831 1838 line-height: 1.8em;
1832 1839 float: right;
1833 1840 }
1834 1841
1835 1842 .cs_files_expand span{
1836 1843 color: @rcblue;
1837 1844 cursor: pointer;
1838 1845 }
1839 1846 .cs_files {
1840 1847 clear: both;
1841 1848 padding-bottom: @padding;
1842 1849
1843 1850 .cur_cs {
1844 1851 margin: 10px 2px;
1845 1852 font-weight: bold;
1846 1853 }
1847 1854
1848 1855 .node {
1849 1856 float: left;
1850 1857 }
1851 1858
1852 1859 .changes {
1853 1860 float: right;
1854 1861 color: white;
1855 1862 font-size: @basefontsize - 4px;
1856 1863 margin-top: 4px;
1857 1864 opacity: 0.6;
1858 1865 filter: Alpha(opacity=60); /* IE8 and earlier */
1859 1866
1860 1867 .added {
1861 1868 background-color: @alert1;
1862 1869 float: left;
1863 1870 text-align: center;
1864 1871 }
1865 1872
1866 1873 .deleted {
1867 1874 background-color: @alert2;
1868 1875 float: left;
1869 1876 text-align: center;
1870 1877 }
1871 1878
1872 1879 .bin {
1873 1880 background-color: @alert1;
1874 1881 text-align: center;
1875 1882 }
1876 1883
1877 1884 /*new binary*/
1878 1885 .bin.bin1 {
1879 1886 background-color: @alert1;
1880 1887 text-align: center;
1881 1888 }
1882 1889
1883 1890 /*deleted binary*/
1884 1891 .bin.bin2 {
1885 1892 background-color: @alert2;
1886 1893 text-align: center;
1887 1894 }
1888 1895
1889 1896 /*mod binary*/
1890 1897 .bin.bin3 {
1891 1898 background-color: @grey2;
1892 1899 text-align: center;
1893 1900 }
1894 1901
1895 1902 /*rename file*/
1896 1903 .bin.bin4 {
1897 1904 background-color: @alert4;
1898 1905 text-align: center;
1899 1906 }
1900 1907
1901 1908 /*copied file*/
1902 1909 .bin.bin5 {
1903 1910 background-color: @alert4;
1904 1911 text-align: center;
1905 1912 }
1906 1913
1907 1914 /*chmod file*/
1908 1915 .bin.bin6 {
1909 1916 background-color: @grey2;
1910 1917 text-align: center;
1911 1918 }
1912 1919 }
1913 1920 }
1914 1921
1915 1922 .cs_files .cs_added, .cs_files .cs_A,
1916 1923 .cs_files .cs_added, .cs_files .cs_M,
1917 1924 .cs_files .cs_added, .cs_files .cs_D {
1918 1925 height: 16px;
1919 1926 padding-right: 10px;
1920 1927 margin-top: 7px;
1921 1928 text-align: left;
1922 1929 }
1923 1930
1924 1931 .cs_icon_td {
1925 1932 min-width: 16px;
1926 1933 width: 16px;
1927 1934 }
1928 1935
1929 1936 .pull-request-merge {
1930 1937 border: 1px solid @grey5;
1931 1938 padding: 10px 0px 20px;
1932 1939 margin-top: 10px;
1933 1940 margin-bottom: 20px;
1934 1941 }
1935 1942
1936 1943 .pull-request-merge-refresh {
1937 1944 margin: 2px 7px;
1938 1945 a {
1939 1946 color: @grey3;
1940 1947 }
1941 1948 }
1942 1949
1943 1950 .pull-request-merge ul {
1944 1951 padding: 0px 0px;
1945 1952 }
1946 1953
1947 1954 .pull-request-merge li {
1948 1955 list-style-type: none;
1949 1956 }
1950 1957
1951 1958 .pull-request-merge .pull-request-wrap {
1952 1959 height: auto;
1953 1960 padding: 0px 0px;
1954 1961 text-align: right;
1955 1962 }
1956 1963
1957 1964 .pull-request-merge span {
1958 1965 margin-right: 5px;
1959 1966 }
1960 1967
1961 1968 .pull-request-merge-actions {
1962 1969 min-height: 30px;
1963 1970 padding: 0px 0px;
1964 1971 }
1965 1972
1966 1973 .pull-request-merge-info {
1967 1974 padding: 0px 5px 5px 0px;
1968 1975 }
1969 1976
1970 1977 .merge-status {
1971 1978 margin-right: 5px;
1972 1979 }
1973 1980
1974 1981 .merge-message {
1975 1982 font-size: 1.2em
1976 1983 }
1977 1984
1978 1985 .merge-message.success i,
1979 1986 .merge-icon.success i {
1980 1987 color:@alert1;
1981 1988 }
1982 1989
1983 1990 .merge-message.warning i,
1984 1991 .merge-icon.warning i {
1985 1992 color: @alert3;
1986 1993 }
1987 1994
1988 1995 .merge-message.error i,
1989 1996 .merge-icon.error i {
1990 1997 color:@alert2;
1991 1998 }
1992 1999
1993 2000 .pr-versions {
1994 2001 font-size: 1.1em;
1995 2002 padding: 7.5px;
1996 2003
1997 2004 table {
1998 2005
1999 2006 }
2000 2007
2001 2008 td {
2002 2009 line-height: 15px;
2003 2010 }
2004 2011
2005 2012 .compare-radio-button {
2006 2013 position: relative;
2007 2014 top: -3px;
2008 2015 }
2009 2016 }
2010 2017
2011 2018
2012 2019 #close_pull_request {
2013 2020 margin-right: 0px;
2014 2021 }
2015 2022
2016 2023 .empty_data {
2017 2024 color: @grey4;
2018 2025 }
2019 2026
2020 2027 #changeset_compare_view_content {
2021 2028 clear: both;
2022 2029 width: 100%;
2023 2030 box-sizing: border-box;
2024 2031 .border-radius(@border-radius);
2025 2032
2026 2033 .help-block {
2027 2034 margin: @padding 0;
2028 2035 color: @text-color;
2029 2036 &.pre-formatting {
2030 2037 white-space: pre;
2031 2038 }
2032 2039 }
2033 2040
2034 2041 .empty_data {
2035 2042 margin: @padding 0;
2036 2043 }
2037 2044
2038 2045 .alert {
2039 2046 margin-bottom: @space;
2040 2047 }
2041 2048 }
2042 2049
2043 2050 .table_disp {
2044 2051 .status {
2045 2052 width: auto;
2046 2053 }
2047 2054 }
2048 2055
2049 2056
2050 2057 .creation_in_progress {
2051 2058 color: @grey4
2052 2059 }
2053 2060
2054 2061 .status_box_menu {
2055 2062 margin: 0;
2056 2063 }
2057 2064
2058 2065 .notification-table{
2059 2066 margin-bottom: @space;
2060 2067 display: table;
2061 2068 width: 100%;
2062 2069
2063 2070 .container{
2064 2071 display: table-row;
2065 2072
2066 2073 .notification-header{
2067 2074 border-bottom: @border-thickness solid @border-default-color;
2068 2075 }
2069 2076
2070 2077 .notification-subject{
2071 2078 display: table-cell;
2072 2079 }
2073 2080 }
2074 2081 }
2075 2082
2076 2083 // Notifications
2077 2084 .notification-header{
2078 2085 display: table;
2079 2086 width: 100%;
2080 2087 padding: floor(@basefontsize/2) 0;
2081 2088 line-height: 1em;
2082 2089
2083 2090 .desc, .delete-notifications, .read-notifications{
2084 2091 display: table-cell;
2085 2092 text-align: left;
2086 2093 }
2087 2094
2088 2095 .delete-notifications, .read-notifications{
2089 2096 width: 35px;
2090 2097 min-width: 35px; //fixes when only one button is displayed
2091 2098 }
2092 2099 }
2093 2100
2094 2101 .notification-body {
2095 2102 .markdown-block,
2096 2103 .rst-block {
2097 2104 padding: @padding 0;
2098 2105 }
2099 2106
2100 2107 .notification-subject {
2101 2108 padding: @textmargin 0;
2102 2109 border-bottom: @border-thickness solid @border-default-color;
2103 2110 }
2104 2111 }
2105 2112
2106 2113 .notice-messages {
2107 2114 .markdown-block,
2108 2115 .rst-block {
2109 2116 padding: 0;
2110 2117 }
2111 2118 }
2112 2119
2113 2120 .notifications_buttons{
2114 2121 float: right;
2115 2122 }
2116 2123
2117 2124 #notification-status{
2118 2125 display: inline;
2119 2126 }
2120 2127
2121 2128 // Repositories
2122 2129
2123 2130 #summary.fields{
2124 2131 display: table;
2125 2132
2126 2133 .field{
2127 2134 display: table-row;
2128 2135
2129 2136 .label-summary{
2130 2137 display: table-cell;
2131 2138 min-width: @label-summary-minwidth;
2132 2139 padding-top: @padding/2;
2133 2140 padding-bottom: @padding/2;
2134 2141 padding-right: @padding/2;
2135 2142 }
2136 2143
2137 2144 .input{
2138 2145 display: table-cell;
2139 2146 padding: @padding/2;
2140 2147
2141 2148 input{
2142 2149 min-width: 29em;
2143 2150 padding: @padding/4;
2144 2151 }
2145 2152 }
2146 2153 .statistics, .downloads{
2147 2154 .disabled{
2148 2155 color: @grey4;
2149 2156 }
2150 2157 }
2151 2158 }
2152 2159 }
2153 2160
2154 2161 #summary{
2155 2162 width: 70%;
2156 2163 }
2157 2164
2158 2165
2159 2166 // Journal
2160 2167 .journal.title {
2161 2168 h5 {
2162 2169 float: left;
2163 2170 margin: 0;
2164 2171 width: 70%;
2165 2172 }
2166 2173
2167 2174 ul {
2168 2175 float: right;
2169 2176 display: inline-block;
2170 2177 margin: 0;
2171 2178 width: 30%;
2172 2179 text-align: right;
2173 2180
2174 2181 li {
2175 2182 display: inline;
2176 2183 font-size: @journal-fontsize;
2177 2184 line-height: 1em;
2178 2185
2179 2186 list-style-type: none;
2180 2187 }
2181 2188 }
2182 2189 }
2183 2190
2184 2191 .filterexample {
2185 2192 position: absolute;
2186 2193 top: 95px;
2187 2194 left: @contentpadding;
2188 2195 color: @rcblue;
2189 2196 font-size: 11px;
2190 2197 font-family: @text-regular;
2191 2198 cursor: help;
2192 2199
2193 2200 &:hover {
2194 2201 color: @rcdarkblue;
2195 2202 }
2196 2203
2197 2204 @media (max-width:768px) {
2198 2205 position: relative;
2199 2206 top: auto;
2200 2207 left: auto;
2201 2208 display: block;
2202 2209 }
2203 2210 }
2204 2211
2205 2212
2206 2213 #journal{
2207 2214 margin-bottom: @space;
2208 2215
2209 2216 .journal_day{
2210 2217 margin-bottom: @textmargin/2;
2211 2218 padding-bottom: @textmargin/2;
2212 2219 font-size: @journal-fontsize;
2213 2220 border-bottom: @border-thickness solid @border-default-color;
2214 2221 }
2215 2222
2216 2223 .journal_container{
2217 2224 margin-bottom: @space;
2218 2225
2219 2226 .journal_user{
2220 2227 display: inline-block;
2221 2228 }
2222 2229 .journal_action_container{
2223 2230 display: block;
2224 2231 margin-top: @textmargin;
2225 2232
2226 2233 div{
2227 2234 display: inline;
2228 2235 }
2229 2236
2230 2237 div.journal_action_params{
2231 2238 display: block;
2232 2239 }
2233 2240
2234 2241 div.journal_repo:after{
2235 2242 content: "\A";
2236 2243 white-space: pre;
2237 2244 }
2238 2245
2239 2246 div.date{
2240 2247 display: block;
2241 2248 margin-bottom: @textmargin;
2242 2249 }
2243 2250 }
2244 2251 }
2245 2252 }
2246 2253
2247 2254 // Files
2248 2255 .edit-file-title {
2249 2256 font-size: 16px;
2250 2257
2251 2258 .title-heading {
2252 2259 padding: 2px;
2253 2260 }
2254 2261 }
2255 2262
2256 2263 .edit-file-fieldset {
2257 2264 margin: @sidebarpadding 0;
2258 2265
2259 2266 .fieldset {
2260 2267 .left-label {
2261 2268 width: 13%;
2262 2269 }
2263 2270 .right-content {
2264 2271 width: 87%;
2265 2272 max-width: 100%;
2266 2273 }
2267 2274 .filename-label {
2268 2275 margin-top: 13px;
2269 2276 }
2270 2277 .commit-message-label {
2271 2278 margin-top: 4px;
2272 2279 }
2273 2280 .file-upload-input {
2274 2281 input {
2275 2282 display: none;
2276 2283 }
2277 2284 margin-top: 10px;
2278 2285 }
2279 2286 .file-upload-label {
2280 2287 margin-top: 10px;
2281 2288 }
2282 2289 p {
2283 2290 margin-top: 5px;
2284 2291 }
2285 2292
2286 2293 }
2287 2294 .custom-path-link {
2288 2295 margin-left: 5px;
2289 2296 }
2290 2297 #commit {
2291 2298 resize: vertical;
2292 2299 }
2293 2300 }
2294 2301
2295 2302 .delete-file-preview {
2296 2303 max-height: 250px;
2297 2304 }
2298 2305
2299 2306 .new-file,
2300 2307 #filter_activate,
2301 2308 #filter_deactivate {
2302 2309 float: right;
2303 2310 margin: 0 0 0 10px;
2304 2311 }
2305 2312
2306 2313 .file-upload-transaction-wrapper {
2307 2314 margin-top: 57px;
2308 2315 clear: both;
2309 2316 }
2310 2317
2311 2318 .file-upload-transaction-wrapper .error {
2312 2319 color: @color5;
2313 2320 }
2314 2321
2315 2322 .file-upload-transaction {
2316 2323 min-height: 200px;
2317 2324 padding: 54px;
2318 2325 border: 1px solid @grey5;
2319 2326 text-align: center;
2320 2327 clear: both;
2321 2328 }
2322 2329
2323 2330 .file-upload-transaction i {
2324 2331 font-size: 48px
2325 2332 }
2326 2333
2327 2334 h3.files_location{
2328 2335 line-height: 2.4em;
2329 2336 }
2330 2337
2331 2338 .browser-nav {
2332 2339 width: 100%;
2333 2340 display: table;
2334 2341 margin-bottom: 20px;
2335 2342
2336 2343 .info_box {
2337 2344 float: left;
2338 2345 display: inline-table;
2339 2346 height: 2.5em;
2340 2347
2341 2348 .browser-cur-rev, .info_box_elem {
2342 2349 display: table-cell;
2343 2350 vertical-align: middle;
2344 2351 }
2345 2352
2346 2353 .drop-menu {
2347 2354 margin: 0 10px;
2348 2355 }
2349 2356
2350 2357 .info_box_elem {
2351 2358 border-top: @border-thickness solid @grey5;
2352 2359 border-bottom: @border-thickness solid @grey5;
2353 2360 box-shadow: @button-shadow;
2354 2361
2355 2362 #at_rev, a {
2356 2363 padding: 0.6em 0.4em;
2357 2364 margin: 0;
2358 2365 .box-shadow(none);
2359 2366 border: 0;
2360 2367 height: 12px;
2361 2368 color: @grey2;
2362 2369 }
2363 2370
2364 2371 input#at_rev {
2365 2372 max-width: 50px;
2366 2373 text-align: center;
2367 2374 }
2368 2375
2369 2376 &.previous {
2370 2377 border: @border-thickness solid @grey5;
2371 2378 border-top-left-radius: @border-radius;
2372 2379 border-bottom-left-radius: @border-radius;
2373 2380
2374 2381 &:hover {
2375 2382 border-color: @grey4;
2376 2383 }
2377 2384
2378 2385 .disabled {
2379 2386 color: @grey5;
2380 2387 cursor: not-allowed;
2381 2388 opacity: 0.5;
2382 2389 }
2383 2390 }
2384 2391
2385 2392 &.next {
2386 2393 border: @border-thickness solid @grey5;
2387 2394 border-top-right-radius: @border-radius;
2388 2395 border-bottom-right-radius: @border-radius;
2389 2396
2390 2397 &:hover {
2391 2398 border-color: @grey4;
2392 2399 }
2393 2400
2394 2401 .disabled {
2395 2402 color: @grey5;
2396 2403 cursor: not-allowed;
2397 2404 opacity: 0.5;
2398 2405 }
2399 2406 }
2400 2407 }
2401 2408
2402 2409 .browser-cur-rev {
2403 2410
2404 2411 span{
2405 2412 margin: 0;
2406 2413 color: @rcblue;
2407 2414 height: 12px;
2408 2415 display: inline-block;
2409 2416 padding: 0.7em 1em ;
2410 2417 border: @border-thickness solid @rcblue;
2411 2418 margin-right: @padding;
2412 2419 }
2413 2420 }
2414 2421
2415 2422 }
2416 2423
2417 2424 .select-index-number {
2418 2425 margin: 0 0 0 20px;
2419 2426 color: @grey3;
2420 2427 }
2421 2428
2422 2429 .search_activate {
2423 2430 display: table-cell;
2424 2431 vertical-align: middle;
2425 2432
2426 2433 input, label{
2427 2434 margin: 0;
2428 2435 padding: 0;
2429 2436 }
2430 2437
2431 2438 input{
2432 2439 margin-left: @textmargin;
2433 2440 }
2434 2441
2435 2442 }
2436 2443 }
2437 2444
2438 2445 .browser-cur-rev{
2439 2446 margin-bottom: @textmargin;
2440 2447 }
2441 2448
2442 2449 #node_filter_box_loading{
2443 2450 .info_text;
2444 2451 }
2445 2452
2446 2453 .browser-search {
2447 2454 margin: -25px 0px 5px 0px;
2448 2455 }
2449 2456
2450 2457 .files-quick-filter {
2451 2458 float: right;
2452 2459 width: 180px;
2453 2460 position: relative;
2454 2461 }
2455 2462
2456 2463 .files-filter-box {
2457 2464 display: flex;
2458 2465 padding: 0px;
2459 2466 border-radius: 3px;
2460 2467 margin-bottom: 0;
2461 2468
2462 2469 a {
2463 2470 border: none !important;
2464 2471 }
2465 2472
2466 2473 li {
2467 2474 list-style-type: none
2468 2475 }
2469 2476 }
2470 2477
2471 2478 .files-filter-box-path {
2472 2479 line-height: 33px;
2473 2480 padding: 0;
2474 2481 width: 20px;
2475 2482 position: absolute;
2476 2483 z-index: 11;
2477 2484 left: 5px;
2478 2485 }
2479 2486
2480 2487 .files-filter-box-input {
2481 2488 margin-right: 0;
2482 2489
2483 2490 input {
2484 2491 border: 1px solid @white;
2485 2492 padding-left: 25px;
2486 2493 width: 145px;
2487 2494
2488 2495 &:hover {
2489 2496 border-color: @grey6;
2490 2497 }
2491 2498
2492 2499 &:focus {
2493 2500 border-color: @grey5;
2494 2501 }
2495 2502 }
2496 2503 }
2497 2504
2498 2505 .browser-result{
2499 2506 td a{
2500 2507 margin-left: 0.5em;
2501 2508 display: inline-block;
2502 2509
2503 2510 em {
2504 2511 font-weight: @text-bold-weight;
2505 2512 font-family: @text-bold;
2506 2513 }
2507 2514 }
2508 2515 }
2509 2516
2510 2517 .browser-highlight{
2511 2518 background-color: @grey5-alpha;
2512 2519 }
2513 2520
2514 2521
2515 2522 .edit-file-fieldset #location,
2516 2523 .edit-file-fieldset #filename {
2517 2524 display: flex;
2518 2525 width: -moz-available; /* WebKit-based browsers will ignore this. */
2519 2526 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2520 2527 width: fill-available;
2521 2528 border: 0;
2522 2529 }
2523 2530
2524 2531 .path-items {
2525 2532 display: flex;
2526 2533 padding: 0;
2527 2534 border: 1px solid #eeeeee;
2528 2535 width: 100%;
2529 2536 float: left;
2530 2537
2531 2538 .breadcrumb-path {
2532 2539 line-height: 30px;
2533 2540 padding: 0 4px;
2534 2541 white-space: nowrap;
2535 2542 }
2536 2543
2537 2544 .upload-form {
2538 2545 margin-top: 46px;
2539 2546 }
2540 2547
2541 2548 .location-path {
2542 2549 width: -moz-available; /* WebKit-based browsers will ignore this. */
2543 2550 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2544 2551 width: fill-available;
2545 2552
2546 2553 .file-name-input {
2547 2554 padding: 0.5em 0;
2548 2555 }
2549 2556
2550 2557 }
2551 2558
2552 2559 ul {
2553 2560 display: flex;
2554 2561 margin: 0;
2555 2562 padding: 0;
2556 2563 width: 100%;
2557 2564 }
2558 2565
2559 2566 li {
2560 2567 list-style-type: none;
2561 2568 }
2562 2569
2563 2570 }
2564 2571
2565 2572 .editor-items {
2566 2573 height: 40px;
2567 2574 margin: 10px 0 -17px 10px;
2568 2575
2569 2576 .editor-action {
2570 2577 cursor: pointer;
2571 2578 }
2572 2579
2573 2580 .editor-action.active {
2574 2581 border-bottom: 2px solid #5C5C5C;
2575 2582 }
2576 2583
2577 2584 li {
2578 2585 list-style-type: none;
2579 2586 }
2580 2587 }
2581 2588
2582 2589 .edit-file-fieldset .message textarea {
2583 2590 border: 1px solid #eeeeee;
2584 2591 }
2585 2592
2586 2593 #files_data .codeblock {
2587 2594 background-color: #F5F5F5;
2588 2595 }
2589 2596
2590 2597 #editor_preview {
2591 2598 background: white;
2592 2599 }
2593 2600
2594 2601 .show-editor {
2595 2602 padding: 10px;
2596 2603 background-color: white;
2597 2604
2598 2605 }
2599 2606
2600 2607 .show-preview {
2601 2608 padding: 10px;
2602 2609 background-color: white;
2603 2610 border-left: 1px solid #eeeeee;
2604 2611 }
2605 2612 // quick filter
2606 2613 .grid-quick-filter {
2607 2614 float: right;
2608 2615 position: relative;
2609 2616 }
2610 2617
2611 2618 .grid-filter-box {
2612 2619 display: flex;
2613 2620 padding: 0px;
2614 2621 border-radius: 3px;
2615 2622 margin-bottom: 0;
2616 2623
2617 2624 a {
2618 2625 border: none !important;
2619 2626 }
2620 2627
2621 2628 li {
2622 2629 list-style-type: none
2623 2630 }
2624 2631 }
2625 2632
2626 2633 .grid-filter-box-icon {
2627 2634 line-height: 33px;
2628 2635 padding: 0;
2629 2636 width: 20px;
2630 2637 position: absolute;
2631 2638 z-index: 11;
2632 2639 left: 5px;
2633 2640 }
2634 2641
2635 2642 .grid-filter-box-input {
2636 2643 margin-right: 0;
2637 2644
2638 2645 input {
2639 2646 border: 1px solid @white;
2640 2647 padding-left: 25px;
2641 2648 width: 145px;
2642 2649
2643 2650 &:hover {
2644 2651 border-color: @grey6;
2645 2652 }
2646 2653
2647 2654 &:focus {
2648 2655 border-color: @grey5;
2649 2656 }
2650 2657 }
2651 2658 }
2652 2659
2653 2660
2654 2661
2655 2662 // Search
2656 2663
2657 2664 .search-form{
2658 2665 #q {
2659 2666 width: @search-form-width;
2660 2667 }
2661 2668 .fields{
2662 2669 margin: 0 0 @space;
2663 2670 }
2664 2671
2665 2672 label{
2666 2673 display: inline-block;
2667 2674 margin-right: @textmargin;
2668 2675 padding-top: 0.25em;
2669 2676 }
2670 2677
2671 2678
2672 2679 .results{
2673 2680 clear: both;
2674 2681 margin: 0 0 @padding;
2675 2682 }
2676 2683
2677 2684 .search-tags {
2678 2685 padding: 5px 0;
2679 2686 }
2680 2687 }
2681 2688
2682 2689 div.search-feedback-items {
2683 2690 display: inline-block;
2684 2691 }
2685 2692
2686 2693 div.search-code-body {
2687 2694 background-color: #ffffff; padding: 5px 0 5px 10px;
2688 2695 pre {
2689 2696 .match { background-color: #faffa6;}
2690 2697 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2691 2698 }
2692 2699 }
2693 2700
2694 2701 .expand_commit.search {
2695 2702 .show_more.open {
2696 2703 height: auto;
2697 2704 max-height: none;
2698 2705 }
2699 2706 }
2700 2707
2701 2708 .search-results {
2702 2709
2703 2710 h2 {
2704 2711 margin-bottom: 0;
2705 2712 }
2706 2713 .codeblock {
2707 2714 border: none;
2708 2715 background: transparent;
2709 2716 }
2710 2717
2711 2718 .codeblock-header {
2712 2719 border: none;
2713 2720 background: transparent;
2714 2721 }
2715 2722
2716 2723 .code-body {
2717 2724 border: @border-thickness solid @grey6;
2718 2725 .border-radius(@border-radius);
2719 2726 }
2720 2727
2721 2728 .td-commit {
2722 2729 &:extend(pre);
2723 2730 border-bottom: @border-thickness solid @border-default-color;
2724 2731 }
2725 2732
2726 2733 .message {
2727 2734 height: auto;
2728 2735 max-width: 350px;
2729 2736 white-space: normal;
2730 2737 text-overflow: initial;
2731 2738 overflow: visible;
2732 2739
2733 2740 .match { background-color: #faffa6;}
2734 2741 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2735 2742 }
2736 2743
2737 2744 .path {
2738 2745 border-bottom: none !important;
2739 2746 border-left: 1px solid @grey6 !important;
2740 2747 border-right: 1px solid @grey6 !important;
2741 2748 }
2742 2749 }
2743 2750
2744 2751 table.rctable td.td-search-results div {
2745 2752 max-width: 100%;
2746 2753 }
2747 2754
2748 2755 #tip-box, .tip-box{
2749 2756 padding: @menupadding/2;
2750 2757 display: block;
2751 2758 border: @border-thickness solid @border-highlight-color;
2752 2759 .border-radius(@border-radius);
2753 2760 background-color: white;
2754 2761 z-index: 99;
2755 2762 white-space: pre-wrap;
2756 2763 }
2757 2764
2758 2765 #linktt {
2759 2766 width: 79px;
2760 2767 }
2761 2768
2762 2769 #help_kb .modal-content{
2763 2770 max-width: 750px;
2764 2771 margin: 10% auto;
2765 2772
2766 2773 table{
2767 2774 td,th{
2768 2775 border-bottom: none;
2769 2776 line-height: 2.5em;
2770 2777 }
2771 2778 th{
2772 2779 padding-bottom: @textmargin/2;
2773 2780 }
2774 2781 td.keys{
2775 2782 text-align: center;
2776 2783 }
2777 2784 }
2778 2785
2779 2786 .block-left{
2780 2787 width: 45%;
2781 2788 margin-right: 5%;
2782 2789 }
2783 2790 .modal-footer{
2784 2791 clear: both;
2785 2792 }
2786 2793 .key.tag{
2787 2794 padding: 0.5em;
2788 2795 background-color: @rcblue;
2789 2796 color: white;
2790 2797 border-color: @rcblue;
2791 2798 .box-shadow(none);
2792 2799 }
2793 2800 }
2794 2801
2795 2802
2796 2803
2797 2804 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2798 2805
2799 2806 @import 'statistics-graph';
2800 2807 @import 'tables';
2801 2808 @import 'forms';
2802 2809 @import 'diff';
2803 2810 @import 'summary';
2804 2811 @import 'navigation';
2805 2812
2806 2813 //--- SHOW/HIDE SECTIONS --//
2807 2814
2808 2815 .btn-collapse {
2809 2816 float: right;
2810 2817 text-align: right;
2811 2818 font-family: @text-light;
2812 2819 font-size: @basefontsize;
2813 2820 cursor: pointer;
2814 2821 border: none;
2815 2822 color: @rcblue;
2816 2823 }
2817 2824
2818 2825 table.rctable,
2819 2826 table.dataTable {
2820 2827 .btn-collapse {
2821 2828 float: right;
2822 2829 text-align: right;
2823 2830 }
2824 2831 }
2825 2832
2826 2833 table.rctable {
2827 2834 &.permissions {
2828 2835
2829 2836 th.td-owner {
2830 2837 padding: 0;
2831 2838 }
2832 2839
2833 2840 th {
2834 2841 font-weight: normal;
2835 2842 padding: 0 5px;
2836 2843 }
2837 2844
2838 2845 }
2839 2846 }
2840 2847
2841 2848
2842 2849 // TODO: johbo: Fix for IE10, this avoids that we see a border
2843 2850 // and padding around checkboxes and radio boxes. Move to the right place,
2844 2851 // or better: Remove this once we did the form refactoring.
2845 2852 input[type=checkbox],
2846 2853 input[type=radio] {
2847 2854 padding: 0;
2848 2855 border: none;
2849 2856 }
2850 2857
2851 2858 .toggle-ajax-spinner{
2852 2859 height: 16px;
2853 2860 width: 16px;
2854 2861 }
2855 2862
2856 2863
2857 2864 .markup-form .clearfix {
2858 2865 .border-radius(@border-radius);
2859 2866 margin: 0px;
2860 2867 }
2861 2868
2862 2869 .markup-form-area {
2863 2870 padding: 8px 12px;
2864 2871 border: 1px solid @grey4;
2865 2872 .border-radius(@border-radius);
2866 2873 }
2867 2874
2868 2875 .markup-form-area-header .nav-links {
2869 2876 display: flex;
2870 2877 flex-flow: row wrap;
2871 2878 -webkit-flex-flow: row wrap;
2872 2879 width: 100%;
2873 2880 }
2874 2881
2875 2882 .markup-form-area-footer {
2876 2883 display: flex;
2877 2884 }
2878 2885
2879 2886 .markup-form-area-footer .toolbar {
2880 2887
2881 2888 }
2882 2889
2883 2890 // markup Form
2884 2891 div.markup-form {
2885 2892 margin-top: 20px;
2886 2893 }
2887 2894
2888 2895 .markup-form strong {
2889 2896 display: block;
2890 2897 margin-bottom: 15px;
2891 2898 }
2892 2899
2893 2900 .markup-form textarea {
2894 2901 width: 100%;
2895 2902 height: 100px;
2896 2903 font-family: @text-monospace;
2897 2904 }
2898 2905
2899 2906 form.markup-form {
2900 2907 margin-top: 10px;
2901 2908 margin-left: 10px;
2902 2909 }
2903 2910
2904 2911 .markup-form .comment-block-ta,
2905 2912 .markup-form .preview-box {
2906 2913 .border-radius(@border-radius);
2907 2914 .box-sizing(border-box);
2908 2915 background-color: white;
2909 2916 }
2910 2917
2911 2918 .markup-form .preview-box.unloaded {
2912 2919 height: 50px;
2913 2920 text-align: center;
2914 2921 padding: 20px;
2915 2922 background-color: white;
2916 2923 }
2917 2924
2918 2925
2919 2926 .dropzone-wrapper {
2920 2927 border: 1px solid @grey5;
2921 2928 padding: 20px;
2922 2929 }
2923 2930
2924 2931 .dropzone,
2925 2932 .dropzone-pure {
2926 2933 border: 2px dashed @grey5;
2927 2934 border-radius: 5px;
2928 2935 background: white;
2929 2936 min-height: 200px;
2930 2937 padding: 54px;
2931 2938
2932 2939 .dz-message {
2933 2940 font-weight: 700;
2934 2941 text-align: center;
2935 2942 margin: 2em 0;
2936 2943 }
2937 2944
2938 2945 }
2939 2946
2940 2947 .dz-preview {
2941 2948 margin: 10px 0 !important;
2942 2949 position: relative;
2943 2950 vertical-align: top;
2944 2951 padding: 10px;
2945 2952 border-bottom: 1px solid @grey5;
2946 2953 }
2947 2954
2948 2955 .dz-filename {
2949 2956 font-weight: 700;
2950 2957 float: left;
2951 2958 }
2952 2959
2953 2960 .dz-sending {
2954 2961 float: right;
2955 2962 }
2956 2963
2957 2964 .dz-response {
2958 2965 clear: both
2959 2966 }
2960 2967
2961 2968 .dz-filename-size {
2962 2969 float: right
2963 2970 }
2964 2971
2965 2972 .dz-error-message {
2966 2973 color: @alert2;
2967 2974 padding-top: 10px;
2968 2975 clear: both;
2969 2976 }
2970 2977
2971 2978
2972 2979 .user-hovercard {
2973 2980 padding: 5px;
2974 2981 }
2975 2982
2976 2983 .user-hovercard-icon {
2977 2984 display: inline;
2978 2985 padding: 0;
2979 2986 box-sizing: content-box;
2980 2987 border-radius: 50%;
2981 2988 float: left;
2982 2989 }
2983 2990
2984 2991 .user-hovercard-name {
2985 2992 float: right;
2986 2993 vertical-align: top;
2987 2994 padding-left: 10px;
2988 2995 min-width: 150px;
2989 2996 }
2990 2997
2991 2998 .user-hovercard-bio {
2992 2999 clear: both;
2993 3000 padding-top: 10px;
2994 3001 }
2995 3002
2996 3003 .user-hovercard-header {
2997 3004 clear: both;
2998 3005 min-height: 10px;
2999 3006 }
3000 3007
3001 3008 .user-hovercard-footer {
3002 3009 clear: both;
3003 3010 min-height: 10px;
3004 3011 }
3005 3012
3006 3013 .user-group-hovercard {
3007 3014 padding: 5px;
3008 3015 }
3009 3016
3010 3017 .user-group-hovercard-icon {
3011 3018 display: inline;
3012 3019 padding: 0;
3013 3020 box-sizing: content-box;
3014 3021 border-radius: 50%;
3015 3022 float: left;
3016 3023 }
3017 3024
3018 3025 .user-group-hovercard-name {
3019 3026 float: left;
3020 3027 vertical-align: top;
3021 3028 padding-left: 10px;
3022 3029 min-width: 150px;
3023 3030 }
3024 3031
3025 3032 .user-group-hovercard-icon i {
3026 3033 border: 1px solid @grey4;
3027 3034 border-radius: 4px;
3028 3035 }
3029 3036
3030 3037 .user-group-hovercard-bio {
3031 3038 clear: both;
3032 3039 padding-top: 10px;
3033 3040 line-height: 1.0em;
3034 3041 }
3035 3042
3036 3043 .user-group-hovercard-header {
3037 3044 clear: both;
3038 3045 min-height: 10px;
3039 3046 }
3040 3047
3041 3048 .user-group-hovercard-footer {
3042 3049 clear: both;
3043 3050 min-height: 10px;
3044 3051 }
3045 3052
3046 3053 .pr-hovercard-header {
3047 3054 clear: both;
3048 3055 display: block;
3049 3056 line-height: 20px;
3050 3057 }
3051 3058
3052 3059 .pr-hovercard-user {
3053 3060 display: flex;
3054 3061 align-items: center;
3055 3062 padding-left: 5px;
3056 3063 }
3057 3064
3058 3065 .pr-hovercard-title {
3059 3066 padding-top: 5px;
3060 3067 } No newline at end of file
@@ -1,1544 +1,1544 b''
1 1 .swal2-popup.swal2-toast {
2 2 flex-direction: row;
3 3 align-items: center;
4 4 width: auto;
5 5 padding: 0.625em;
6 6 overflow-y: hidden;
7 7 background: #fff;
8 8 box-shadow: none;
9 9 }
10 10
11 11 .swal2-popup.swal2-toast .swal2-header {
12 12 flex-direction: row;
13 13 }
14 14
15 15 .swal2-popup.swal2-toast .swal2-title {
16 16 flex-grow: 1;
17 17 justify-content: flex-start;
18 18 margin: 0 0.6em;
19 19 font-size: 1em;
20 20 }
21 21
22 22 .swal2-popup.swal2-toast .swal2-footer {
23 23 margin: 0.5em 0 0;
24 24 padding: 0.5em 0 0;
25 25 font-size: 0.8em;
26 26 }
27 27
28 28 .swal2-popup.swal2-toast .swal2-close {
29 29 position: static;
30 30 width: 0.8em;
31 31 height: 0.8em;
32 32 line-height: 0.8;
33 33 }
34 34
35 35 .swal2-popup.swal2-toast .swal2-content {
36 36 justify-content: flex-start;
37 37 font-size: 1em;
38 38 }
39 39
40 40 .swal2-popup.swal2-toast .swal2-icon {
41 41 width: 2em;
42 42 min-width: 2em;
43 43 height: 2em;
44 44 margin: 0;
45 45 }
46 46
47 47 .swal2-popup.swal2-toast .swal2-icon .swal2-icon-content {
48 48 display: flex;
49 49 align-items: center;
50 50 font-size: 1.8em;
51 51 font-weight: bold;
52 52 }
53 53
54 54 @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
55 55 .swal2-popup.swal2-toast .swal2-icon .swal2-icon-content {
56 56 font-size: 0.25em;
57 57 }
58 58 }
59 59
60 60 .swal2-popup.swal2-toast .swal2-icon.swal2-success .swal2-success-ring {
61 61 width: 2em;
62 62 height: 2em;
63 63 }
64 64
65 65 .swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line] {
66 66 top: 0.875em;
67 67 width: 1.375em;
68 68 }
69 69
70 70 .swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left] {
71 71 left: 0.3125em;
72 72 }
73 73
74 74 .swal2-popup.swal2-toast .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right] {
75 75 right: 0.3125em;
76 76 }
77 77
78 78 .swal2-popup.swal2-toast .swal2-actions {
79 79 flex-basis: auto !important;
80 80 width: auto;
81 81 height: auto;
82 82 margin: 0 0.3125em;
83 83 }
84 84
85 85 .swal2-popup.swal2-toast .swal2-styled {
86 86 margin: 0 0.3125em;
87 87 padding: 0.3125em 0.625em;
88 88 font-size: 1em;
89 89 }
90 90
91 91 .swal2-popup.swal2-toast .swal2-styled:focus {
92 92 box-shadow: 0 0 0 1px #fff, 0 0 0 3px rgba(50, 100, 150, 0.4);
93 93 }
94 94
95 95 .swal2-popup.swal2-toast .swal2-success {
96 96 border-color: @alert1;
97 97 }
98 98
99 99 .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line] {
100 100 position: absolute;
101 101 width: 1.6em;
102 102 height: 3em;
103 103 transform: rotate(45deg);
104 104 border-radius: 50%;
105 105 }
106 106
107 107 .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=left] {
108 108 top: -0.8em;
109 109 left: -0.5em;
110 110 transform: rotate(-45deg);
111 111 transform-origin: 2em 2em;
112 112 border-radius: 4em 0 0 4em;
113 113 }
114 114
115 115 .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-circular-line][class$=right] {
116 116 top: -0.25em;
117 117 left: 0.9375em;
118 118 transform-origin: 0 1.5em;
119 119 border-radius: 0 4em 4em 0;
120 120 }
121 121
122 122 .swal2-popup.swal2-toast .swal2-success .swal2-success-ring {
123 123 width: 2em;
124 124 height: 2em;
125 125 }
126 126
127 127 .swal2-popup.swal2-toast .swal2-success .swal2-success-fix {
128 128 top: 0;
129 129 left: 0.4375em;
130 130 width: 0.4375em;
131 131 height: 2.6875em;
132 132 }
133 133
134 134 .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line] {
135 135 height: 0.3125em;
136 136 }
137 137
138 138 .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line][class$=tip] {
139 139 top: 1.125em;
140 140 left: 0.1875em;
141 141 width: 0.75em;
142 142 }
143 143
144 144 .swal2-popup.swal2-toast .swal2-success [class^=swal2-success-line][class$=long] {
145 145 top: 0.9375em;
146 146 right: 0.1875em;
147 147 width: 1.375em;
148 148 }
149 149
150 150 .swal2-popup.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-tip {
151 151 -webkit-animation: swal2-toast-animate-success-line-tip 0.75s;
152 152 animation: swal2-toast-animate-success-line-tip 0.75s;
153 153 }
154 154
155 155 .swal2-popup.swal2-toast .swal2-success.swal2-icon-show .swal2-success-line-long {
156 156 -webkit-animation: swal2-toast-animate-success-line-long 0.75s;
157 157 animation: swal2-toast-animate-success-line-long 0.75s;
158 158 }
159 159
160 160 .swal2-popup.swal2-toast.swal2-show {
161 161 -webkit-animation: swal2-toast-show 0.5s;
162 162 animation: swal2-toast-show 0.5s;
163 163 }
164 164
165 165 .swal2-popup.swal2-toast.swal2-hide {
166 166 -webkit-animation: swal2-toast-hide 0.1s forwards;
167 167 animation: swal2-toast-hide 0.1s forwards;
168 168 }
169 169
170 170 .swal2-container {
171 171 display: flex;
172 172 position: fixed;
173 173 z-index: 1060;
174 174 top: 0;
175 175 right: 0;
176 176 bottom: 0;
177 177 left: 0;
178 178 flex-direction: row;
179 179 align-items: center;
180 180 justify-content: center;
181 181 padding: 0.625em;
182 182 overflow-x: hidden;
183 183 transition: background-color 0.1s;
184 184 -webkit-overflow-scrolling: touch;
185 185 }
186 186
187 187 .swal2-container.swal2-backdrop-show, .swal2-container.swal2-noanimation {
188 188 background: rgba(0, 0, 0, 0.4);
189 189 }
190 190
191 191 .swal2-container.swal2-backdrop-hide {
192 192 background: transparent !important;
193 193 }
194 194
195 195 .swal2-container.swal2-top {
196 196 align-items: flex-start;
197 197 }
198 198
199 199 .swal2-container.swal2-top-start, .swal2-container.swal2-top-left {
200 200 align-items: flex-start;
201 201 justify-content: flex-start;
202 202 }
203 203
204 204 .swal2-container.swal2-top-end, .swal2-container.swal2-top-right {
205 205 align-items: flex-start;
206 206 justify-content: flex-end;
207 207 }
208 208
209 209 .swal2-container.swal2-center {
210 210 align-items: center;
211 211 }
212 212
213 213 .swal2-container.swal2-center-start, .swal2-container.swal2-center-left {
214 214 align-items: center;
215 215 justify-content: flex-start;
216 216 }
217 217
218 218 .swal2-container.swal2-center-end, .swal2-container.swal2-center-right {
219 219 align-items: center;
220 220 justify-content: flex-end;
221 221 }
222 222
223 223 .swal2-container.swal2-bottom {
224 224 align-items: flex-end;
225 225 }
226 226
227 227 .swal2-container.swal2-bottom-start, .swal2-container.swal2-bottom-left {
228 228 align-items: flex-end;
229 229 justify-content: flex-start;
230 230 }
231 231
232 232 .swal2-container.swal2-bottom-end, .swal2-container.swal2-bottom-right {
233 233 align-items: flex-end;
234 234 justify-content: flex-end;
235 235 }
236 236
237 237 .swal2-container.swal2-bottom > :first-child,
238 238 .swal2-container.swal2-bottom-start > :first-child,
239 239 .swal2-container.swal2-bottom-left > :first-child,
240 240 .swal2-container.swal2-bottom-end > :first-child,
241 241 .swal2-container.swal2-bottom-right > :first-child {
242 242 margin-top: auto;
243 243 }
244 244
245 245 .swal2-container.swal2-grow-fullscreen > .swal2-modal {
246 246 display: flex !important;
247 247 flex: 1;
248 248 align-self: stretch;
249 249 justify-content: center;
250 250 }
251 251
252 252 .swal2-container.swal2-grow-row > .swal2-modal {
253 253 display: flex !important;
254 254 flex: 1;
255 255 align-content: center;
256 256 justify-content: center;
257 257 }
258 258
259 259 .swal2-container.swal2-grow-column {
260 260 flex: 1;
261 261 flex-direction: column;
262 262 }
263 263
264 264 .swal2-container.swal2-grow-column.swal2-top, .swal2-container.swal2-grow-column.swal2-center, .swal2-container.swal2-grow-column.swal2-bottom {
265 265 align-items: center;
266 266 }
267 267
268 268 .swal2-container.swal2-grow-column.swal2-top-start, .swal2-container.swal2-grow-column.swal2-center-start, .swal2-container.swal2-grow-column.swal2-bottom-start, .swal2-container.swal2-grow-column.swal2-top-left, .swal2-container.swal2-grow-column.swal2-center-left, .swal2-container.swal2-grow-column.swal2-bottom-left {
269 269 align-items: flex-start;
270 270 }
271 271
272 272 .swal2-container.swal2-grow-column.swal2-top-end, .swal2-container.swal2-grow-column.swal2-center-end, .swal2-container.swal2-grow-column.swal2-bottom-end, .swal2-container.swal2-grow-column.swal2-top-right, .swal2-container.swal2-grow-column.swal2-center-right, .swal2-container.swal2-grow-column.swal2-bottom-right {
273 273 align-items: flex-end;
274 274 }
275 275
276 276 .swal2-container.swal2-grow-column > .swal2-modal {
277 277 display: flex !important;
278 278 flex: 1;
279 279 align-content: center;
280 280 justify-content: center;
281 281 }
282 282
283 283 .swal2-container.swal2-no-transition {
284 284 transition: none !important;
285 285 }
286 286
287 287 .swal2-container:not(.swal2-top):not(.swal2-top-start):not(.swal2-top-end):not(.swal2-top-left):not(.swal2-top-right):not(.swal2-center-start):not(.swal2-center-end):not(.swal2-center-left):not(.swal2-center-right):not(.swal2-bottom):not(.swal2-bottom-start):not(.swal2-bottom-end):not(.swal2-bottom-left):not(.swal2-bottom-right):not(.swal2-grow-fullscreen) > .swal2-modal {
288 288 margin: auto;
289 289 }
290 290
291 291 @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
292 292 .swal2-container .swal2-modal {
293 293 margin: 0 !important;
294 294 }
295 295 }
296 296
297 297 .swal2-popup {
298 298 display: none;
299 299 position: relative;
300 300 box-sizing: border-box;
301 301 flex-direction: column;
302 302 justify-content: center;
303 303 width: 38em;
304 304 max-width: 100%;
305 305 padding: 1.25em;
306 306 border: none;
307 307 border-radius: 0;
308 308 background: #fff;
309 309 font-family: inherit;
310 font-size: 1rem;
310 font-size: 13px;
311 311 }
312 312
313 313 .swal2-popup:focus {
314 314 outline: none;
315 315 }
316 316
317 317 .swal2-popup.swal2-loading {
318 318 overflow-y: hidden;
319 319 }
320 320
321 321 .swal2-header {
322 322 display: flex;
323 323 flex-direction: column;
324 324 align-items: center;
325 325 }
326 326
327 327 .swal2-title {
328 328 position: relative;
329 329 max-width: 100%;
330 330 margin: 0 0 0.4em;
331 331 padding: 0;
332 332 color: #595959;
333 333 font-size: 1.875em;
334 334 font-weight: 600;
335 335 text-align: center;
336 336 text-transform: none;
337 337 word-wrap: break-word;
338 338 }
339 339
340 340 .swal2-actions {
341 341 display: flex;
342 342 z-index: 1;
343 343 flex-wrap: wrap;
344 344 align-items: center;
345 345 justify-content: center;
346 346 width: 100%;
347 347 margin: 1.25em auto 0;
348 348 }
349 349
350 350 .swal2-actions:not(.swal2-loading) .swal2-styled[disabled] {
351 351 opacity: 0.4;
352 352 }
353 353
354 354 .swal2-actions:not(.swal2-loading) .swal2-styled:hover {
355 355 background-image: linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1));
356 356 }
357 357
358 358 .swal2-actions:not(.swal2-loading) .swal2-styled:active {
359 359 background-image: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2));
360 360 }
361 361
362 362 .swal2-actions.swal2-loading .swal2-styled.swal2-confirm {
363 363 box-sizing: border-box;
364 364 width: 2.5em;
365 365 height: 2.5em;
366 366 margin: 0.46875em;
367 367 padding: 0;
368 368 -webkit-animation: swal2-rotate-loading 1.5s linear 0s infinite normal;
369 369 animation: swal2-rotate-loading 1.5s linear 0s infinite normal;
370 370 border: 0.25em solid transparent;
371 371 border-radius: 100%;
372 372 border-color: transparent;
373 373 background-color: transparent !important;
374 374 color: transparent !important;
375 375 cursor: default;
376 376 -webkit-user-select: none;
377 377 -moz-user-select: none;
378 378 -ms-user-select: none;
379 379 user-select: none;
380 380 }
381 381
382 382 .swal2-actions.swal2-loading .swal2-styled.swal2-cancel {
383 383 margin-right: 30px;
384 384 margin-left: 30px;
385 385 }
386 386
387 387 .swal2-actions.swal2-loading :not(.swal2-styled).swal2-confirm::after {
388 388 content: "";
389 389 display: inline-block;
390 390 width: 15px;
391 391 height: 15px;
392 392 margin-left: 5px;
393 393 -webkit-animation: swal2-rotate-loading 1.5s linear 0s infinite normal;
394 394 animation: swal2-rotate-loading 1.5s linear 0s infinite normal;
395 395 border: 3px solid #999999;
396 396 border-radius: 50%;
397 397 border-right-color: transparent;
398 398 box-shadow: 1px 1px 1px #fff;
399 399 }
400 400
401 401 .swal2-styled {
402 402 margin: 0.3125em;
403 403 padding: 0.625em 2em;
404 404 box-shadow: none;
405 405 font-weight: 500;
406 406 }
407 407
408 408 .swal2-styled:not([disabled]) {
409 409 cursor: pointer;
410 410 }
411 411
412 412 .swal2-styled.swal2-confirm {
413 413 border: 0;
414 414 border-radius: 0;
415 415 background: initial;
416 416 background-color: @alert4;
417 417 color: #fff;
418 418 font-size: 1.0625em;
419 419 }
420 420
421 421 .swal2-styled.swal2-cancel {
422 422 border: 0;
423 423 border-radius: 0;
424 424 background: initial;
425 425 background-color: #aaa;
426 426 color: #fff;
427 427 font-size: 1.0625em;
428 428 }
429 429
430 430 .swal2-styled:focus {
431 431 outline: none;
432 432 box-shadow: 0 0 0 1px #fff, 0 0 0 3px rgba(50, 100, 150, 0.4);
433 433 }
434 434
435 435 .swal2-styled::-moz-focus-inner {
436 436 border: 0;
437 437 }
438 438
439 439 .swal2-footer {
440 440 justify-content: center;
441 441 margin: 1.25em 0 0;
442 442 padding: 1em 0 0;
443 443 border-top: 1px solid #eee;
444 444 color: #545454;
445 445 font-size: 1em;
446 446 }
447 447
448 448 .swal2-timer-progress-bar-container {
449 449 position: absolute;
450 450 right: 0;
451 451 bottom: 0;
452 452 left: 0;
453 453 height: 0.25em;
454 454 overflow: hidden;
455 455 border-bottom-right-radius: 0;
456 456 border-bottom-left-radius: 0;
457 457 }
458 458
459 459 .swal2-timer-progress-bar {
460 460 width: 100%;
461 461 height: 0.25em;
462 462 background: rgba(0, 0, 0, 0.2);
463 463 }
464 464
465 465 .swal2-image {
466 466 max-width: 100%;
467 467 margin: 1.25em auto;
468 468 }
469 469
470 470 .swal2-close {
471 471 position: absolute;
472 472 z-index: 2;
473 473 /* 1617 */
474 474 top: 0;
475 475 right: 0;
476 476 align-items: center;
477 477 justify-content: center;
478 478 width: 1.2em;
479 479 height: 1.2em;
480 480 padding: 0;
481 481 overflow: hidden;
482 482 transition: color 0.1s ease-out;
483 483 border: none;
484 484 border-radius: 0;
485 485 background: transparent;
486 486 color: #cccccc;
487 487 font-family: serif;
488 488 font-size: 2.5em;
489 489 line-height: 1.2;
490 490 cursor: pointer;
491 491 }
492 492
493 493 .swal2-close:hover {
494 494 transform: none;
495 495 background: transparent;
496 496 color: #f27474;
497 497 }
498 498
499 499 .swal2-close::-moz-focus-inner {
500 500 border: 0;
501 501 }
502 502
503 503 .swal2-content {
504 504 z-index: 1;
505 505 justify-content: center;
506 506 margin: 0;
507 507 padding: 0;
508 508 color: #545454;
509 509 font-size: 1.125em;
510 510 font-weight: normal;
511 511 line-height: normal;
512 512 text-align: center;
513 513 word-wrap: break-word;
514 514 }
515 515
516 516 .swal2-input,
517 517 .swal2-file,
518 518 .swal2-textarea,
519 519 .swal2-select,
520 520 .swal2-radio,
521 521 .swal2-checkbox {
522 522 margin: 1em auto;
523 523 }
524 524
525 525 .swal2-input,
526 526 .swal2-file,
527 527 .swal2-textarea {
528 528 box-sizing: border-box;
529 529 width: 100%;
530 530 transition: initial;
531 531 border: 1px solid #d9d9d9;
532 532 border-radius: 0;
533 533 background: inherit;
534 534 box-shadow: none;
535 535 color: inherit;
536 536 font-size: 1.125em;
537 537 }
538 538
539 539 .swal2-input.swal2-inputerror,
540 540 .swal2-file.swal2-inputerror,
541 541 .swal2-textarea.swal2-inputerror {
542 542 border-color: #f27474 !important;
543 543 box-shadow: 0 0 2px #f27474 !important;
544 544 }
545 545
546 546 .swal2-input:focus,
547 547 .swal2-file:focus,
548 548 .swal2-textarea:focus {
549 549 border: 1px solid #b4dbed;
550 550 outline: none;
551 551 box-shadow: 0 0 3px #c4e6f5;
552 552 }
553 553
554 554 .swal2-input::-webkit-input-placeholder, .swal2-file::-webkit-input-placeholder, .swal2-textarea::-webkit-input-placeholder {
555 555 color: #cccccc;
556 556 }
557 557
558 558 .swal2-input::-moz-placeholder, .swal2-file::-moz-placeholder, .swal2-textarea::-moz-placeholder {
559 559 color: #cccccc;
560 560 }
561 561
562 562 .swal2-input:-ms-input-placeholder, .swal2-file:-ms-input-placeholder, .swal2-textarea:-ms-input-placeholder {
563 563 color: #cccccc;
564 564 }
565 565
566 566 .swal2-input::-ms-input-placeholder, .swal2-file::-ms-input-placeholder, .swal2-textarea::-ms-input-placeholder {
567 567 color: #cccccc;
568 568 }
569 569
570 570 .swal2-input::placeholder,
571 571 .swal2-file::placeholder,
572 572 .swal2-textarea::placeholder {
573 573 color: #cccccc;
574 574 }
575 575
576 576 .swal2-range {
577 577 margin: 1em auto;
578 578 background: #fff;
579 579 }
580 580
581 581 .swal2-range input {
582 582 width: 80%;
583 583 }
584 584
585 585 .swal2-range output {
586 586 width: 20%;
587 587 color: inherit;
588 588 font-weight: 600;
589 589 text-align: center;
590 590 }
591 591
592 592 .swal2-range input,
593 593 .swal2-range output {
594 594 height: 2.625em;
595 595 padding: 0;
596 596 font-size: 1.125em;
597 597 line-height: 2.625em;
598 598 }
599 599
600 600 .swal2-input {
601 601 height: 2.625em;
602 602 padding: 0 0.75em;
603 603 }
604 604
605 605 .swal2-input[type=number] {
606 606 max-width: 10em;
607 607 }
608 608
609 609 .swal2-file {
610 610 background: inherit;
611 611 font-size: 1.125em;
612 612 }
613 613
614 614 .swal2-textarea {
615 615 height: 6.75em;
616 616 padding: 0.75em;
617 617 }
618 618
619 619 .swal2-select {
620 620 min-width: 50%;
621 621 max-width: 100%;
622 622 padding: 0.375em 0.625em;
623 623 background: inherit;
624 624 color: inherit;
625 625 font-size: 1.125em;
626 626 }
627 627
628 628 .swal2-radio,
629 629 .swal2-checkbox {
630 630 align-items: center;
631 631 justify-content: center;
632 632 background: #fff;
633 633 color: inherit;
634 634 }
635 635
636 636 .swal2-radio label,
637 637 .swal2-checkbox label {
638 638 margin: 0 0.6em;
639 639 font-size: 1.125em;
640 640 }
641 641
642 642 .swal2-radio input,
643 643 .swal2-checkbox input {
644 644 margin: 0 0.4em;
645 645 }
646 646
647 647 .swal2-validation-message {
648 648 display: none;
649 649 align-items: center;
650 650 justify-content: center;
651 651 padding: 0.625em;
652 652 overflow: hidden;
653 653 background: #f0f0f0;
654 654 color: #666666;
655 655 font-size: 1em;
656 656 font-weight: 300;
657 657 }
658 658
659 659 .swal2-validation-message::before {
660 660 content: "!";
661 661 display: inline-block;
662 662 width: 1.5em;
663 663 min-width: 1.5em;
664 664 height: 1.5em;
665 665 margin: 0 0.625em;
666 666 border-radius: 50%;
667 667 background-color: #f27474;
668 668 color: #fff;
669 669 font-weight: 600;
670 670 line-height: 1.5em;
671 671 text-align: center;
672 672 }
673 673
674 674 .swal2-icon {
675 675 position: relative;
676 676 box-sizing: content-box;
677 677 justify-content: center;
678 678 width: 5em;
679 679 height: 5em;
680 680 margin: 1.25em auto 1.875em;
681 681 border: 0.25em solid transparent;
682 682 border-radius: 50%;
683 683 font-family: inherit;
684 684 line-height: 5em;
685 685 cursor: default;
686 686 -webkit-user-select: none;
687 687 -moz-user-select: none;
688 688 -ms-user-select: none;
689 689 user-select: none;
690 690 }
691 691
692 692 .swal2-icon .swal2-icon-content {
693 693 display: flex;
694 694 align-items: center;
695 695 font-size: 3.75em;
696 696 }
697 697
698 698 .swal2-icon.swal2-error {
699 699 border-color: @alert2;
700 700 color: @alert2;
701 701 }
702 702
703 703 .swal2-icon.swal2-error .swal2-x-mark {
704 704 position: relative;
705 705 flex-grow: 1;
706 706 }
707 707
708 708 .swal2-icon.swal2-error [class^=swal2-x-mark-line] {
709 709 display: block;
710 710 position: absolute;
711 711 top: 2.3125em;
712 712 width: 2.9375em;
713 713 height: 0.3125em;
714 714 border-radius: 0.125em;
715 715 background-color: @alert2;
716 716 }
717 717
718 718 .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=left] {
719 719 left: 1.0625em;
720 720 transform: rotate(45deg);
721 721 }
722 722
723 723 .swal2-icon.swal2-error [class^=swal2-x-mark-line][class$=right] {
724 724 right: 1em;
725 725 transform: rotate(-45deg);
726 726 }
727 727
728 728 .swal2-icon.swal2-error.swal2-icon-show {
729 729 //-webkit-animation: swal2-animate-error-icon 0.5s;
730 730 // animation: swal2-animate-error-icon 0.5s;
731 731 }
732 732
733 733 .swal2-icon.swal2-error.swal2-icon-show .swal2-x-mark {
734 734 //-webkit-animation: swal2-animate-error-x-mark 0.5s;
735 735 // animation: swal2-animate-error-x-mark 0.5s;
736 736 }
737 737
738 738 .swal2-icon.swal2-warning {
739 739 border-color: @alert3;
740 740 color: @alert3;
741 741 }
742 742
743 743 .swal2-icon.swal2-info {
744 744 border-color: #9de0f6;
745 745 color: #3fc3ee;
746 746 }
747 747
748 748 .swal2-icon.swal2-question {
749 749 border-color: #c9dae1;
750 750 color: #87adbd;
751 751 }
752 752
753 753 .swal2-icon.swal2-success {
754 754 border-color: @alert1;
755 755 color: @alert1;
756 756 }
757 757
758 758 .swal2-icon.swal2-success [class^=swal2-success-circular-line] {
759 759 position: absolute;
760 760 width: 3.75em;
761 761 height: 7.5em;
762 762 transform: rotate(45deg);
763 763 border-radius: 50%;
764 764 }
765 765
766 766 .swal2-icon.swal2-success [class^=swal2-success-circular-line][class$=left] {
767 767 top: -0.4375em;
768 768 left: -2.0635em;
769 769 transform: rotate(-45deg);
770 770 transform-origin: 3.75em 3.75em;
771 771 border-radius: 7.5em 0 0 7.5em;
772 772 }
773 773
774 774 .swal2-icon.swal2-success [class^=swal2-success-circular-line][class$=right] {
775 775 top: -0.6875em;
776 776 left: 1.875em;
777 777 transform: rotate(-45deg);
778 778 transform-origin: 0 3.75em;
779 779 border-radius: 0 7.5em 7.5em 0;
780 780 }
781 781
782 782 .swal2-icon.swal2-success .swal2-success-ring {
783 783 position: absolute;
784 784 z-index: 2;
785 785 top: -0.25em;
786 786 left: -0.25em;
787 787 box-sizing: content-box;
788 788 width: 100%;
789 789 height: 100%;
790 790 border: 0.25em solid rgba(165, 220, 134, 0.3);
791 791 border-radius: 50%;
792 792 }
793 793
794 794 .swal2-icon.swal2-success .swal2-success-fix {
795 795 position: absolute;
796 796 z-index: 1;
797 797 top: 0.5em;
798 798 left: 1.625em;
799 799 width: 0.4375em;
800 800 height: 5.625em;
801 801 transform: rotate(-45deg);
802 802 }
803 803
804 804 .swal2-icon.swal2-success [class^=swal2-success-line] {
805 805 display: block;
806 806 position: absolute;
807 807 z-index: 2;
808 808 height: 0.3125em;
809 809 border-radius: 0.125em;
810 810 background-color: @alert1;
811 811 }
812 812
813 813 .swal2-icon.swal2-success [class^=swal2-success-line][class$=tip] {
814 814 top: 2.875em;
815 815 left: 0.8125em;
816 816 width: 1.5625em;
817 817 transform: rotate(45deg);
818 818 }
819 819
820 820 .swal2-icon.swal2-success [class^=swal2-success-line][class$=long] {
821 821 top: 2.375em;
822 822 right: 0.5em;
823 823 width: 2.9375em;
824 824 transform: rotate(-45deg);
825 825 }
826 826
827 827 .swal2-icon.swal2-success.swal2-icon-show .swal2-success-line-tip {
828 828 -webkit-animation: swal2-animate-success-line-tip 0.75s;
829 829 animation: swal2-animate-success-line-tip 0.75s;
830 830 }
831 831
832 832 .swal2-icon.swal2-success.swal2-icon-show .swal2-success-line-long {
833 833 -webkit-animation: swal2-animate-success-line-long 0.75s;
834 834 animation: swal2-animate-success-line-long 0.75s;
835 835 }
836 836
837 837 .swal2-icon.swal2-success.swal2-icon-show .swal2-success-circular-line-right {
838 838 -webkit-animation: swal2-rotate-success-circular-line 4.25s ease-in;
839 839 animation: swal2-rotate-success-circular-line 4.25s ease-in;
840 840 }
841 841
842 842 .swal2-progress-steps {
843 843 align-items: center;
844 844 margin: 0 0 1.25em;
845 845 padding: 0;
846 846 background: inherit;
847 847 font-weight: 600;
848 848 }
849 849
850 850 .swal2-progress-steps li {
851 851 display: inline-block;
852 852 position: relative;
853 853 }
854 854
855 855 .swal2-progress-steps .swal2-progress-step {
856 856 z-index: 20;
857 857 width: 2em;
858 858 height: 2em;
859 859 border-radius: 2em;
860 860 background: #3085d6;
861 861 color: #fff;
862 862 line-height: 2em;
863 863 text-align: center;
864 864 }
865 865
866 866 .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step {
867 867 background: #3085d6;
868 868 }
869 869
870 870 .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step ~ .swal2-progress-step {
871 871 background: #add8e6;
872 872 color: #fff;
873 873 }
874 874
875 875 .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step ~ .swal2-progress-step-line {
876 876 background: #add8e6;
877 877 }
878 878
879 879 .swal2-progress-steps .swal2-progress-step-line {
880 880 z-index: 10;
881 881 width: 2.5em;
882 882 height: 0.4em;
883 883 margin: 0 -1px;
884 884 background: #3085d6;
885 885 }
886 886
887 887 [class^=swal2] {
888 888 -webkit-tap-highlight-color: transparent;
889 889 }
890 890
891 891 .swal2-show {
892 892 -webkit-animation: swal2-show 0.3s;
893 893 animation: swal2-show 0.3s;
894 894 }
895 895
896 896 .swal2-hide {
897 897 -webkit-animation: swal2-hide 0.15s forwards;
898 898 animation: swal2-hide 0.15s forwards;
899 899 }
900 900
901 901 .swal2-noanimation {
902 902 transition: none;
903 903 }
904 904
905 905 .swal2-scrollbar-measure {
906 906 position: absolute;
907 907 top: -9999px;
908 908 width: 50px;
909 909 height: 50px;
910 910 overflow: scroll;
911 911 }
912 912
913 913 .swal2-rtl .swal2-close {
914 914 right: auto;
915 915 left: 0;
916 916 }
917 917
918 918 .swal2-rtl .swal2-timer-progress-bar {
919 919 right: 0;
920 920 left: auto;
921 921 }
922 922
923 923 @supports (-ms-accelerator: true) {
924 924 .swal2-range input {
925 925 width: 100% !important;
926 926 }
927 927
928 928 .swal2-range output {
929 929 display: none;
930 930 }
931 931 }
932 932
933 933 @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
934 934 .swal2-range input {
935 935 width: 100% !important;
936 936 }
937 937
938 938 .swal2-range output {
939 939 display: none;
940 940 }
941 941 }
942 942
943 943 @-moz-document url-prefix() {
944 944 .swal2-close:focus {
945 945 outline: 2px solid rgba(50, 100, 150, 0.4);
946 946 }
947 947 }
948 948
949 949 @-webkit-keyframes swal2-toast-show {
950 950 0% {
951 951 transform: translateY(-0.625em) rotateZ(2deg);
952 952 }
953 953 33% {
954 954 transform: translateY(0) rotateZ(-2deg);
955 955 }
956 956 66% {
957 957 transform: translateY(0.3125em) rotateZ(2deg);
958 958 }
959 959 100% {
960 960 transform: translateY(0) rotateZ(0deg);
961 961 }
962 962 }
963 963
964 964 @keyframes swal2-toast-show {
965 965 0% {
966 966 transform: translateY(-0.625em) rotateZ(2deg);
967 967 }
968 968 33% {
969 969 transform: translateY(0) rotateZ(-2deg);
970 970 }
971 971 66% {
972 972 transform: translateY(0.3125em) rotateZ(2deg);
973 973 }
974 974 100% {
975 975 transform: translateY(0) rotateZ(0deg);
976 976 }
977 977 }
978 978
979 979 @-webkit-keyframes swal2-toast-hide {
980 980 100% {
981 981 transform: rotateZ(1deg);
982 982 opacity: 0;
983 983 }
984 984 }
985 985
986 986 @keyframes swal2-toast-hide {
987 987 100% {
988 988 transform: rotateZ(1deg);
989 989 opacity: 0;
990 990 }
991 991 }
992 992
993 993 @-webkit-keyframes swal2-toast-animate-success-line-tip {
994 994 0% {
995 995 top: 0.5625em;
996 996 left: 0.0625em;
997 997 width: 0;
998 998 }
999 999 54% {
1000 1000 top: 0.125em;
1001 1001 left: 0.125em;
1002 1002 width: 0;
1003 1003 }
1004 1004 70% {
1005 1005 top: 0.625em;
1006 1006 left: -0.25em;
1007 1007 width: 1.625em;
1008 1008 }
1009 1009 84% {
1010 1010 top: 1.0625em;
1011 1011 left: 0.75em;
1012 1012 width: 0.5em;
1013 1013 }
1014 1014 100% {
1015 1015 top: 1.125em;
1016 1016 left: 0.1875em;
1017 1017 width: 0.75em;
1018 1018 }
1019 1019 }
1020 1020
1021 1021 @keyframes swal2-toast-animate-success-line-tip {
1022 1022 0% {
1023 1023 top: 0.5625em;
1024 1024 left: 0.0625em;
1025 1025 width: 0;
1026 1026 }
1027 1027 54% {
1028 1028 top: 0.125em;
1029 1029 left: 0.125em;
1030 1030 width: 0;
1031 1031 }
1032 1032 70% {
1033 1033 top: 0.625em;
1034 1034 left: -0.25em;
1035 1035 width: 1.625em;
1036 1036 }
1037 1037 84% {
1038 1038 top: 1.0625em;
1039 1039 left: 0.75em;
1040 1040 width: 0.5em;
1041 1041 }
1042 1042 100% {
1043 1043 top: 1.125em;
1044 1044 left: 0.1875em;
1045 1045 width: 0.75em;
1046 1046 }
1047 1047 }
1048 1048
1049 1049 @-webkit-keyframes swal2-toast-animate-success-line-long {
1050 1050 0% {
1051 1051 top: 1.625em;
1052 1052 right: 1.375em;
1053 1053 width: 0;
1054 1054 }
1055 1055 65% {
1056 1056 top: 1.25em;
1057 1057 right: 0.9375em;
1058 1058 width: 0;
1059 1059 }
1060 1060 84% {
1061 1061 top: 0.9375em;
1062 1062 right: 0;
1063 1063 width: 1.125em;
1064 1064 }
1065 1065 100% {
1066 1066 top: 0.9375em;
1067 1067 right: 0.1875em;
1068 1068 width: 1.375em;
1069 1069 }
1070 1070 }
1071 1071
1072 1072 @keyframes swal2-toast-animate-success-line-long {
1073 1073 0% {
1074 1074 top: 1.625em;
1075 1075 right: 1.375em;
1076 1076 width: 0;
1077 1077 }
1078 1078 65% {
1079 1079 top: 1.25em;
1080 1080 right: 0.9375em;
1081 1081 width: 0;
1082 1082 }
1083 1083 84% {
1084 1084 top: 0.9375em;
1085 1085 right: 0;
1086 1086 width: 1.125em;
1087 1087 }
1088 1088 100% {
1089 1089 top: 0.9375em;
1090 1090 right: 0.1875em;
1091 1091 width: 1.375em;
1092 1092 }
1093 1093 }
1094 1094
1095 1095 @-webkit-keyframes swal2-show {
1096 1096 0% {
1097 1097 transform: scale(0.7);
1098 1098 }
1099 1099 45% {
1100 1100 transform: scale(1.05);
1101 1101 }
1102 1102 80% {
1103 1103 transform: scale(0.95);
1104 1104 }
1105 1105 100% {
1106 1106 transform: scale(1);
1107 1107 }
1108 1108 }
1109 1109
1110 1110 @keyframes swal2-show {
1111 1111 0% {
1112 1112 transform: scale(0.7);
1113 1113 }
1114 1114 45% {
1115 1115 transform: scale(1.05);
1116 1116 }
1117 1117 80% {
1118 1118 transform: scale(0.95);
1119 1119 }
1120 1120 100% {
1121 1121 transform: scale(1);
1122 1122 }
1123 1123 }
1124 1124
1125 1125 @-webkit-keyframes swal2-hide {
1126 1126 0% {
1127 1127 transform: scale(1);
1128 1128 opacity: 1;
1129 1129 }
1130 1130 100% {
1131 1131 transform: scale(0.5);
1132 1132 opacity: 0;
1133 1133 }
1134 1134 }
1135 1135
1136 1136 @keyframes swal2-hide {
1137 1137 0% {
1138 1138 transform: scale(1);
1139 1139 opacity: 1;
1140 1140 }
1141 1141 100% {
1142 1142 transform: scale(0.5);
1143 1143 opacity: 0;
1144 1144 }
1145 1145 }
1146 1146
1147 1147 @-webkit-keyframes swal2-animate-success-line-tip {
1148 1148 0% {
1149 1149 top: 1.1875em;
1150 1150 left: 0.0625em;
1151 1151 width: 0;
1152 1152 }
1153 1153 54% {
1154 1154 top: 1.0625em;
1155 1155 left: 0.125em;
1156 1156 width: 0;
1157 1157 }
1158 1158 70% {
1159 1159 top: 2.1875em;
1160 1160 left: -0.375em;
1161 1161 width: 3.125em;
1162 1162 }
1163 1163 84% {
1164 1164 top: 3em;
1165 1165 left: 1.3125em;
1166 1166 width: 1.0625em;
1167 1167 }
1168 1168 100% {
1169 1169 top: 2.8125em;
1170 1170 left: 0.8125em;
1171 1171 width: 1.5625em;
1172 1172 }
1173 1173 }
1174 1174
1175 1175 @keyframes swal2-animate-success-line-tip {
1176 1176 0% {
1177 1177 top: 1.1875em;
1178 1178 left: 0.0625em;
1179 1179 width: 0;
1180 1180 }
1181 1181 54% {
1182 1182 top: 1.0625em;
1183 1183 left: 0.125em;
1184 1184 width: 0;
1185 1185 }
1186 1186 70% {
1187 1187 top: 2.1875em;
1188 1188 left: -0.375em;
1189 1189 width: 3.125em;
1190 1190 }
1191 1191 84% {
1192 1192 top: 3em;
1193 1193 left: 1.3125em;
1194 1194 width: 1.0625em;
1195 1195 }
1196 1196 100% {
1197 1197 top: 2.8125em;
1198 1198 left: 0.8125em;
1199 1199 width: 1.5625em;
1200 1200 }
1201 1201 }
1202 1202
1203 1203 @-webkit-keyframes swal2-animate-success-line-long {
1204 1204 0% {
1205 1205 top: 3.375em;
1206 1206 right: 2.875em;
1207 1207 width: 0;
1208 1208 }
1209 1209 65% {
1210 1210 top: 3.375em;
1211 1211 right: 2.875em;
1212 1212 width: 0;
1213 1213 }
1214 1214 84% {
1215 1215 top: 2.1875em;
1216 1216 right: 0;
1217 1217 width: 3.4375em;
1218 1218 }
1219 1219 100% {
1220 1220 top: 2.375em;
1221 1221 right: 0.5em;
1222 1222 width: 2.9375em;
1223 1223 }
1224 1224 }
1225 1225
1226 1226 @keyframes swal2-animate-success-line-long {
1227 1227 0% {
1228 1228 top: 3.375em;
1229 1229 right: 2.875em;
1230 1230 width: 0;
1231 1231 }
1232 1232 65% {
1233 1233 top: 3.375em;
1234 1234 right: 2.875em;
1235 1235 width: 0;
1236 1236 }
1237 1237 84% {
1238 1238 top: 2.1875em;
1239 1239 right: 0;
1240 1240 width: 3.4375em;
1241 1241 }
1242 1242 100% {
1243 1243 top: 2.375em;
1244 1244 right: 0.5em;
1245 1245 width: 2.9375em;
1246 1246 }
1247 1247 }
1248 1248
1249 1249 @-webkit-keyframes swal2-rotate-success-circular-line {
1250 1250 0% {
1251 1251 transform: rotate(-45deg);
1252 1252 }
1253 1253 5% {
1254 1254 transform: rotate(-45deg);
1255 1255 }
1256 1256 12% {
1257 1257 transform: rotate(-405deg);
1258 1258 }
1259 1259 100% {
1260 1260 transform: rotate(-405deg);
1261 1261 }
1262 1262 }
1263 1263
1264 1264 @keyframes swal2-rotate-success-circular-line {
1265 1265 0% {
1266 1266 transform: rotate(-45deg);
1267 1267 }
1268 1268 5% {
1269 1269 transform: rotate(-45deg);
1270 1270 }
1271 1271 12% {
1272 1272 transform: rotate(-405deg);
1273 1273 }
1274 1274 100% {
1275 1275 transform: rotate(-405deg);
1276 1276 }
1277 1277 }
1278 1278
1279 1279 @-webkit-keyframes swal2-animate-error-x-mark {
1280 1280 0% {
1281 1281 margin-top: 1.625em;
1282 1282 transform: scale(0.4);
1283 1283 opacity: 0;
1284 1284 }
1285 1285 50% {
1286 1286 margin-top: 1.625em;
1287 1287 transform: scale(0.4);
1288 1288 opacity: 0;
1289 1289 }
1290 1290 80% {
1291 1291 margin-top: -0.375em;
1292 1292 transform: scale(1.15);
1293 1293 }
1294 1294 100% {
1295 1295 margin-top: 0;
1296 1296 transform: scale(1);
1297 1297 opacity: 1;
1298 1298 }
1299 1299 }
1300 1300
1301 1301 @keyframes swal2-animate-error-x-mark {
1302 1302 0% {
1303 1303 margin-top: 1.625em;
1304 1304 transform: scale(0.4);
1305 1305 opacity: 0;
1306 1306 }
1307 1307 50% {
1308 1308 margin-top: 1.625em;
1309 1309 transform: scale(0.4);
1310 1310 opacity: 0;
1311 1311 }
1312 1312 80% {
1313 1313 margin-top: -0.375em;
1314 1314 transform: scale(1.15);
1315 1315 }
1316 1316 100% {
1317 1317 margin-top: 0;
1318 1318 transform: scale(1);
1319 1319 opacity: 1;
1320 1320 }
1321 1321 }
1322 1322
1323 1323 @-webkit-keyframes swal2-animate-error-icon {
1324 1324 0% {
1325 1325 transform: rotateX(100deg);
1326 1326 opacity: 0;
1327 1327 }
1328 1328 100% {
1329 1329 transform: rotateX(0deg);
1330 1330 opacity: 1;
1331 1331 }
1332 1332 }
1333 1333
1334 1334 @keyframes swal2-animate-error-icon {
1335 1335 0% {
1336 1336 transform: rotateX(100deg);
1337 1337 opacity: 0;
1338 1338 }
1339 1339 100% {
1340 1340 transform: rotateX(0deg);
1341 1341 opacity: 1;
1342 1342 }
1343 1343 }
1344 1344
1345 1345 @-webkit-keyframes swal2-rotate-loading {
1346 1346 0% {
1347 1347 transform: rotate(0deg);
1348 1348 }
1349 1349 100% {
1350 1350 transform: rotate(360deg);
1351 1351 }
1352 1352 }
1353 1353
1354 1354 @keyframes swal2-rotate-loading {
1355 1355 0% {
1356 1356 transform: rotate(0deg);
1357 1357 }
1358 1358 100% {
1359 1359 transform: rotate(360deg);
1360 1360 }
1361 1361 }
1362 1362
1363 1363 body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) {
1364 1364 overflow: hidden;
1365 1365 }
1366 1366
1367 1367 body.swal2-height-auto {
1368 1368 height: auto !important;
1369 1369 }
1370 1370
1371 1371 body.swal2-no-backdrop .swal2-container {
1372 1372 top: auto;
1373 1373 right: auto;
1374 1374 bottom: auto;
1375 1375 left: auto;
1376 1376 max-width: calc(100% - 0.625em * 2);
1377 1377 background-color: transparent !important;
1378 1378 }
1379 1379
1380 1380 body.swal2-no-backdrop .swal2-container > .swal2-modal {
1381 1381 box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
1382 1382 }
1383 1383
1384 1384 body.swal2-no-backdrop .swal2-container.swal2-top {
1385 1385 top: 0;
1386 1386 left: 50%;
1387 1387 transform: translateX(-50%);
1388 1388 }
1389 1389
1390 1390 body.swal2-no-backdrop .swal2-container.swal2-top-start, body.swal2-no-backdrop .swal2-container.swal2-top-left {
1391 1391 top: 0;
1392 1392 left: 0;
1393 1393 }
1394 1394
1395 1395 body.swal2-no-backdrop .swal2-container.swal2-top-end, body.swal2-no-backdrop .swal2-container.swal2-top-right {
1396 1396 top: 0;
1397 1397 right: 0;
1398 1398 }
1399 1399
1400 1400 body.swal2-no-backdrop .swal2-container.swal2-center {
1401 1401 top: 50%;
1402 1402 left: 50%;
1403 1403 transform: translate(-50%, -50%);
1404 1404 }
1405 1405
1406 1406 body.swal2-no-backdrop .swal2-container.swal2-center-start, body.swal2-no-backdrop .swal2-container.swal2-center-left {
1407 1407 top: 50%;
1408 1408 left: 0;
1409 1409 transform: translateY(-50%);
1410 1410 }
1411 1411
1412 1412 body.swal2-no-backdrop .swal2-container.swal2-center-end, body.swal2-no-backdrop .swal2-container.swal2-center-right {
1413 1413 top: 50%;
1414 1414 right: 0;
1415 1415 transform: translateY(-50%);
1416 1416 }
1417 1417
1418 1418 body.swal2-no-backdrop .swal2-container.swal2-bottom {
1419 1419 bottom: 0;
1420 1420 left: 50%;
1421 1421 transform: translateX(-50%);
1422 1422 }
1423 1423
1424 1424 body.swal2-no-backdrop .swal2-container.swal2-bottom-start, body.swal2-no-backdrop .swal2-container.swal2-bottom-left {
1425 1425 bottom: 0;
1426 1426 left: 0;
1427 1427 }
1428 1428
1429 1429 body.swal2-no-backdrop .swal2-container.swal2-bottom-end, body.swal2-no-backdrop .swal2-container.swal2-bottom-right {
1430 1430 right: 0;
1431 1431 bottom: 0;
1432 1432 }
1433 1433
1434 1434 @media print {
1435 1435 body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) {
1436 1436 overflow-y: scroll !important;
1437 1437 }
1438 1438
1439 1439 body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) > [aria-hidden=true] {
1440 1440 display: none;
1441 1441 }
1442 1442
1443 1443 body.swal2-shown:not(.swal2-no-backdrop):not(.swal2-toast-shown) .swal2-container {
1444 1444 position: static !important;
1445 1445 }
1446 1446 }
1447 1447
1448 1448 body.swal2-toast-shown .swal2-container {
1449 1449 background-color: transparent;
1450 1450 }
1451 1451
1452 1452 body.swal2-toast-shown .swal2-container.swal2-top {
1453 1453 top: 0;
1454 1454 right: auto;
1455 1455 bottom: auto;
1456 1456 left: 50%;
1457 1457 transform: translateX(-50%);
1458 1458 }
1459 1459
1460 1460 body.swal2-toast-shown .swal2-container.swal2-top-end, body.swal2-toast-shown .swal2-container.swal2-top-right {
1461 1461 top: 0;
1462 1462 right: 0;
1463 1463 bottom: auto;
1464 1464 left: auto;
1465 1465 }
1466 1466
1467 1467 body.swal2-toast-shown .swal2-container.swal2-top-start, body.swal2-toast-shown .swal2-container.swal2-top-left {
1468 1468 top: 0;
1469 1469 right: auto;
1470 1470 bottom: auto;
1471 1471 left: 0;
1472 1472 }
1473 1473
1474 1474 body.swal2-toast-shown .swal2-container.swal2-center-start, body.swal2-toast-shown .swal2-container.swal2-center-left {
1475 1475 top: 50%;
1476 1476 right: auto;
1477 1477 bottom: auto;
1478 1478 left: 0;
1479 1479 transform: translateY(-50%);
1480 1480 }
1481 1481
1482 1482 body.swal2-toast-shown .swal2-container.swal2-center {
1483 1483 top: 50%;
1484 1484 right: auto;
1485 1485 bottom: auto;
1486 1486 left: 50%;
1487 1487 transform: translate(-50%, -50%);
1488 1488 }
1489 1489
1490 1490 body.swal2-toast-shown .swal2-container.swal2-center-end, body.swal2-toast-shown .swal2-container.swal2-center-right {
1491 1491 top: 50%;
1492 1492 right: 0;
1493 1493 bottom: auto;
1494 1494 left: auto;
1495 1495 transform: translateY(-50%);
1496 1496 }
1497 1497
1498 1498 body.swal2-toast-shown .swal2-container.swal2-bottom-start, body.swal2-toast-shown .swal2-container.swal2-bottom-left {
1499 1499 top: auto;
1500 1500 right: auto;
1501 1501 bottom: 0;
1502 1502 left: 0;
1503 1503 }
1504 1504
1505 1505 body.swal2-toast-shown .swal2-container.swal2-bottom {
1506 1506 top: auto;
1507 1507 right: auto;
1508 1508 bottom: 0;
1509 1509 left: 50%;
1510 1510 transform: translateX(-50%);
1511 1511 }
1512 1512
1513 1513 body.swal2-toast-shown .swal2-container.swal2-bottom-end, body.swal2-toast-shown .swal2-container.swal2-bottom-right {
1514 1514 top: auto;
1515 1515 right: 0;
1516 1516 bottom: 0;
1517 1517 left: auto;
1518 1518 }
1519 1519
1520 1520 body.swal2-toast-column .swal2-toast {
1521 1521 flex-direction: column;
1522 1522 align-items: stretch;
1523 1523 }
1524 1524
1525 1525 body.swal2-toast-column .swal2-toast .swal2-actions {
1526 1526 flex: 1;
1527 1527 align-self: stretch;
1528 1528 height: 2.2em;
1529 1529 margin-top: 0.3125em;
1530 1530 }
1531 1531
1532 1532 body.swal2-toast-column .swal2-toast .swal2-loading {
1533 1533 justify-content: center;
1534 1534 }
1535 1535
1536 1536 body.swal2-toast-column .swal2-toast .swal2-input {
1537 1537 height: 2em;
1538 1538 margin: 0.3125em auto;
1539 1539 font-size: 1em;
1540 1540 }
1541 1541
1542 1542 body.swal2-toast-column .swal2-toast .swal2-validation-message {
1543 1543 font-size: 1em;
1544 1544 } No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Add another comment',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': 'Delete',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Follow',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': 'Lifetime',
42 49 'Loading ...': 'Loading ...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'No matches found',
51 59 'No matching files': 'No matching files',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'No results',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': 'Not Reviewed',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': 'Open new pull request',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Please delete {0} character',
68 76 'Please delete {0} characters': 'Please delete {0} characters',
69 77 'Please enter {0} or more character': 'Please enter {0} or more character',
70 78 'Please enter {0} or more characters': 'Please enter {0} or more characters',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': 'Selection link',
75 84 'Send': 'Send',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Show more',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'Start following this repository',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': 'Stop following this repository',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': 'Submitting...',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Unfollow',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': 'disabled',
110 126 'enabled': 'enabled',
111 127 'file': 'file',
112 128 'files': 'files',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'just now',
118 134 'loading...': 'loading...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Add another comment',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': 'Löschen',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Follow',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': 'Lebensdauer',
42 49 'Loading ...': 'Loading ...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'Keine Treffer gefunden',
51 59 'No matching files': 'No matching files',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'No results',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': 'Nicht Begutachtet',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': 'Open new pull request',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Bitte {0} Zeichen löschen',
68 76 'Please delete {0} characters': 'Bitte {0} Zeichen löschen',
69 77 'Please enter {0} or more character': 'Bitte {0} oder mehr Zeichen eingeben',
70 78 'Please enter {0} or more characters': 'Bitte {0} oder mehr Zeichen eingeben',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': 'Selection link',
75 84 'Send': 'Senden',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Show more',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'Start following this repository',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': 'Stop following this repository',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': 'Submitting...',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Unfollow',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': 'disabled',
110 126 'enabled': 'enabled',
111 127 'file': 'file',
112 128 'files': 'files',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'jetzt gerade',
118 134 'loading...': 'loading...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Add another comment',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': 'Delete',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Follow',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': 'Lifetime',
42 49 'Loading ...': 'Loading ...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'No matches found',
51 59 'No matching files': 'No matching files',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'No results',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': 'Not Reviewed',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': 'Open new pull request',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Please delete {0} character',
68 76 'Please delete {0} characters': 'Please delete {0} characters',
69 77 'Please enter {0} or more character': 'Please enter {0} or more character',
70 78 'Please enter {0} or more characters': 'Please enter {0} or more characters',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': 'Selection link',
75 84 'Send': 'Send',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Show more',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'Start following this repository',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': 'Stop following this repository',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': 'Submitting...',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Unfollow',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': 'disabled',
110 126 'enabled': 'enabled',
111 127 'file': 'file',
112 128 'files': 'files',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'just now',
118 134 'loading...': 'loading...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Add another comment',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': 'Delete',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Follow',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': 'De por vida',
42 49 'Loading ...': 'Loading ...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'No matches found',
51 59 'No matching files': 'No matching files',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'No results',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': 'Not Reviewed',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': 'Open new pull request',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Please delete {0} character',
68 76 'Please delete {0} characters': 'Please delete {0} characters',
69 77 'Please enter {0} or more character': 'Please enter {0} or more character',
70 78 'Please enter {0} or more characters': 'Please enter {0} or more characters',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': 'Selection link',
75 84 'Send': 'Send',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Show more',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'Start following this repository',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': 'Stop following this repository',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': 'Submitting...',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Unfollow',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': 'disabled',
110 126 'enabled': 'enabled',
111 127 'file': 'file',
112 128 'files': 'files',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'just now',
118 134 'loading...': 'loading...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Add another comment',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': 'Supprimer',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Follow',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': 'Durée de vie',
42 49 'Loading ...': 'Loading ...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'No matches found',
51 59 'No matching files': 'No matching files',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'No results',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': 'Pas encore relue',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': 'Nouvelle requête de pull',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Please delete {0} character',
68 76 'Please delete {0} characters': 'Please delete {0} characters',
69 77 'Please enter {0} or more character': 'Please enter {0} or more character',
70 78 'Please enter {0} or more characters': 'Please enter {0} or more characters',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': 'Lien vers la sélection',
75 84 'Send': 'Envoyer',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Show more',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'Suivre ce dépôt',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': 'Arrêter de suivre ce dépôt',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': 'Envoi…',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Unfollow',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': 'Désactivé',
110 126 'enabled': 'Activé',
111 127 'file': 'file',
112 128 'files': 'Fichiers',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'à l’instant',
118 134 'loading...': 'Chargement…',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'Spécifier un commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} jours',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} heures',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} mois',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} années',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Aggiungi un altro commento',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': 'Elimina',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Segui',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': 'a vita',
42 49 'Loading ...': 'Caricamento ...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'Nessuna corrispondenza',
51 59 'No matching files': 'Nessuna corrispondenza tra i file',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'Nessun risultato',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': 'Non Revisionato',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': 'Apri una richiesta PULL',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Please delete {0} character',
68 76 'Please delete {0} characters': 'Please delete {0} characters',
69 77 'Please enter {0} or more character': 'Please enter {0} or more character',
70 78 'Please enter {0} or more characters': 'Please enter {0} or more characters',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': 'Collegamento selezione',
75 84 'Send': 'Invia',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Mostra ancora',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'Inizia a seguire il repository',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': 'Smetti di seguire il repository',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': 'Inoltro...',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'Al momento non ci sono richieste di PULL che richiedono il tuo intervento',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Smetti di seguire',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': 'disabilitato',
110 126 'enabled': 'abilitato',
111 127 'file': 'file',
112 128 'files': 'i file',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'proprio ora',
118 134 'loading...': 'loading...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': '別のコメントを追加',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': '選択したステータス ({0}) を元にコメントが自動的に設定されます...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': '削除',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'フォロー',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': '有効期間',
42 49 'Loading ...': '読み込み中...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': '読み込み失敗',
44 52 'Loading more results...': '結果を読み込み中...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'まだブックマークがありません。',
47 55 'No branches available yet.': 'まだブランチがありません。',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'まだ Gist がありません。',
50 58 'No matches found': '一致するものが見つかりません',
51 59 'No matching files': 'マッチするファイルはありません',
52 60 'No pull requests available yet.': 'まだプルリクエストがありません。',
53 61 'No repositories available yet.': 'まだリポジトリがありません。',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'まだリポジトリグループがありません。',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': '結果がありません',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'まだタグがありません。',
60 68 'No user groups available yet.': 'まだユーザーグループがありません。',
61 69 'No users available yet.': 'まだユーザーがいません。',
62 70 'Not Reviewed': '未レビュー',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': '1 件の結果があります。 Enter で選択できます。',
65 73 'Open new pull request': '新しいプルリクエストを作成',
66 74 'Open new pull request for selected commit': '選択したコミットから新しいプルリクエストを作成',
67 75 'Please delete {0} character': '{0} 文字削除してください',
68 76 'Please delete {0} characters': '{0} 文字削除してください',
69 77 'Please enter {0} or more character': '{0} 文字以上入力してください',
70 78 'Please enter {0} or more characters': '{0} 文字以上入力してください',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': '検索中...',
74 83 'Selection link': 'セレクション・リンク',
75 84 'Send': '送信',
76 85 'Set status to Approved': 'ステータスを承認にする',
77 86 'Set status to Rejected': 'ステータスを拒否にする',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'もっと表示',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'このリポジトリのフォローする',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'ステータスレビュー',
89 100 'Stop following this repository': 'このリポジトリのフォローをやめる',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': '送信中...',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'アンフォロー',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': '{0} 件のみ選択できます',
105 121 'You can only select {0} items': '{0} 件のみ選択できます',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': '無効',
110 126 'enabled': '有効',
111 127 'file': 'ファイル',
112 128 'files': 'ファイル',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'たったいま',
118 134 'loading...': '読み込み中...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': '省略された結果',
126 143 'truncated results': '省略された結果',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} 前',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} 日',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} 時間',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} 分',
138 155 '{0} month': '{0} ヶ月',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} 件の結果があります。矢印キーの上下で選択できます。',
147 164 '{0} sec': '{0} 秒',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} 年',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,146 +1,163 b''
1 1 // AUTO GENERATED FILE FOR Babel JS-GETTEXT EXTRACTORS, DO NOT CHANGE
2 2 _gettext('(from usergroup {0})');
3 _gettext('<strong>{0} file</strong> changed, ');
4 _gettext('<strong>{0} files</strong> changed, ');
3 5 _gettext('Add another comment');
4 6 _gettext('Adding new reviewers is forbidden.');
7 _gettext('Ajax Request Error');
5 8 _gettext('All Authors');
6 9 _gettext('All individual reviewers must vote.');
7 10 _gettext('All reviewers must vote.');
8 11 _gettext('Are you sure to close this pull request without merging?');
9 12 _gettext('At least {0} reviewer must vote.');
10 13 _gettext('At least {0} reviewers must vote.');
14 _gettext('Authentication Token');
11 15 _gettext('Author is not allowed to be a reviewer.');
12 16 _gettext('Changed files');
13 17 _gettext('Close');
14 18 _gettext('Collapse all files');
15 19 _gettext('Collapse {0} commit');
16 20 _gettext('Collapse {0} commits');
17 21 _gettext('Comment text will be set automatically based on currently selected status ({0}) ...');
18 22 _gettext('Commit Authors are not allowed to be a reviewer.');
19 23 _gettext('Context file: ');
24 _gettext('Delete');
20 25 _gettext('Delete this comment?');
21 26 _gettext('Diff to Commit ');
27 _gettext('Error during search operation');
22 28 _gettext('Expand all files');
23 29 _gettext('Expand {0} commit');
24 30 _gettext('Expand {0} commits');
25 31 _gettext('Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.');
26 32 _gettext('Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.');
33 _gettext('File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.');
27 34 _gettext('Follow');
28 35 _gettext('Force updating...');
29 36 _gettext('Hide full context diff');
30 37 _gettext('Hide whitespace changes');
31 38 _gettext('Invite reviewers to this discussion');
32 39 _gettext('Leave a comment on line {0}.');
33 40 _gettext('Leave a comment, or click resolve button to resolve TODO comment #{0}');
34 41 _gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}');
35 42 _gettext('Lifetime');
36 43 _gettext('Loading ...');
44 _gettext('Loading diff ...');
37 45 _gettext('Loading failed');
38 46 _gettext('Loading more results...');
39 47 _gettext('Loading...');
40 48 _gettext('No bookmarks available yet.');
41 49 _gettext('No branches available yet.');
42 50 _gettext('No forks available yet.');
43 51 _gettext('No gists available yet.');
44 52 _gettext('No matches found');
45 53 _gettext('No matching files');
46 54 _gettext('No pull requests available yet.');
47 55 _gettext('No repositories available yet.');
48 56 _gettext('No repositories present.');
49 57 _gettext('No repository groups available yet.');
50 58 _gettext('No repository groups present.');
51 59 _gettext('No results');
52 60 _gettext('No ssh keys available yet.');
53 61 _gettext('No tags available yet.');
54 62 _gettext('No user groups available yet.');
55 63 _gettext('No users available yet.');
56 64 _gettext('Not Reviewed');
57 65 _gettext('Note Comment');
58 66 _gettext('One result is available, press enter to select it.');
59 67 _gettext('Open new pull request');
60 68 _gettext('Open new pull request for selected commit');
61 69 _gettext('Please delete {0} character');
62 70 _gettext('Please delete {0} characters');
63 71 _gettext('Please enter {0} or more character');
64 72 _gettext('Please enter {0} or more characters');
73 _gettext('Please wait creating pull request...');
65 74 _gettext('Reviewers picked from source code changes.');
66 75 _gettext('Saving...');
67 76 _gettext('Searching...');
68 77 _gettext('Selection link');
69 78 _gettext('Send');
70 79 _gettext('Set status to Approved');
71 80 _gettext('Set status to Rejected');
81 _gettext('Show');
72 82 _gettext('Show at Commit ');
73 83 _gettext('Show commit range {0} ... {1}');
74 84 _gettext('Show full context diff');
75 85 _gettext('Show more');
76 86 _gettext('Show selected commit __S');
77 87 _gettext('Show selected commits __S ... __E');
88 _gettext('Show this authentication token?');
78 89 _gettext('Show whitespace changes');
79 90 _gettext('Specified expiration date');
80 91 _gettext('Start following this repository');
81 92 _gettext('Started watching this repository');
82 93 _gettext('Status Review');
83 94 _gettext('Stop following this repository');
84 95 _gettext('Stopped watching this repository');
85 96 _gettext('Submitting...');
86 97 _gettext('Switch to chat');
87 98 _gettext('Switch to comment');
88 99 _gettext('TODO comment');
89 100 _gettext('TODO from comment {0} was fixed.');
90 101 _gettext('There are currently no open pull requests requiring your participation.');
102 _gettext('There is a later version of file tree available. Click {0} to create a file at the latest tree.');
103 _gettext('There is an existing path `{0}` at this commit.');
104 _gettext('This pull requests will consist of <strong>{0} commit</strong>.');
105 _gettext('This pull requests will consist of <strong>{0} commits</strong>.');
91 106 _gettext('Toggle Wide Mode diff');
92 107 _gettext('Unfollow');
93 108 _gettext('Unwatch');
94 109 _gettext('Updating...');
95 110 _gettext('User `{0}` already in reviewers');
96 111 _gettext('User `{0}` not allowed to be a reviewer');
97 112 _gettext('Watch');
113 _gettext('Yes, delete comment #{0}!');
98 114 _gettext('You can only select {0} item');
99 115 _gettext('You can only select {0} items');
100 116 _gettext('activated');
101 117 _gettext('added manually by "{0}"');
102 118 _gettext('date not in future');
103 119 _gettext('disabled');
104 120 _gettext('enabled');
105 121 _gettext('file');
106 122 _gettext('files');
107 123 _gettext('go to numeric commit');
108 124 _gettext('in {0}');
109 125 _gettext('in {0} and {1}');
110 126 _gettext('in {0}, {1}');
111 127 _gettext('just now');
112 128 _gettext('loading...');
113 129 _gettext('member of "{0}"');
130 _gettext('no commits');
114 131 _gettext('not active');
115 132 _gettext('resolve comment');
116 133 _gettext('showing {0} out of {1} commit');
117 134 _gettext('showing {0} out of {1} commits');
118 135 _gettext('specify commit');
119 136 _gettext('truncated result');
120 137 _gettext('truncated results');
121 138 _gettext('{0} ({1} inactive) of {2} user groups ({3} inactive)');
122 139 _gettext('{0} ({1} inactive) of {2} users ({3} inactive)');
123 140 _gettext('{0} active out of {1} users');
124 141 _gettext('{0} ago');
125 142 _gettext('{0} and {1}');
126 143 _gettext('{0} and {1} ago');
127 144 _gettext('{0} day');
128 145 _gettext('{0} days');
129 146 _gettext('{0} hour');
130 147 _gettext('{0} hours');
131 148 _gettext('{0} min');
132 149 _gettext('{0} month');
133 150 _gettext('{0} months');
134 151 _gettext('{0} of {1} repositories');
135 152 _gettext('{0} of {1} repository groups');
136 153 _gettext('{0} out of {1} ssh keys');
137 154 _gettext('{0} out of {1} users');
138 155 _gettext('{0} repositories');
139 156 _gettext('{0} repository groups');
140 157 _gettext('{0} results are available, use up and down arrow keys to navigate.');
141 158 _gettext('{0} sec');
142 159 _gettext('{0} user groups ({1} inactive)');
143 160 _gettext('{0} users ({1} inactive)');
144 161 _gettext('{0} year');
145 162 _gettext('{0} years');
146 163 _gettext('{0}, {1} ago');
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Dodaj kolejny komentarz',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Zamknij',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': 'Usuń',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Obserwuj',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': 'Czas życia',
42 49 'Loading ...': 'Ładuję...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'No matches found',
51 59 'No matching files': 'Nie ma plików pasujących',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'No results',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': 'Brak Korekty',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': 'Otwórz nową prośbę o połączenie gałęzi',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Please delete {0} character',
68 76 'Please delete {0} characters': 'Please delete {0} characters',
69 77 'Please enter {0} or more character': 'Please enter {0} or more character',
70 78 'Please enter {0} or more characters': 'Please enter {0} or more characters',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': 'Wybór linku',
75 84 'Send': 'Wyślij',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Pokaż więcej',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'Zacznij obserwację tego repozytorium',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': 'Zakończyć obserwację tego repozytorium',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': 'Przesyłanie...',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Nie obserwuj',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': 'disabled',
110 126 'enabled': 'enabled',
111 127 'file': 'file',
112 128 'files': 'pliki',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'przed chwilą',
118 134 'loading...': 'wczytywanie...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} aktywnych z {1} użytkowników',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Adicionar outro comentário',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': 'Excluir',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Seguir',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': 'Tempo de Vida',
42 49 'Loading ...': 'Carregando...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'No matches found',
51 59 'No matching files': 'Nenhum arquivo encontrado',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'No results',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': 'Não Revisado',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': 'Crie novo pull request',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Please delete {0} character',
68 76 'Please delete {0} characters': 'Please delete {0} characters',
69 77 'Please enter {0} or more character': 'Please enter {0} or more character',
70 78 'Please enter {0} or more characters': 'Please enter {0} or more characters',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': 'Link da seleção',
75 84 'Send': 'Enviar',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Mostrar mais',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'Passar a seguir este repositório',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': 'Parar de seguir este repositório',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': 'Enviando...',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Parar de seguir',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': 'desabilitado',
110 126 'enabled': 'enabled',
111 127 'file': 'file',
112 128 'files': 'arquivos',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'agora há pouco',
118 134 'loading...': 'loading...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Добавить другой комментарий',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': 'Удалить',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Наблюдать',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': 'Срок',
42 49 'Loading ...': 'Загрузка...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'No matches found',
51 59 'No matching files': 'Нет совпадений',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'No results',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': 'Не просмотрено',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': 'Создать новый pull запрос',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Please delete {0} character',
68 76 'Please delete {0} characters': 'Please delete {0} characters',
69 77 'Please enter {0} or more character': 'Please enter {0} or more character',
70 78 'Please enter {0} or more characters': 'Please enter {0} or more characters',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': 'Ссылка выбора',
75 84 'Send': 'Отправить',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Показать еще',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': 'Наблюдать за репозиторием',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': 'Отменить наблюдение за репозиторием',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': 'Применение...',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Не наблюдать',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': 'отключено',
110 126 'enabled': 'enabled',
111 127 'file': 'file',
112 128 'files': 'файлы',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': 'прямо сейчас',
118 134 'loading...': 'загрузка...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,153 +1,170 b''
1 1 /* This file is automatically generated. DO NOT change it manually.
2 2 * If this file needs to be modified, edit
3 3 * rhodecode/utils/file_generation/js_i18n_data.py
4 4 * and run the script invoke -r scripts/ generate.js-i18n .
5 5 */
6 6 //JS translations map
7 7 var _TM = {
8 8 '(from usergroup {0})': '(from usergroup {0})',
9 '<strong>{0} file</strong> changed, ': '<strong>{0} file</strong> changed, ',
10 '<strong>{0} files</strong> changed, ': '<strong>{0} files</strong> changed, ',
9 11 'Add another comment': 'Add another comment',
10 12 'Adding new reviewers is forbidden.': 'Adding new reviewers is forbidden.',
13 'Ajax Request Error': 'Ajax Request Error',
11 14 'All Authors': 'All Authors',
12 15 'All individual reviewers must vote.': 'All individual reviewers must vote.',
13 16 'All reviewers must vote.': 'All reviewers must vote.',
14 17 'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
15 18 'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
16 19 'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
20 'Authentication Token': 'Authentication Token',
17 21 'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
18 22 'Changed files': 'Changed files',
19 23 'Close': 'Close',
20 24 'Collapse all files': 'Collapse all files',
21 25 'Collapse {0} commit': 'Collapse {0} commit',
22 26 'Collapse {0} commits': 'Collapse {0} commits',
23 27 'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
24 28 'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
25 29 'Context file: ': 'Context file: ',
30 'Delete': '删除',
26 31 'Delete this comment?': 'Delete this comment?',
27 32 'Diff to Commit ': 'Diff to Commit ',
33 'Error during search operation': 'Error during search operation',
28 34 'Expand all files': 'Expand all files',
29 35 'Expand {0} commit': 'Expand {0} commit',
30 36 'Expand {0} commits': 'Expand {0} commits',
31 37 '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.',
32 38 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
39 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.': 'File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.',
33 40 'Follow': 'Follow',
34 41 'Force updating...': 'Force updating...',
35 42 'Hide full context diff': 'Hide full context diff',
36 43 'Hide whitespace changes': 'Hide whitespace changes',
37 44 'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
38 45 'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
39 46 '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 47 '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}',
41 48 'Lifetime': '终身',
42 49 'Loading ...': 'Loading ...',
50 'Loading diff ...': 'Loading diff ...',
43 51 'Loading failed': 'Loading failed',
44 52 'Loading more results...': 'Loading more results...',
45 53 'Loading...': 'Loading...',
46 54 'No bookmarks available yet.': 'No bookmarks available yet.',
47 55 'No branches available yet.': 'No branches available yet.',
48 56 'No forks available yet.': 'No forks available yet.',
49 57 'No gists available yet.': 'No gists available yet.',
50 58 'No matches found': 'No matches found',
51 59 'No matching files': 'No matching files',
52 60 'No pull requests available yet.': 'No pull requests available yet.',
53 61 'No repositories available yet.': 'No repositories available yet.',
54 62 'No repositories present.': 'No repositories present.',
55 63 'No repository groups available yet.': 'No repository groups available yet.',
56 64 'No repository groups present.': 'No repository groups present.',
57 65 'No results': 'No results',
58 66 'No ssh keys available yet.': 'No ssh keys available yet.',
59 67 'No tags available yet.': 'No tags available yet.',
60 68 'No user groups available yet.': 'No user groups available yet.',
61 69 'No users available yet.': 'No users available yet.',
62 70 'Not Reviewed': '未检视',
63 71 'Note Comment': 'Note Comment',
64 72 'One result is available, press enter to select it.': 'One result is available, press enter to select it.',
65 73 'Open new pull request': '新建拉取请求',
66 74 'Open new pull request for selected commit': 'Open new pull request for selected commit',
67 75 'Please delete {0} character': 'Please delete {0} character',
68 76 'Please delete {0} characters': 'Please delete {0} characters',
69 77 'Please enter {0} or more character': 'Please enter {0} or more character',
70 78 'Please enter {0} or more characters': 'Please enter {0} or more characters',
79 'Please wait creating pull request...': 'Please wait creating pull request...',
71 80 'Reviewers picked from source code changes.': 'Reviewers picked from source code changes.',
72 81 'Saving...': 'Saving...',
73 82 'Searching...': 'Searching...',
74 83 'Selection link': '选择链接',
75 84 'Send': '发送',
76 85 'Set status to Approved': 'Set status to Approved',
77 86 'Set status to Rejected': 'Set status to Rejected',
87 'Show': 'Show',
78 88 'Show at Commit ': 'Show at Commit ',
79 89 'Show commit range {0} ... {1}': 'Show commit range {0} ... {1}',
80 90 'Show full context diff': 'Show full context diff',
81 91 'Show more': 'Show more',
82 92 'Show selected commit __S': 'Show selected commit __S',
83 93 'Show selected commits __S ... __E': 'Show selected commits __S ... __E',
94 'Show this authentication token?': 'Show this authentication token?',
84 95 'Show whitespace changes': 'Show whitespace changes',
85 96 'Specified expiration date': 'Specified expiration date',
86 97 'Start following this repository': '开始关注该版本库',
87 98 'Started watching this repository': 'Started watching this repository',
88 99 'Status Review': 'Status Review',
89 100 'Stop following this repository': '停止关注该版本库',
90 101 'Stopped watching this repository': 'Stopped watching this repository',
91 102 'Submitting...': '提交中……',
92 103 'Switch to chat': 'Switch to chat',
93 104 'Switch to comment': 'Switch to comment',
94 105 'TODO comment': 'TODO comment',
95 106 'TODO from comment {0} was fixed.': 'TODO from comment {0} was fixed.',
96 107 'There are currently no open pull requests requiring your participation.': 'There are currently no open pull requests requiring your participation.',
108 'There is a later version of file tree available. Click {0} to create a file at the latest tree.': 'There is a later version of file tree available. Click {0} to create a file at the latest tree.',
109 'There is an existing path `{0}` at this commit.': 'There is an existing path `{0}` at this commit.',
110 'This pull requests will consist of <strong>{0} commit</strong>.': 'This pull requests will consist of <strong>{0} commit</strong>.',
111 'This pull requests will consist of <strong>{0} commits</strong>.': 'This pull requests will consist of <strong>{0} commits</strong>.',
97 112 'Toggle Wide Mode diff': 'Toggle Wide Mode diff',
98 113 'Unfollow': 'Unfollow',
99 114 'Unwatch': 'Unwatch',
100 115 'Updating...': 'Updating...',
101 116 'User `{0}` already in reviewers': 'User `{0}` already in reviewers',
102 117 'User `{0}` not allowed to be a reviewer': 'User `{0}` not allowed to be a reviewer',
103 118 'Watch': 'Watch',
119 'Yes, delete comment #{0}!': 'Yes, delete comment #{0}!',
104 120 'You can only select {0} item': 'You can only select {0} item',
105 121 'You can only select {0} items': 'You can only select {0} items',
106 122 'activated': 'activated',
107 123 'added manually by "{0}"': 'added manually by "{0}"',
108 124 'date not in future': 'date not in future',
109 125 'disabled': '禁用',
110 126 'enabled': 'enabled',
111 127 'file': 'file',
112 128 'files': '文件',
113 129 'go to numeric commit': 'go to numeric commit',
114 130 'in {0}': 'in {0}',
115 131 'in {0} and {1}': 'in {0} and {1}',
116 132 'in {0}, {1}': 'in {0}, {1}',
117 133 'just now': '刚刚',
118 134 'loading...': 'loading...',
119 135 'member of "{0}"': 'member of "{0}"',
136 'no commits': 'no commits',
120 137 'not active': 'not active',
121 138 'resolve comment': 'resolve comment',
122 139 'showing {0} out of {1} commit': 'showing {0} out of {1} commit',
123 140 'showing {0} out of {1} commits': 'showing {0} out of {1} commits',
124 141 'specify commit': 'specify commit',
125 142 'truncated result': 'truncated result',
126 143 'truncated results': 'truncated results',
127 144 '{0} ({1} inactive) of {2} user groups ({3} inactive)': '{0} ({1} inactive) of {2} user groups ({3} inactive)',
128 145 '{0} ({1} inactive) of {2} users ({3} inactive)': '{0} ({1} inactive) of {2} users ({3} inactive)',
129 146 '{0} active out of {1} users': '{0} active out of {1} users',
130 147 '{0} ago': '{0} ago',
131 148 '{0} and {1}': '{0} and {1}',
132 149 '{0} and {1} ago': '{0} and {1} ago',
133 150 '{0} day': '{0} day',
134 151 '{0} days': '{0} days',
135 152 '{0} hour': '{0} hour',
136 153 '{0} hours': '{0} hours',
137 154 '{0} min': '{0} min',
138 155 '{0} month': '{0} month',
139 156 '{0} months': '{0} months',
140 157 '{0} of {1} repositories': '{0} of {1} repositories',
141 158 '{0} of {1} repository groups': '{0} of {1} repository groups',
142 159 '{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
143 160 '{0} out of {1} users': '{0} out of {1} users',
144 161 '{0} repositories': '{0} repositories',
145 162 '{0} repository groups': '{0} repository groups',
146 163 '{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
147 164 '{0} sec': '{0} sec',
148 165 '{0} user groups ({1} inactive)': '{0} user groups ({1} inactive)',
149 166 '{0} users ({1} inactive)': '{0} users ({1} inactive)',
150 167 '{0} year': '{0} year',
151 168 '{0} years': '{0} years',
152 169 '{0}, {1} ago': '{0}, {1} ago'
153 170 }; No newline at end of file
@@ -1,1201 +1,1210 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 <%!
4 4 ## base64 filter e.g ${ example | base64 }
5 5 def base64(text):
6 6 import base64
7 7 from rhodecode.lib.helpers import safe_str
8 8 return base64.encodestring(safe_str(text))
9 9 %>
10 10
11 11 <%inherit file="root.mako"/>
12 12
13 13 <%include file="/ejs_templates/templates.html"/>
14 14
15 15 <div class="outerwrapper">
16 16 <!-- HEADER -->
17 17 <div class="header">
18 18 <div id="header-inner" class="wrapper">
19 19 <div id="logo">
20 20 <div class="logo-wrapper">
21 21 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
22 22 </div>
23 23 % if c.rhodecode_name:
24 24 <div class="branding">
25 25 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
26 26 </div>
27 27 % endif
28 28 </div>
29 29 <!-- MENU BAR NAV -->
30 30 ${self.menu_bar_nav()}
31 31 <!-- END MENU BAR NAV -->
32 32 </div>
33 33 </div>
34 34 ${self.menu_bar_subnav()}
35 35 <!-- END HEADER -->
36 36
37 37 <!-- CONTENT -->
38 38 <div id="content" class="wrapper">
39 39
40 40 <rhodecode-toast id="notifications"></rhodecode-toast>
41 41
42 42 <div class="main">
43 43 ${next.main()}
44 44 </div>
45 45 </div>
46 46 <!-- END CONTENT -->
47 47
48 48 </div>
49 49 <!-- FOOTER -->
50 50 <div id="footer">
51 51 <div id="footer-inner" class="title wrapper">
52 52 <div>
53 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
54
53 55 <p class="footer-link-right">
56 <a class="grey-link-action" href="${h.route_path('home', _query={'showrcid': 1})}">
57 RhodeCode
54 58 % if c.visual.show_version:
55 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
59 ${c.rhodecode_version}
56 60 % endif
57 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
61 ${c.rhodecode_edition}
62 </a> |
63
58 64 % if c.visual.rhodecode_support_url:
59 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
65 <a class="grey-link-action" href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a> |
66 <a class="grey-link-action" href="https://docs.rhodecode.com" target="_blank">${_('Documentation')}</a>
60 67 % endif
68
61 69 </p>
62 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
70
63 71 <p class="server-instance" style="display:${sid}">
64 72 ## display hidden instance ID if specially defined
73 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
65 74 % if c.rhodecode_instanceid:
66 75 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
67 76 % endif
68 77 </p>
69 78 </div>
70 79 </div>
71 80 </div>
72 81
73 82 <!-- END FOOTER -->
74 83
75 84 ### MAKO DEFS ###
76 85
77 86 <%def name="menu_bar_subnav()">
78 87 </%def>
79 88
80 89 <%def name="breadcrumbs(class_='breadcrumbs')">
81 90 <div class="${class_}">
82 91 ${self.breadcrumbs_links()}
83 92 </div>
84 93 </%def>
85 94
86 95 <%def name="admin_menu(active=None)">
87 96
88 97 <div id="context-bar">
89 98 <div class="wrapper">
90 99 <div class="title">
91 100 <div class="title-content">
92 101 <div class="title-main">
93 102 % if c.is_super_admin:
94 103 ${_('Super-admin Panel')}
95 104 % else:
96 105 ${_('Delegated Admin Panel')}
97 106 % endif
98 107 </div>
99 108 </div>
100 109 </div>
101 110
102 111 <ul id="context-pages" class="navigation horizontal-list">
103 112
104 113 ## super-admin case
105 114 % if c.is_super_admin:
106 115 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
107 116 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
108 117 <li class="${h.is_active('repository_groups', active)}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
109 118 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
110 119 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
111 120 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
112 121 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
113 122 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
114 123 <li class="${h.is_active('defaults', active)}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
115 124 <li class="${h.is_active('settings', active)}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
116 125
117 126 ## delegated admin
118 127 % elif c.is_delegated_admin:
119 128 <%
120 129 repositories=c.auth_user.repositories_admin or c.can_create_repo
121 130 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
122 131 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
123 132 %>
124 133
125 134 %if repositories:
126 135 <li class="${h.is_active('repositories', active)} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
127 136 %endif
128 137 %if repository_groups:
129 138 <li class="${h.is_active('repository_groups', active)} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
130 139 %endif
131 140 %if user_groups:
132 141 <li class="${h.is_active('user_groups', active)} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
133 142 %endif
134 143 % endif
135 144 </ul>
136 145
137 146 </div>
138 147 <div class="clear"></div>
139 148 </div>
140 149 </%def>
141 150
142 151 <%def name="dt_info_panel(elements)">
143 152 <dl class="dl-horizontal">
144 153 %for dt, dd, title, show_items in elements:
145 154 <dt>${dt}:</dt>
146 155 <dd title="${h.tooltip(title)}">
147 156 %if callable(dd):
148 157 ## allow lazy evaluation of elements
149 158 ${dd()}
150 159 %else:
151 160 ${dd}
152 161 %endif
153 162 %if show_items:
154 163 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
155 164 %endif
156 165 </dd>
157 166
158 167 %if show_items:
159 168 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
160 169 %for item in show_items:
161 170 <dt></dt>
162 171 <dd>${item}</dd>
163 172 %endfor
164 173 </div>
165 174 %endif
166 175
167 176 %endfor
168 177 </dl>
169 178 </%def>
170 179
171 180 <%def name="tr_info_entry(element)">
172 181 <% key, val, title, show_items = element %>
173 182
174 183 <tr>
175 184 <td style="vertical-align: top">${key}</td>
176 185 <td title="${h.tooltip(title)}">
177 186 %if callable(val):
178 187 ## allow lazy evaluation of elements
179 188 ${val()}
180 189 %else:
181 190 ${val}
182 191 %endif
183 192 %if show_items:
184 193 <div class="collapsable-content" data-toggle="item-${h.md5_safe(val)[:6]}-details" style="display: none">
185 194 % for item in show_items:
186 195 <dt></dt>
187 196 <dd>${item}</dd>
188 197 % endfor
189 198 </div>
190 199 %endif
191 200 </td>
192 201 <td style="vertical-align: top">
193 202 %if show_items:
194 203 <span class="btn-collapse" data-toggle="item-${h.md5_safe(val)[:6]}-details">${_('Show More')} </span>
195 204 %endif
196 205 </td>
197 206 </tr>
198 207
199 208 </%def>
200 209
201 210 <%def name="gravatar(email, size=16, tooltip=False, tooltip_alt=None, user=None, extra_class=None)">
202 211 <%
203 212 if size > 16:
204 213 gravatar_class = ['gravatar','gravatar-large']
205 214 else:
206 215 gravatar_class = ['gravatar']
207 216
208 217 data_hovercard_url = ''
209 218 data_hovercard_alt = tooltip_alt.replace('<', '&lt;').replace('>', '&gt;') if tooltip_alt else ''
210 219
211 220 if tooltip:
212 221 gravatar_class += ['tooltip-hovercard']
213 222 if extra_class:
214 223 gravatar_class += extra_class
215 224 if tooltip and user:
216 225 if user.username == h.DEFAULT_USER:
217 226 gravatar_class.pop(-1)
218 227 else:
219 228 data_hovercard_url = request.route_path('hovercard_user', user_id=getattr(user, 'user_id', ''))
220 229 gravatar_class = ' '.join(gravatar_class)
221 230
222 231 %>
223 232 <%doc>
224 233 TODO: johbo: For now we serve double size images to make it smooth
225 234 for retina. This is how it worked until now. Should be replaced
226 235 with a better solution at some point.
227 236 </%doc>
228 237
229 238 <img class="${gravatar_class}" height="${size}" width="${size}" data-hovercard-url="${data_hovercard_url}" data-hovercard-alt="${data_hovercard_alt}" src="${h.gravatar_url(email, size * 2)}" />
230 239 </%def>
231 240
232 241
233 242 <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False, _class='rc-user')">
234 243 <%
235 244 email = h.email_or_none(contact)
236 245 rc_user = h.discover_user(contact)
237 246 %>
238 247
239 248 <div class="${_class}">
240 249 ${self.gravatar(email, size, tooltip=tooltip, tooltip_alt=contact, user=rc_user)}
241 250 <span class="${('user user-disabled' if show_disabled else 'user')}"> ${h.link_to_user(rc_user or contact)}</span>
242 251 </div>
243 252 </%def>
244 253
245 254
246 255 <%def name="user_group_icon(user_group=None, size=16, tooltip=False)">
247 256 <%
248 257 if (size > 16):
249 258 gravatar_class = 'icon-user-group-alt'
250 259 else:
251 260 gravatar_class = 'icon-user-group-alt'
252 261
253 262 if tooltip:
254 263 gravatar_class += ' tooltip-hovercard'
255 264
256 265 data_hovercard_url = request.route_path('hovercard_user_group', user_group_id=user_group.users_group_id)
257 266 %>
258 267 <%doc>
259 268 TODO: johbo: For now we serve double size images to make it smooth
260 269 for retina. This is how it worked until now. Should be replaced
261 270 with a better solution at some point.
262 271 </%doc>
263 272
264 273 <i style="font-size: ${size}px" class="${gravatar_class} x-icon-size-${size}" data-hovercard-url="${data_hovercard_url}"></i>
265 274 </%def>
266 275
267 276 <%def name="repo_page_title(repo_instance)">
268 277 <div class="title-content repo-title">
269 278
270 279 <div class="title-main">
271 280 ## SVN/HG/GIT icons
272 281 %if h.is_hg(repo_instance):
273 282 <i class="icon-hg"></i>
274 283 %endif
275 284 %if h.is_git(repo_instance):
276 285 <i class="icon-git"></i>
277 286 %endif
278 287 %if h.is_svn(repo_instance):
279 288 <i class="icon-svn"></i>
280 289 %endif
281 290
282 291 ## public/private
283 292 %if repo_instance.private:
284 293 <i class="icon-repo-private"></i>
285 294 %else:
286 295 <i class="icon-repo-public"></i>
287 296 %endif
288 297
289 298 ## repo name with group name
290 299 ${h.breadcrumb_repo_link(repo_instance)}
291 300
292 301 ## Context Actions
293 302 <div class="pull-right">
294 303 %if c.rhodecode_user.username != h.DEFAULT_USER:
295 304 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
296 305
297 306 <a href="#WatchRepo" onclick="toggleFollowingRepo(this, templateContext.repo_id); return false" title="${_('Watch this Repository and actions on it in your personalized journal')}" class="btn btn-sm ${('watching' if c.repository_is_user_following else '')}">
298 307 % if c.repository_is_user_following:
299 308 <i class="icon-eye-off"></i>${_('Unwatch')}
300 309 % else:
301 310 <i class="icon-eye"></i>${_('Watch')}
302 311 % endif
303 312
304 313 </a>
305 314 %else:
306 315 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid)}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
307 316 %endif
308 317 </div>
309 318
310 319 </div>
311 320
312 321 ## FORKED
313 322 %if repo_instance.fork:
314 323 <p class="discreet">
315 324 <i class="icon-code-fork"></i> ${_('Fork of')}
316 325 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
317 326 </p>
318 327 %endif
319 328
320 329 ## IMPORTED FROM REMOTE
321 330 %if repo_instance.clone_uri:
322 331 <p class="discreet">
323 332 <i class="icon-code-fork"></i> ${_('Clone from')}
324 333 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
325 334 </p>
326 335 %endif
327 336
328 337 ## LOCKING STATUS
329 338 %if repo_instance.locked[0]:
330 339 <p class="locking_locked discreet">
331 340 <i class="icon-repo-lock"></i>
332 341 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
333 342 </p>
334 343 %elif repo_instance.enable_locking:
335 344 <p class="locking_unlocked discreet">
336 345 <i class="icon-repo-unlock"></i>
337 346 ${_('Repository not locked. Pull repository to lock it.')}
338 347 </p>
339 348 %endif
340 349
341 350 </div>
342 351 </%def>
343 352
344 353 <%def name="repo_menu(active=None)">
345 354 <%
346 355 ## determine if we have "any" option available
347 356 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
348 357 has_actions = can_lock
349 358
350 359 %>
351 360 % if c.rhodecode_db_repo.archived:
352 361 <div class="alert alert-warning text-center">
353 362 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
354 363 </div>
355 364 % endif
356 365
357 366 <!--- REPO CONTEXT BAR -->
358 367 <div id="context-bar">
359 368 <div class="wrapper">
360 369
361 370 <div class="title">
362 371 ${self.repo_page_title(c.rhodecode_db_repo)}
363 372 </div>
364 373
365 374 <ul id="context-pages" class="navigation horizontal-list">
366 <li class="${h.is_active('summary', active)}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
375 <li class="${h.is_active('summary', active)}"><a class="menulink" href="${h.route_path('repo_summary_explicit', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
367 376 <li class="${h.is_active('commits', active)}"><a class="menulink" href="${h.route_path('repo_commits', repo_name=c.repo_name)}"><div class="menulabel">${_('Commits')}</div></a></li>
368 <li class="${h.is_active('files', active)}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
377 <li class="${h.is_active('files', active)}"><a class="menulink" href="${h.repo_files_by_ref_url(c.repo_name, c.rhodecode_db_repo.repo_type, f_path='', ref_name=c.rhodecode_db_repo.landing_ref_name, commit_id='tip', query={'at':c.rhodecode_db_repo.landing_ref_name})}"><div class="menulabel">${_('Files')}</div></a></li>
369 378 <li class="${h.is_active('compare', active)}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
370 379
371 380 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
372 381 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
373 382 <li class="${h.is_active('showpullrequest', active)}">
374 383 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
375 384 <div class="menulabel">
376 385 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
377 386 </div>
378 387 </a>
379 388 </li>
380 389 %endif
381 390
382 391 <li class="${h.is_active('artifacts', active)}">
383 392 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
384 393 <div class="menulabel">
385 394 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
386 395 </div>
387 396 </a>
388 397 </li>
389 398
390 399 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
391 400 <li class="${h.is_active('settings', active)}"><a class="menulink" href="${h.route_path('edit_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Repository Settings')}</div></a></li>
392 401 %endif
393 402
394 403 <li class="${h.is_active('options', active)}">
395 404 % if has_actions:
396 405 <a class="menulink dropdown">
397 406 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
398 407 </a>
399 408 <ul class="submenu">
400 409 %if can_lock:
401 410 %if c.rhodecode_db_repo.locked[0]:
402 411 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
403 412 %else:
404 413 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
405 414 %endif
406 415 %endif
407 416 </ul>
408 417 % endif
409 418 </li>
410 419
411 420 </ul>
412 421 </div>
413 422 <div class="clear"></div>
414 423 </div>
415 424
416 425 <!--- REPO END CONTEXT BAR -->
417 426
418 427 </%def>
419 428
420 429 <%def name="repo_group_page_title(repo_group_instance)">
421 430 <div class="title-content">
422 431 <div class="title-main">
423 432 ## Repository Group icon
424 433 <i class="icon-repo-group"></i>
425 434
426 435 ## repo name with group name
427 436 ${h.breadcrumb_repo_group_link(repo_group_instance)}
428 437 </div>
429 438
430 439 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
431 440 <div class="repo-group-desc discreet">
432 441 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
433 442 </div>
434 443
435 444 </div>
436 445 </%def>
437 446
438 447
439 448 <%def name="repo_group_menu(active=None)">
440 449 <%
441 450 gr_name = c.repo_group.group_name if c.repo_group else None
442 451 # create repositories with write permission on group is set to true
443 452 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
444 453
445 454 %>
446 455
447 456
448 457 <!--- REPO GROUP CONTEXT BAR -->
449 458 <div id="context-bar">
450 459 <div class="wrapper">
451 460 <div class="title">
452 461 ${self.repo_group_page_title(c.repo_group)}
453 462 </div>
454 463
455 464 <ul id="context-pages" class="navigation horizontal-list">
456 465 <li class="${h.is_active('home', active)}">
457 466 <a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a>
458 467 </li>
459 468 % if c.is_super_admin or group_admin:
460 469 <li class="${h.is_active('settings', active)}">
461 470 <a class="menulink" href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}"><div class="menulabel">${_('Group Settings')}</div></a>
462 471 </li>
463 472 % endif
464 473
465 474 </ul>
466 475 </div>
467 476 <div class="clear"></div>
468 477 </div>
469 478
470 479 <!--- REPO GROUP CONTEXT BAR -->
471 480
472 481 </%def>
473 482
474 483
475 484 <%def name="usermenu(active=False)">
476 485 <%
477 486 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
478 487
479 488 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
480 489 # create repositories with write permission on group is set to true
481 490
482 491 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
483 492 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
484 493 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
485 494 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
486 495
487 496 can_create_repos = c.is_super_admin or c.can_create_repo
488 497 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
489 498
490 499 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
491 500 can_create_repo_groups_in_group = c.is_super_admin or group_admin
492 501 %>
493 502
494 503 % if not_anonymous:
495 504 <%
496 505 default_target_group = dict()
497 506 if c.rhodecode_user.personal_repo_group:
498 507 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
499 508 %>
500 509
501 510 ## create action
502 511 <li>
503 512 <a href="#create-actions" onclick="return false;" class="menulink childs">
504 513 <i class="tooltip icon-plus-circled" title="${_('Create')}"></i>
505 514 </a>
506 515
507 516 <div class="action-menu submenu">
508 517
509 518 <ol>
510 519 ## scope of within a repository
511 520 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
512 521 <li class="submenu-title">${_('This Repository')}</li>
513 522 <li>
514 523 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
515 524 </li>
516 525 % if can_fork:
517 526 <li>
518 527 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
519 528 </li>
520 529 % endif
521 530 % endif
522 531
523 532 ## scope of within repository groups
524 533 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
525 534 <li class="submenu-title">${_('This Repository Group')}</li>
526 535
527 536 % if can_create_repos_in_group:
528 537 <li>
529 538 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository')}</a>
530 539 </li>
531 540 % endif
532 541
533 542 % if can_create_repo_groups_in_group:
534 543 <li>
535 544 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
536 545 </li>
537 546 % endif
538 547 % endif
539 548
540 549 ## personal group
541 550 % if c.rhodecode_user.personal_repo_group:
542 551 <li class="submenu-title">Personal Group</li>
543 552
544 553 <li>
545 554 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
546 555 </li>
547 556
548 557 <li>
549 558 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
550 559 </li>
551 560 % endif
552 561
553 562 ## Global actions
554 563 <li class="submenu-title">RhodeCode</li>
555 564 % if can_create_repos:
556 565 <li>
557 566 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
558 567 </li>
559 568 % endif
560 569
561 570 % if can_create_repo_groups:
562 571 <li>
563 572 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
564 573 </li>
565 574 % endif
566 575
567 576 <li>
568 577 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
569 578 </li>
570 579
571 580 </ol>
572 581
573 582 </div>
574 583 </li>
575 584
576 585 ## notifications
577 586 <li>
578 587 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
579 588 ${c.unread_notifications}
580 589 </a>
581 590 </li>
582 591 % endif
583 592
584 593 ## USER MENU
585 594 <li id="quick_login_li" class="${'active' if active else ''}">
586 595 % if c.rhodecode_user.username == h.DEFAULT_USER:
587 596 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
588 597 ${gravatar(c.rhodecode_user.email, 20)}
589 598 <span class="user">
590 599 <span>${_('Sign in')}</span>
591 600 </span>
592 601 </a>
593 602 % else:
594 603 ## logged in user
595 604 <a id="quick_login_link" class="menulink childs">
596 605 ${gravatar(c.rhodecode_user.email, 20)}
597 606 <span class="user">
598 607 <span class="menu_link_user">${c.rhodecode_user.username}</span>
599 608 <div class="show_more"></div>
600 609 </span>
601 610 </a>
602 611 ## subnav with menu for logged in user
603 612 <div class="user-menu submenu">
604 613 <div id="quick_login">
605 614 %if c.rhodecode_user.username != h.DEFAULT_USER:
606 615 <div class="">
607 616 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
608 617 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
609 618 <div class="email">${c.rhodecode_user.email}</div>
610 619 </div>
611 620 <div class="">
612 621 <ol class="links">
613 622 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
614 623 % if c.rhodecode_user.personal_repo_group:
615 624 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
616 625 % endif
617 626 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
618 627
619 628 % if c.debug_style:
620 629 <li>
621 630 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
622 631 <div class="menulabel">${_('[Style]')}</div>
623 632 </a>
624 633 </li>
625 634 % endif
626 635
627 636 ## bookmark-items
628 637 <li class="bookmark-items">
629 638 ${_('Bookmarks')}
630 639 <div class="pull-right">
631 640 <a href="${h.route_path('my_account_bookmarks')}">
632 641
633 642 <i class="icon-cog"></i>
634 643 </a>
635 644 </div>
636 645 </li>
637 646 % if not c.bookmark_items:
638 647 <li>
639 648 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
640 649 </li>
641 650 % endif
642 651 % for item in c.bookmark_items:
643 652 <li>
644 653 % if item.repository:
645 654 <div>
646 655 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
647 656 <code>${item.position}</code>
648 657 % if item.repository.repo_type == 'hg':
649 658 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
650 659 % elif item.repository.repo_type == 'git':
651 660 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
652 661 % elif item.repository.repo_type == 'svn':
653 662 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
654 663 % endif
655 664 ${(item.title or h.shorter(item.repository.repo_name, 30))}
656 665 </a>
657 666 </div>
658 667 % elif item.repository_group:
659 668 <div>
660 669 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
661 670 <code>${item.position}</code>
662 671 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
663 672 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
664 673 </a>
665 674 </div>
666 675 % else:
667 676 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
668 677 <code>${item.position}</code>
669 678 ${item.title}
670 679 </a>
671 680 % endif
672 681 </li>
673 682 % endfor
674 683
675 684 <li class="logout">
676 685 ${h.secure_form(h.route_path('logout'), request=request)}
677 686 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
678 687 ${h.end_form()}
679 688 </li>
680 689 </ol>
681 690 </div>
682 691 %endif
683 692 </div>
684 693 </div>
685 694
686 695 % endif
687 696 </li>
688 697 </%def>
689 698
690 699 <%def name="menu_items(active=None)">
691 700 <%
692 701 notice_messages, notice_level = c.rhodecode_user.get_notice_messages()
693 702 notice_display = 'none' if len(notice_messages) == 0 else ''
694 703 %>
695 704 <style>
696 705
697 706 </style>
698 707
699 708 <ul id="quick" class="main_nav navigation horizontal-list">
700 709 ## notice box for important system messages
701 710 <li style="display: ${notice_display}">
702 711 <a class="notice-box" href="#openNotice" onclick="$('.notice-messages-container').toggle(); return false">
703 712 <div class="menulabel-notice ${notice_level}" >
704 713 ${len(notice_messages)}
705 714 </div>
706 715 </a>
707 716 </li>
708 717 <div class="notice-messages-container" style="display: none">
709 718 <div class="notice-messages">
710 719 <table class="rctable">
711 720 % for notice in notice_messages:
712 721 <tr id="notice-message-${notice['msg_id']}" class="notice-message-${notice['level']}">
713 722 <td style="vertical-align: text-top; width: 20px">
714 723 <i class="tooltip icon-info notice-color-${notice['level']}" title="${notice['level']}"></i>
715 724 </td>
716 725 <td>
717 726 <span><i class="icon-plus-squared cursor-pointer" onclick="$('#notice-${notice['msg_id']}').toggle()"></i> </span>
718 727 ${notice['subject']}
719 728
720 729 <div id="notice-${notice['msg_id']}" style="display: none">
721 730 ${h.render(notice['body'], renderer='markdown')}
722 731 </div>
723 732 </td>
724 733 <td style="vertical-align: text-top; width: 35px;">
725 734 <a class="tooltip" title="${_('dismiss')}" href="#dismiss" onclick="dismissNotice(${notice['msg_id']});return false">
726 735 <i class="icon-remove icon-filled-red"></i>
727 736 </a>
728 737 </td>
729 738 </tr>
730 739
731 740 % endfor
732 741 </table>
733 742 </div>
734 743 </div>
735 744 ## Main filter
736 745 <li>
737 746 <div class="menulabel main_filter_box">
738 747 <div class="main_filter_input_box">
739 748 <ul class="searchItems">
740 749
741 750 <li class="searchTag searchTagIcon">
742 751 <i class="icon-search"></i>
743 752 </li>
744 753
745 754 % if c.template_context['search_context']['repo_id']:
746 755 <li class="searchTag searchTagFilter searchTagHidable" >
747 756 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
748 757 <span class="tag">
749 758 This repo
750 759 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
751 760 </span>
752 761 ##</a>
753 762 </li>
754 763 % elif c.template_context['search_context']['repo_group_id']:
755 764 <li class="searchTag searchTagFilter searchTagHidable">
756 765 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
757 766 <span class="tag">
758 767 This group
759 768 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
760 769 </span>
761 770 ##</a>
762 771 </li>
763 772 % endif
764 773
765 774 <li class="searchTagInput">
766 775 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
767 776 </li>
768 777 <li class="searchTag searchTagHelp">
769 778 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
770 779 </li>
771 780 </ul>
772 781 </div>
773 782 </div>
774 783
775 784 <div id="main_filter_help" style="display: none">
776 785 - Use '/' key to quickly access this field.
777 786
778 787 - Enter a name of repository, or repository group for quick search.
779 788
780 789 - Prefix query to allow special search:
781 790
782 791 user:admin, to search for usernames, always global
783 792
784 793 user_group:devops, to search for user groups, always global
785 794
786 795 pr:303, to search for pull request number, title, or description, always global
787 796
788 797 commit:efced4, to search for commits, scoped to repositories or groups
789 798
790 799 file:models.py, to search for file paths, scoped to repositories or groups
791 800
792 801 % if c.template_context['search_context']['repo_id']:
793 802 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
794 803 % elif c.template_context['search_context']['repo_group_id']:
795 804 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
796 805 % else:
797 806 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
798 807 % endif
799 808 </div>
800 809 </li>
801 810
802 811 ## ROOT MENU
803 812 <li class="${h.is_active('home', active)}">
804 813 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
805 814 <div class="menulabel">${_('Home')}</div>
806 815 </a>
807 816 </li>
808 817
809 818 %if c.rhodecode_user.username != h.DEFAULT_USER:
810 819 <li class="${h.is_active('journal', active)}">
811 820 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
812 821 <div class="menulabel">${_('Journal')}</div>
813 822 </a>
814 823 </li>
815 824 %else:
816 825 <li class="${h.is_active('journal', active)}">
817 826 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
818 827 <div class="menulabel">${_('Public journal')}</div>
819 828 </a>
820 829 </li>
821 830 %endif
822 831
823 832 <li class="${h.is_active('gists', active)}">
824 833 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
825 834 <div class="menulabel">${_('Gists')}</div>
826 835 </a>
827 836 </li>
828 837
829 838 % if c.is_super_admin or c.is_delegated_admin:
830 839 <li class="${h.is_active('admin', active)}">
831 840 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
832 841 <div class="menulabel">${_('Admin')} </div>
833 842 </a>
834 843 </li>
835 844 % endif
836 845
837 846 ## render extra user menu
838 847 ${usermenu(active=(active=='my_account'))}
839 848
840 849 </ul>
841 850
842 851 <script type="text/javascript">
843 852 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
844 853
845 854 var formatRepoResult = function(result, container, query, escapeMarkup) {
846 855 return function(data, escapeMarkup) {
847 856 if (!data.repo_id){
848 857 return data.text; // optgroup text Repositories
849 858 }
850 859
851 860 var tmpl = '';
852 861 var repoType = data['repo_type'];
853 862 var repoName = data['text'];
854 863
855 864 if(data && data.type == 'repo'){
856 865 if(repoType === 'hg'){
857 866 tmpl += '<i class="icon-hg"></i> ';
858 867 }
859 868 else if(repoType === 'git'){
860 869 tmpl += '<i class="icon-git"></i> ';
861 870 }
862 871 else if(repoType === 'svn'){
863 872 tmpl += '<i class="icon-svn"></i> ';
864 873 }
865 874 if(data['private']){
866 875 tmpl += '<i class="icon-lock" ></i> ';
867 876 }
868 877 else if(visualShowPublicIcon){
869 878 tmpl += '<i class="icon-unlock-alt"></i> ';
870 879 }
871 880 }
872 881 tmpl += escapeMarkup(repoName);
873 882 return tmpl;
874 883
875 884 }(result, escapeMarkup);
876 885 };
877 886
878 887 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
879 888 return function(data, escapeMarkup) {
880 889 if (!data.repo_group_id){
881 890 return data.text; // optgroup text Repositories
882 891 }
883 892
884 893 var tmpl = '';
885 894 var repoGroupName = data['text'];
886 895
887 896 if(data){
888 897
889 898 tmpl += '<i class="icon-repo-group"></i> ';
890 899
891 900 }
892 901 tmpl += escapeMarkup(repoGroupName);
893 902 return tmpl;
894 903
895 904 }(result, escapeMarkup);
896 905 };
897 906
898 907 var escapeRegExChars = function (value) {
899 908 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
900 909 };
901 910
902 911 var getRepoIcon = function(repo_type) {
903 912 if (repo_type === 'hg') {
904 913 return '<i class="icon-hg"></i> ';
905 914 }
906 915 else if (repo_type === 'git') {
907 916 return '<i class="icon-git"></i> ';
908 917 }
909 918 else if (repo_type === 'svn') {
910 919 return '<i class="icon-svn"></i> ';
911 920 }
912 921 return ''
913 922 };
914 923
915 924 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
916 925
917 926 if (value.split(':').length === 2) {
918 927 value = value.split(':')[1]
919 928 }
920 929
921 930 var searchType = data['type'];
922 931 var searchSubType = data['subtype'];
923 932 var valueDisplay = data['value_display'];
924 933 var valueIcon = data['value_icon'];
925 934
926 935 var pattern = '(' + escapeRegExChars(value) + ')';
927 936
928 937 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
929 938
930 939 // highlight match
931 940 if (searchType != 'text') {
932 941 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
933 942 }
934 943
935 944 var icon = '';
936 945
937 946 if (searchType === 'hint') {
938 947 icon += '<i class="icon-repo-group"></i> ';
939 948 }
940 949 // full text search/hints
941 950 else if (searchType === 'search') {
942 951 if (valueIcon === undefined) {
943 952 icon += '<i class="icon-more"></i> ';
944 953 } else {
945 954 icon += valueIcon + ' ';
946 955 }
947 956
948 957 if (searchSubType !== undefined && searchSubType == 'repo') {
949 958 valueDisplay += '<div class="pull-right tag">repository</div>';
950 959 }
951 960 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
952 961 valueDisplay += '<div class="pull-right tag">repo group</div>';
953 962 }
954 963 }
955 964 // repository
956 965 else if (searchType === 'repo') {
957 966
958 967 var repoIcon = getRepoIcon(data['repo_type']);
959 968 icon += repoIcon;
960 969
961 970 if (data['private']) {
962 971 icon += '<i class="icon-lock" ></i> ';
963 972 }
964 973 else if (visualShowPublicIcon) {
965 974 icon += '<i class="icon-unlock-alt"></i> ';
966 975 }
967 976 }
968 977 // repository groups
969 978 else if (searchType === 'repo_group') {
970 979 icon += '<i class="icon-repo-group"></i> ';
971 980 }
972 981 // user group
973 982 else if (searchType === 'user_group') {
974 983 icon += '<i class="icon-group"></i> ';
975 984 }
976 985 // user
977 986 else if (searchType === 'user') {
978 987 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
979 988 }
980 989 // pull request
981 990 else if (searchType === 'pull_request') {
982 991 icon += '<i class="icon-merge"></i> ';
983 992 }
984 993 // commit
985 994 else if (searchType === 'commit') {
986 995 var repo_data = data['repo_data'];
987 996 var repoIcon = getRepoIcon(repo_data['repository_type']);
988 997 if (repoIcon) {
989 998 icon += repoIcon;
990 999 } else {
991 1000 icon += '<i class="icon-tag"></i>';
992 1001 }
993 1002 }
994 1003 // file
995 1004 else if (searchType === 'file') {
996 1005 var repo_data = data['repo_data'];
997 1006 var repoIcon = getRepoIcon(repo_data['repository_type']);
998 1007 if (repoIcon) {
999 1008 icon += repoIcon;
1000 1009 } else {
1001 1010 icon += '<i class="icon-tag"></i>';
1002 1011 }
1003 1012 }
1004 1013 // generic text
1005 1014 else if (searchType === 'text') {
1006 1015 icon = '';
1007 1016 }
1008 1017
1009 1018 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
1010 1019 return tmpl.format(icon, valueDisplay);
1011 1020 };
1012 1021
1013 1022 var handleSelect = function(element, suggestion) {
1014 1023 if (suggestion.type === "hint") {
1015 1024 // we skip action
1016 1025 $('#main_filter').focus();
1017 1026 }
1018 1027 else if (suggestion.type === "text") {
1019 1028 // we skip action
1020 1029 $('#main_filter').focus();
1021 1030
1022 1031 } else {
1023 1032 window.location = suggestion['url'];
1024 1033 }
1025 1034 };
1026 1035
1027 1036 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
1028 1037 if (queryLowerCase.split(':').length === 2) {
1029 1038 queryLowerCase = queryLowerCase.split(':')[1]
1030 1039 }
1031 1040 if (suggestion.type === "text") {
1032 1041 // special case we don't want to "skip" display for
1033 1042 return true
1034 1043 }
1035 1044 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
1036 1045 };
1037 1046
1038 1047 var cleanContext = {
1039 1048 repo_view_type: null,
1040 1049
1041 1050 repo_id: null,
1042 1051 repo_name: "",
1043 1052
1044 1053 repo_group_id: null,
1045 1054 repo_group_name: null
1046 1055 };
1047 1056 var removeGoToFilter = function () {
1048 1057 $('.searchTagHidable').hide();
1049 1058 $('#main_filter').autocomplete(
1050 1059 'setOptions', {params:{search_context: cleanContext}});
1051 1060 };
1052 1061
1053 1062 $('#main_filter').autocomplete({
1054 1063 serviceUrl: pyroutes.url('goto_switcher_data'),
1055 1064 params: {
1056 1065 "search_context": templateContext.search_context
1057 1066 },
1058 1067 minChars:2,
1059 1068 maxHeight:400,
1060 1069 deferRequestBy: 300, //miliseconds
1061 1070 tabDisabled: true,
1062 1071 autoSelectFirst: false,
1063 1072 containerClass: 'autocomplete-qfilter-suggestions',
1064 1073 formatResult: autocompleteMainFilterFormatResult,
1065 1074 lookupFilter: autocompleteMainFilterResult,
1066 1075 onSelect: function (element, suggestion) {
1067 1076 handleSelect(element, suggestion);
1068 1077 return false;
1069 1078 },
1070 1079 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
1071 1080 if (jqXHR !== 'abort') {
1072 1081 var message = formatErrorMessage(jqXHR, textStatus, errorThrown);
1073 1082 SwalNoAnimation.fire({
1074 1083 icon: 'error',
1075 1084 title: _gettext('Error during search operation'),
1076 1085 html: '<span style="white-space: pre-line">{0}</span>'.format(message),
1077 1086 }).then(function(result) {
1078 1087 window.location.reload();
1079 1088 })
1080 1089 }
1081 1090 },
1082 1091 onSearchStart: function (params) {
1083 1092 $('.searchTag.searchTagIcon').html('<i class="icon-spin animate-spin"></i>')
1084 1093 },
1085 1094 onSearchComplete: function (query, suggestions) {
1086 1095 $('.searchTag.searchTagIcon').html('<i class="icon-search"></i>')
1087 1096 },
1088 1097 });
1089 1098
1090 1099 showMainFilterBox = function () {
1091 1100 $('#main_filter_help').toggle();
1092 1101 };
1093 1102
1094 1103 $('#main_filter').on('keydown.autocomplete', function (e) {
1095 1104
1096 1105 var BACKSPACE = 8;
1097 1106 var el = $(e.currentTarget);
1098 1107 if(e.which === BACKSPACE){
1099 1108 var inputVal = el.val();
1100 1109 if (inputVal === ""){
1101 1110 removeGoToFilter()
1102 1111 }
1103 1112 }
1104 1113 });
1105 1114
1106 1115 var dismissNotice = function(noticeId) {
1107 1116
1108 1117 var url = pyroutes.url('user_notice_dismiss',
1109 1118 {"user_id": templateContext.rhodecode_user.user_id});
1110 1119
1111 1120 var postData = {
1112 1121 'csrf_token': CSRF_TOKEN,
1113 1122 'notice_id': noticeId,
1114 1123 };
1115 1124
1116 1125 var success = function(response) {
1117 1126 $('#notice-message-' + noticeId).remove();
1118 1127 return false;
1119 1128 };
1120 1129 var failure = function(data, textStatus, xhr) {
1121 1130 alert("error processing request: " + textStatus);
1122 1131 return false;
1123 1132 };
1124 1133 ajaxPOST(url, postData, success, failure);
1125 1134 }
1126 1135 </script>
1127 1136 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
1128 1137 </%def>
1129 1138
1130 1139 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
1131 1140 <div class="modal-dialog">
1132 1141 <div class="modal-content">
1133 1142 <div class="modal-header">
1134 1143 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1135 1144 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
1136 1145 </div>
1137 1146 <div class="modal-body">
1138 1147 <div class="block-left">
1139 1148 <table class="keyboard-mappings">
1140 1149 <tbody>
1141 1150 <tr>
1142 1151 <th></th>
1143 1152 <th>${_('Site-wide shortcuts')}</th>
1144 1153 </tr>
1145 1154 <%
1146 1155 elems = [
1147 1156 ('/', 'Use quick search box'),
1148 1157 ('g h', 'Goto home page'),
1149 1158 ('g g', 'Goto my private gists page'),
1150 1159 ('g G', 'Goto my public gists page'),
1151 1160 ('g 0-9', 'Goto bookmarked items from 0-9'),
1152 1161 ('n r', 'New repository page'),
1153 1162 ('n g', 'New gist page'),
1154 1163 ]
1155 1164 %>
1156 1165 %for key, desc in elems:
1157 1166 <tr>
1158 1167 <td class="keys">
1159 1168 <span class="key tag">${key}</span>
1160 1169 </td>
1161 1170 <td>${desc}</td>
1162 1171 </tr>
1163 1172 %endfor
1164 1173 </tbody>
1165 1174 </table>
1166 1175 </div>
1167 1176 <div class="block-left">
1168 1177 <table class="keyboard-mappings">
1169 1178 <tbody>
1170 1179 <tr>
1171 1180 <th></th>
1172 1181 <th>${_('Repositories')}</th>
1173 1182 </tr>
1174 1183 <%
1175 1184 elems = [
1176 1185 ('g s', 'Goto summary page'),
1177 1186 ('g c', 'Goto changelog page'),
1178 1187 ('g f', 'Goto files page'),
1179 1188 ('g F', 'Goto files page with file search activated'),
1180 1189 ('g p', 'Goto pull requests page'),
1181 1190 ('g o', 'Goto repository settings'),
1182 1191 ('g O', 'Goto repository access permissions settings'),
1183 1192 ]
1184 1193 %>
1185 1194 %for key, desc in elems:
1186 1195 <tr>
1187 1196 <td class="keys">
1188 1197 <span class="key tag">${key}</span>
1189 1198 </td>
1190 1199 <td>${desc}</td>
1191 1200 </tr>
1192 1201 %endfor
1193 1202 </tbody>
1194 1203 </table>
1195 1204 </div>
1196 1205 </div>
1197 1206 <div class="modal-footer">
1198 1207 </div>
1199 1208 </div><!-- /.modal-content -->
1200 1209 </div><!-- /.modal-dialog -->
1201 1210 </div><!-- /.modal -->
@@ -1,166 +1,166 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <!DOCTYPE html>
3 3
4 4 <%
5 5 c.template_context['repo_name'] = getattr(c, 'repo_name', '')
6 6 go_import_header = ''
7 7 if hasattr(c, 'rhodecode_db_repo'):
8 8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_ref_name
10 10 c.template_context['repo_id'] = c.rhodecode_db_repo.repo_id
11 11 c.template_context['repo_view_type'] = h.get_repo_view_type(request)
12 12
13 13 if getattr(c, 'repo_group', None):
14 14 c.template_context['repo_group_id'] = c.repo_group.group_id
15 15 c.template_context['repo_group_name'] = c.repo_group.group_name
16 16
17 17 if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id:
18 18 c.template_context['rhodecode_user']['user_id'] = c.rhodecode_user.user_id
19 19 c.template_context['rhodecode_user']['username'] = c.rhodecode_user.username
20 20 c.template_context['rhodecode_user']['email'] = c.rhodecode_user.email
21 21 c.template_context['rhodecode_user']['notification_status'] = c.rhodecode_user.get_instance().user_data.get('notification_status', True)
22 22 c.template_context['rhodecode_user']['first_name'] = c.rhodecode_user.first_name
23 23 c.template_context['rhodecode_user']['last_name'] = c.rhodecode_user.last_name
24 24
25 25 c.template_context['visual']['default_renderer'] = h.get_visual_attr(c, 'default_renderer')
26 26 c.template_context['default_user'] = {
27 27 'username': h.DEFAULT_USER,
28 28 'user_id': 1
29 29 }
30 30 c.template_context['search_context'] = {
31 31 'repo_group_id': c.template_context.get('repo_group_id'),
32 32 'repo_group_name': c.template_context.get('repo_group_name'),
33 33 'repo_id': c.template_context.get('repo_id'),
34 34 'repo_name': c.template_context.get('repo_name'),
35 35 'repo_view_type': c.template_context.get('repo_view_type'),
36 36 }
37 37
38 38 c.template_context['attachment_store'] = {
39 39 'max_file_size_mb': 10,
40 40 'image_ext': ["png", "jpg", "gif", "jpeg"]
41 41 }
42 42
43 43 %>
44 44 <html xmlns="http://www.w3.org/1999/xhtml">
45 45 <head>
46 46 <title>${self.title()}</title>
47 47 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
48 48
49 49 ${h.go_import_header(request, getattr(c, 'rhodecode_db_repo', None))}
50 50
51 51 % if 'safari' in (request.user_agent or '').lower():
52 52 <meta name="referrer" content="origin">
53 53 % else:
54 54 <meta name="referrer" content="origin-when-cross-origin">
55 55 % endif
56 56
57 57 <%def name="robots()">
58 58 <meta name="robots" content="index, nofollow"/>
59 59 </%def>
60 60 ${self.robots()}
61 61 <link rel="icon" href="${h.asset('images/favicon.ico', ver=c.rhodecode_version_hash)}" sizes="16x16 32x32" type="image/png" />
62 62 <script src="${h.asset('js/vendors/webcomponentsjs/custom-elements-es5-adapter.js', ver=c.rhodecode_version_hash)}"></script>
63 63 <script src="${h.asset('js/vendors/webcomponentsjs/webcomponents-bundle.js', ver=c.rhodecode_version_hash)}"></script>
64 64
65 65 ## CSS definitions
66 66 <%def name="css()">
67 67 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
68 68 ## EXTRA FOR CSS
69 69 ${self.css_extra()}
70 70 </%def>
71 71 ## CSS EXTRA - optionally inject some extra CSS stuff needed for specific websites
72 72 <%def name="css_extra()">
73 73 </%def>
74 74
75 75 ${self.css()}
76 76
77 77 ## JAVASCRIPT
78 78 <%def name="js()">
79 79
80 80 <script src="${h.asset('js/rhodecode/i18n/%s.js' % c.language, ver=c.rhodecode_version_hash)}"></script>
81 81 <script type="text/javascript">
82 82 // register templateContext to pass template variables to JS
83 83 var templateContext = ${h.json.dumps(c.template_context)|n};
84 84
85 85 var APPLICATION_URL = "${h.route_path('home').rstrip('/')}";
86 86 var APPLICATION_PLUGINS = [];
87 87 var ASSET_URL = "${h.asset('')}";
88 88 var DEFAULT_RENDERER = "${h.get_visual_attr(c, 'default_renderer')}";
89 89 var CSRF_TOKEN = "${getattr(c, 'csrf_token', '')}";
90 90
91 91 var APPENLIGHT = {
92 92 enabled: ${'true' if getattr(c, 'appenlight_enabled', False) else 'false'},
93 93 key: '${getattr(c, "appenlight_api_public_key", "")}',
94 94 % if getattr(c, 'appenlight_server_url', None):
95 95 serverUrl: '${getattr(c, "appenlight_server_url", "")}',
96 96 % endif
97 97 requestInfo: {
98 98 % if getattr(c, 'rhodecode_user', None):
99 99 ip: '${c.rhodecode_user.ip_addr}',
100 100 username: '${c.rhodecode_user.username}'
101 101 % endif
102 102 },
103 103 tags: {
104 104 rhodecode_version: '${c.rhodecode_version}',
105 105 rhodecode_edition: '${c.rhodecode_edition}'
106 106 }
107 107 };
108 108
109 109 </script>
110 110 <%include file="/base/plugins_base.mako"/>
111 111 <!--[if lt IE 9]>
112 112 <script language="javascript" type="text/javascript" src="${h.asset('js/src/excanvas.min.js')}"></script>
113 113 <![endif]-->
114 114 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script>
115 115 <script> var alertMessagePayloads = ${h.flash.json_alerts(request=request)|n}; </script>
116 116 ## avoide escaping the %N
117 117 <script language="javascript" type="text/javascript" src="${h.asset('js/scripts.min.js', ver=c.rhodecode_version_hash)}"></script>
118 118 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
119 119
120 120
121 121 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
122 122 ${self.js_extra()}
123 123
124 124 <script type="text/javascript">
125 125 Rhodecode = (function() {
126 126 function _Rhodecode() {
127 127 this.comments = new CommentsController();
128 128 }
129 129 return new _Rhodecode();
130 130 })();
131 131
132 132 $(document).ready(function(){
133 133 show_more_event();
134 134 timeagoActivate();
135 135 tooltipActivate();
136 136 clipboardActivate();
137 137 })
138 138 </script>
139 139
140 140 </%def>
141 141
142 142 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
143 143 <%def name="js_extra()"></%def>
144 144 ${self.js()}
145 145
146 146 <%def name="head_extra()"></%def>
147 147 ${self.head_extra()}
148 148 ## extra stuff
149 149 %if c.pre_code:
150 150 ${c.pre_code|n}
151 151 %endif
152 152 </head>
153 153 <body id="body">
154 154 <noscript>
155 155 <div class="noscript-error">
156 156 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
157 157 </div>
158 158 </noscript>
159 159
160 160 ${next.body()}
161 161 %if c.post_code:
162 162 ${c.post_code|n}
163 163 %endif
164 164 <rhodecode-app></rhodecode-app>
165 165 </body>
166 166 </html>
@@ -1,1193 +1,1215 b''
1 1 <%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/>
2 2
3 3 <%def name="diff_line_anchor(commit, filename, line, type)"><%
4 4 return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line)
5 5 %></%def>
6 6
7 7 <%def name="action_class(action)">
8 8 <%
9 9 return {
10 10 '-': 'cb-deletion',
11 11 '+': 'cb-addition',
12 12 ' ': 'cb-context',
13 13 }.get(action, 'cb-empty')
14 14 %>
15 15 </%def>
16 16
17 17 <%def name="op_class(op_id)">
18 18 <%
19 19 return {
20 20 DEL_FILENODE: 'deletion', # file deleted
21 21 BIN_FILENODE: 'warning' # binary diff hidden
22 22 }.get(op_id, 'addition')
23 23 %>
24 24 </%def>
25 25
26 26
27 27
28 28 <%def name="render_diffset(diffset, commit=None,
29 29
30 30 # collapse all file diff entries when there are more than this amount of files in the diff
31 31 collapse_when_files_over=20,
32 32
33 33 # collapse lines in the diff when more than this amount of lines changed in the file diff
34 34 lines_changed_limit=500,
35 35
36 36 # add a ruler at to the output
37 37 ruler_at_chars=0,
38 38
39 39 # show inline comments
40 40 use_comments=False,
41 41
42 42 # disable new comments
43 43 disable_new_comments=False,
44 44
45 45 # special file-comments that were deleted in previous versions
46 46 # it's used for showing outdated comments for deleted files in a PR
47 47 deleted_files_comments=None,
48 48
49 49 # for cache purpose
50 50 inline_comments=None,
51 51
52 52 # additional menu for PRs
53 53 pull_request_menu=None,
54 54
55 55 # show/hide todo next to comments
56 56 show_todos=True,
57 57
58 58 )">
59 59
60 60 <%
61 61 diffset_container_id = h.md5(diffset.target_ref)
62 62 collapse_all = len(diffset.files) > collapse_when_files_over
63 63 active_pattern_entries = h.get_active_pattern_entries(getattr(c, 'repo_name', None))
64 64 %>
65 65
66 66 %if use_comments:
67 67
68 68 ## Template for injecting comments
69 69 <div id="cb-comments-inline-container-template" class="js-template">
70 70 ${inline_comments_container([])}
71 71 </div>
72 72
73 73 <div class="js-template" id="cb-comment-inline-form-template">
74 74 <div class="comment-inline-form ac">
75 75
76 76 %if c.rhodecode_user.username != h.DEFAULT_USER:
77 77 ## render template for inline comments
78 78 ${commentblock.comment_form(form_type='inline')}
79 79 %else:
80 80 ${h.form('', class_='inline-form comment-form-login', method='get')}
81 81 <div class="pull-left">
82 82 <div class="comment-help pull-right">
83 83 ${_('You need to be logged in to leave comments.')} <a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a>
84 84 </div>
85 85 </div>
86 86 <div class="comment-button pull-right">
87 87 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
88 88 ${_('Cancel')}
89 89 </button>
90 90 </div>
91 91 <div class="clearfix"></div>
92 92 ${h.end_form()}
93 93 %endif
94 94 </div>
95 95 </div>
96 96
97 97 %endif
98 98
99 99 %if c.user_session_attrs["diffmode"] == 'sideside':
100 100 <style>
101 101 .wrapper {
102 102 max-width: 1600px !important;
103 103 }
104 104 </style>
105 105 %endif
106 106
107 107 %if ruler_at_chars:
108 108 <style>
109 109 .diff table.cb .cb-content:after {
110 110 content: "";
111 111 border-left: 1px solid blue;
112 112 position: absolute;
113 113 top: 0;
114 114 height: 18px;
115 115 opacity: .2;
116 116 z-index: 10;
117 117 //## +5 to account for diff action (+/-)
118 118 left: ${ruler_at_chars + 5}ch;
119 119 </style>
120 120 %endif
121 121
122 122 <div class="diffset ${disable_new_comments and 'diffset-comments-disabled'}">
123 123
124 124 <div style="height: 20px; line-height: 20px">
125 125 ## expand/collapse action
126 126 <div class="pull-left">
127 127 <a class="${'collapsed' if collapse_all else ''}" href="#expand-files" onclick="toggleExpand(this, '${diffset_container_id}'); return false">
128 128 % if collapse_all:
129 129 <i class="icon-plus-squared-alt icon-no-margin"></i>${_('Expand all files')}
130 130 % else:
131 131 <i class="icon-minus-squared-alt icon-no-margin"></i>${_('Collapse all files')}
132 132 % endif
133 133 </a>
134 134
135 135 </div>
136 136
137 137 ## todos
138 138 % if show_todos and getattr(c, 'at_version', None):
139 139 <div class="pull-right">
140 140 <i class="icon-flag-filled" style="color: #949494">TODOs:</i>
141 141 ${_('not available in this view')}
142 142 </div>
143 143 % elif show_todos:
144 144 <div class="pull-right">
145 145 <div class="comments-number" style="padding-left: 10px">
146 146 % if hasattr(c, 'unresolved_comments') and hasattr(c, 'resolved_comments'):
147 147 <i class="icon-flag-filled" style="color: #949494">TODOs:</i>
148 148 % if c.unresolved_comments:
149 149 <a href="#show-todos" onclick="$('#todo-box').toggle(); return false">
150 150 ${_('{} unresolved').format(len(c.unresolved_comments))}
151 151 </a>
152 152 % else:
153 153 ${_('0 unresolved')}
154 154 % endif
155 155
156 156 ${_('{} Resolved').format(len(c.resolved_comments))}
157 157 % endif
158 158 </div>
159 159 </div>
160 160 % endif
161 161
162 162 ## comments
163 163 <div class="pull-right">
164 164 <div class="comments-number" style="padding-left: 10px">
165 165 % if hasattr(c, 'comments') and hasattr(c, 'inline_cnt'):
166 166 <i class="icon-comment" style="color: #949494">COMMENTS:</i>
167 167 % if c.comments:
168 168 <a href="#comments">${_ungettext("{} General", "{} General", len(c.comments)).format(len(c.comments))}</a>,
169 169 % else:
170 170 ${_('0 General')}
171 171 % endif
172 172
173 173 % if c.inline_cnt:
174 174 <a href="#" onclick="return Rhodecode.comments.nextComment();"
175 175 id="inline-comments-counter">${_ungettext("{} Inline", "{} Inline", c.inline_cnt).format(c.inline_cnt)}
176 176 </a>
177 177 % else:
178 178 ${_('0 Inline')}
179 179 % endif
180 180 % endif
181 181
182 182 % if pull_request_menu:
183 183 <%
184 184 outdated_comm_count_ver = pull_request_menu['outdated_comm_count_ver']
185 185 %>
186 186
187 187 % if outdated_comm_count_ver:
188 188 <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;">
189 189 (${_("{} Outdated").format(outdated_comm_count_ver)})
190 190 </a>
191 191 <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a>
192 192 <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a>
193 193 % else:
194 194 (${_("{} Outdated").format(outdated_comm_count_ver)})
195 195 % endif
196 196
197 197 % endif
198 198
199 199 </div>
200 200 </div>
201 201
202 202 </div>
203 203
204 204 % if diffset.limited_diff:
205 205 <div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}">
206 206 <h2 class="clearinner">
207 207 ${_('The requested changes are too big and content was truncated.')}
208 208 <a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
209 209 </h2>
210 210 </div>
211 211 ## commit range header for each individual diff
212 212 % elif commit and hasattr(c, 'commit_ranges') and len(c.commit_ranges) > 1:
213 213 <div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}">
214 214 <div class="clearinner">
215 215 <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.route_path('repo_commit',repo_name=diffset.repo_name,commit_id=commit.raw_id)}">${('r%s:%s' % (commit.idx,h.short_id(commit.raw_id)))}</a>
216 216 </div>
217 217 </div>
218 218 % endif
219 219
220 220 <div id="todo-box">
221 221 % if hasattr(c, 'unresolved_comments') and c.unresolved_comments:
222 222 % for co in c.unresolved_comments:
223 223 <a class="permalink" href="#comment-${co.comment_id}"
224 224 onclick="Rhodecode.comments.scrollToComment($('#comment-${co.comment_id}'))">
225 225 <i class="icon-flag-filled-red"></i>
226 226 ${co.comment_id}</a>${('' if loop.last else ',')}
227 227 % endfor
228 228 % endif
229 229 </div>
230 230 %if diffset.has_hidden_changes:
231 231 <p class="empty_data">${_('Some changes may be hidden')}</p>
232 232 %elif not diffset.files:
233 233 <p class="empty_data">${_('No files')}</p>
234 234 %endif
235 235
236 236 <div class="filediffs">
237 237
238 238 ## initial value could be marked as False later on
239 239 <% over_lines_changed_limit = False %>
240 240 %for i, filediff in enumerate(diffset.files):
241 241
242 242 <%
243 243 lines_changed = filediff.patch['stats']['added'] + filediff.patch['stats']['deleted']
244 244 over_lines_changed_limit = lines_changed > lines_changed_limit
245 245 %>
246 246 ## anchor with support of sticky header
247 247 <div class="anchor" id="a_${h.FID(filediff.raw_id, filediff.patch['filename'])}"></div>
248 248
249 249 <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filediff)}" type="checkbox" onchange="updateSticky();">
250 250 <div
251 251 class="filediff"
252 252 data-f-path="${filediff.patch['filename']}"
253 253 data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}"
254 254 >
255 255 <label for="filediff-collapse-${id(filediff)}" class="filediff-heading">
256 <%
257 file_comments = (get_inline_comments(inline_comments, filediff.patch['filename']) or {}).values()
258 total_file_comments = [_c for _c in h.itertools.chain.from_iterable(file_comments) if not _c.outdated]
259 %>
256 260 <div class="filediff-collapse-indicator icon-"></div>
261 <span class="pill-group pull-right" >
262 <span class="pill"><i class="icon-comment"></i> ${len(total_file_comments)}</span>
263 </span>
257 264 ${diff_ops(filediff)}
265
258 266 </label>
259 267
260 268 ${diff_menu(filediff, use_comments=use_comments)}
261 269 <table data-f-path="${filediff.patch['filename']}" data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" class="code-visible-block cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
262 270
263 271 ## new/deleted/empty content case
264 272 % if not filediff.hunks:
265 273 ## Comment container, on "fakes" hunk that contains all data to render comments
266 274 ${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)}
267 275 % endif
268 276
269 277 %if filediff.limited_diff:
270 278 <tr class="cb-warning cb-collapser">
271 279 <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}>
272 280 ${_('The requested commit or file is too big and content was truncated.')} <a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
273 281 </td>
274 282 </tr>
275 283 %else:
276 284 %if over_lines_changed_limit:
277 285 <tr class="cb-warning cb-collapser">
278 286 <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}>
279 287 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
280 288 <a href="#" class="cb-expand"
281 289 onclick="$(this).closest('table').removeClass('cb-collapsed'); updateSticky(); return false;">${_('Show them')}
282 290 </a>
283 291 <a href="#" class="cb-collapse"
284 292 onclick="$(this).closest('table').addClass('cb-collapsed'); updateSticky(); return false;">${_('Hide them')}
285 293 </a>
286 294 </td>
287 295 </tr>
288 296 %endif
289 297 %endif
290 298
291 299 % for hunk in filediff.hunks:
292 300 <tr class="cb-hunk">
293 301 <td ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=3' or '')}>
294 302 ## TODO: dan: add ajax loading of more context here
295 303 ## <a href="#">
296 304 <i class="icon-more"></i>
297 305 ## </a>
298 306 </td>
299 307 <td ${(c.user_session_attrs["diffmode"] == 'sideside' and 'colspan=5' or '')}>
300 308 @@
301 309 -${hunk.source_start},${hunk.source_length}
302 310 +${hunk.target_start},${hunk.target_length}
303 311 ${hunk.section_header}
304 312 </td>
305 313 </tr>
306 314 ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)}
307 315 % endfor
308 316
309 317 <% unmatched_comments = (inline_comments or {}).get(filediff.patch['filename'], {}) %>
310 318
311 319 ## outdated comments that do not fit into currently displayed lines
312 320 % for lineno, comments in unmatched_comments.items():
313 321
314 322 %if c.user_session_attrs["diffmode"] == 'unified':
315 323 % if loop.index == 0:
316 324 <tr class="cb-hunk">
317 325 <td colspan="3"></td>
318 326 <td>
319 327 <div>
320 328 ${_('Unmatched/outdated inline comments below')}
321 329 </div>
322 330 </td>
323 331 </tr>
324 332 % endif
325 333 <tr class="cb-line">
326 334 <td class="cb-data cb-context"></td>
327 335 <td class="cb-lineno cb-context"></td>
328 336 <td class="cb-lineno cb-context"></td>
329 337 <td class="cb-content cb-context">
330 338 ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)}
331 339 </td>
332 340 </tr>
333 341 %elif c.user_session_attrs["diffmode"] == 'sideside':
334 342 % if loop.index == 0:
335 343 <tr class="cb-comment-info">
336 344 <td colspan="2"></td>
337 345 <td class="cb-line">
338 346 <div>
339 347 ${_('Unmatched/outdated inline comments below')}
340 348 </div>
341 349 </td>
342 350 <td colspan="2"></td>
343 351 <td class="cb-line">
344 352 <div>
345 353 ${_('Unmatched/outdated comments below')}
346 354 </div>
347 355 </td>
348 356 </tr>
349 357 % endif
350 358 <tr class="cb-line">
351 359 <td class="cb-data cb-context"></td>
352 360 <td class="cb-lineno cb-context"></td>
353 361 <td class="cb-content cb-context">
354 362 % if lineno.startswith('o'):
355 363 ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)}
356 364 % endif
357 365 </td>
358 366
359 367 <td class="cb-data cb-context"></td>
360 368 <td class="cb-lineno cb-context"></td>
361 369 <td class="cb-content cb-context">
362 370 % if lineno.startswith('n'):
363 371 ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)}
364 372 % endif
365 373 </td>
366 374 </tr>
367 375 %endif
368 376
369 377 % endfor
370 378
371 379 </table>
372 380 </div>
373 381 %endfor
374 382
375 383 ## outdated comments that are made for a file that has been deleted
376 384 % for filename, comments_dict in (deleted_files_comments or {}).items():
377 385
378 386 <%
379 387 display_state = 'display: none'
380 388 open_comments_in_file = [x for x in comments_dict['comments'] if x.outdated is False]
381 389 if open_comments_in_file:
382 390 display_state = ''
383 391 fid = str(id(filename))
384 392 %>
385 393 <div class="filediffs filediff-outdated" style="${display_state}">
386 394 <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filename)}" type="checkbox" onchange="updateSticky();">
387 395 <div class="filediff" data-f-path="${filename}" id="a_${h.FID(fid, filename)}">
388 396 <label for="filediff-collapse-${id(filename)}" class="filediff-heading">
389 397 <div class="filediff-collapse-indicator icon-"></div>
390 398
391 399 <span class="pill">
392 400 ## file was deleted
393 401 ${filename}
394 402 </span>
395 403 <span class="pill-group pull-left" >
396 404 ## file op, doesn't need translation
397 405 <span class="pill" op="removed">unresolved comments</span>
398 406 </span>
399 407 <a class="pill filediff-anchor" href="#a_${h.FID(fid, filename)}"></a>
400 408 <span class="pill-group pull-right">
401 409 <span class="pill" op="deleted">
402 410 % if comments_dict['stats'] >0:
403 411 -${comments_dict['stats']}
404 412 % else:
405 413 ${comments_dict['stats']}
406 414 % endif
407 415 </span>
408 416 </span>
409 417 </label>
410 418
411 419 <table class="cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}">
412 420 <tr>
413 421 % if c.user_session_attrs["diffmode"] == 'unified':
414 422 <td></td>
415 423 %endif
416 424
417 425 <td></td>
418 426 <td class="cb-text cb-${op_class(BIN_FILENODE)}" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=5')}>
419 427 <strong>${_('This file was removed from diff during updates to this pull-request.')}</strong><br/>
420 428 ${_('There are still outdated/unresolved comments attached to it.')}
421 429 </td>
422 430 </tr>
423 431 %if c.user_session_attrs["diffmode"] == 'unified':
424 432 <tr class="cb-line">
425 433 <td class="cb-data cb-context"></td>
426 434 <td class="cb-lineno cb-context"></td>
427 435 <td class="cb-lineno cb-context"></td>
428 436 <td class="cb-content cb-context">
429 437 ${inline_comments_container(comments_dict['comments'], active_pattern_entries=active_pattern_entries)}
430 438 </td>
431 439 </tr>
432 440 %elif c.user_session_attrs["diffmode"] == 'sideside':
433 441 <tr class="cb-line">
434 442 <td class="cb-data cb-context"></td>
435 443 <td class="cb-lineno cb-context"></td>
436 444 <td class="cb-content cb-context"></td>
437 445
438 446 <td class="cb-data cb-context"></td>
439 447 <td class="cb-lineno cb-context"></td>
440 448 <td class="cb-content cb-context">
441 449 ${inline_comments_container(comments_dict['comments'], active_pattern_entries=active_pattern_entries)}
442 450 </td>
443 451 </tr>
444 452 %endif
445 453 </table>
446 454 </div>
447 455 </div>
448 456 % endfor
449 457
450 458 </div>
451 459 </div>
452 460 </%def>
453 461
454 462 <%def name="diff_ops(filediff)">
455 463 <%
456 464 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
457 465 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE
458 466 %>
459 467 <span class="pill">
460 468 <i class="icon-file-text"></i>
461 469 %if filediff.source_file_path and filediff.target_file_path:
462 470 %if filediff.source_file_path != filediff.target_file_path:
463 471 ## file was renamed, or copied
464 472 %if RENAMED_FILENODE in filediff.patch['stats']['ops']:
465 473 ${filediff.target_file_path}<del>${filediff.source_file_path}</del>
466 474 <% final_path = filediff.target_file_path %>
467 475 %elif COPIED_FILENODE in filediff.patch['stats']['ops']:
468 476 ${filediff.target_file_path}${filediff.source_file_path}
469 477 <% final_path = filediff.target_file_path %>
470 478 %endif
471 479 %else:
472 480 ## file was modified
473 481 ${filediff.source_file_path}
474 482 <% final_path = filediff.source_file_path %>
475 483 %endif
476 484 %else:
477 485 %if filediff.source_file_path:
478 486 ## file was deleted
479 487 ${filediff.source_file_path}
480 488 <% final_path = filediff.source_file_path %>
481 489 %else:
482 490 ## file was added
483 491 ${filediff.target_file_path}
484 492 <% final_path = filediff.target_file_path %>
485 493 %endif
486 494 %endif
487 <i style="color: #aaa" class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${final_path}" title="${_('Copy file path')}" onclick="return false;"></i>
495 <i style="color: #aaa" class="on-hover-icon icon-clipboard clipboard-action" data-clipboard-text="${final_path}" title="${_('Copy file path')}" onclick="return false;"></i>
488 496 </span>
489 497 ## anchor link
490 498 <a class="pill filediff-anchor" href="#a_${h.FID(filediff.raw_id, filediff.patch['filename'])}"></a>
491 499
492 500 <span class="pill-group pull-right">
493 501
494 502 ## ops pills
495 503 %if filediff.limited_diff:
496 504 <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span>
497 505 %endif
498 506
499 507 %if NEW_FILENODE in filediff.patch['stats']['ops']:
500 508 <span class="pill" op="created">created</span>
501 509 %if filediff['target_mode'].startswith('120'):
502 510 <span class="pill" op="symlink">symlink</span>
503 511 %else:
504 512 <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span>
505 513 %endif
506 514 %endif
507 515
508 516 %if RENAMED_FILENODE in filediff.patch['stats']['ops']:
509 517 <span class="pill" op="renamed">renamed</span>
510 518 %endif
511 519
512 520 %if COPIED_FILENODE in filediff.patch['stats']['ops']:
513 521 <span class="pill" op="copied">copied</span>
514 522 %endif
515 523
516 524 %if DEL_FILENODE in filediff.patch['stats']['ops']:
517 525 <span class="pill" op="removed">removed</span>
518 526 %endif
519 527
520 528 %if CHMOD_FILENODE in filediff.patch['stats']['ops']:
521 529 <span class="pill" op="mode">
522 530 ${nice_mode(filediff['source_mode'])}${nice_mode(filediff['target_mode'])}
523 531 </span>
524 532 %endif
525 533
526 534 %if BIN_FILENODE in filediff.patch['stats']['ops']:
527 535 <span class="pill" op="binary">binary</span>
528 536 %if MOD_FILENODE in filediff.patch['stats']['ops']:
529 537 <span class="pill" op="modified">modified</span>
530 538 %endif
531 539 %endif
532 540
533 541 <span class="pill" op="added">${('+' if filediff.patch['stats']['added'] else '')}${filediff.patch['stats']['added']}</span>
534 542 <span class="pill" op="deleted">${((h.safe_int(filediff.patch['stats']['deleted']) or 0) * -1)}</span>
535 543
536 544 </span>
537 545
538 546 </%def>
539 547
540 548 <%def name="nice_mode(filemode)">
541 549 ${(filemode.startswith('100') and filemode[3:] or filemode)}
542 550 </%def>
543 551
544 552 <%def name="diff_menu(filediff, use_comments=False)">
545 553 <div class="filediff-menu">
546 554
547 555 %if filediff.diffset.source_ref:
548 556
549 557 ## FILE BEFORE CHANGES
550 558 %if filediff.operation in ['D', 'M']:
551 559 <a
552 560 class="tooltip"
553 561 href="${h.route_path('repo_files',repo_name=filediff.diffset.target_repo_name,commit_id=filediff.diffset.source_ref,f_path=filediff.source_file_path)}"
554 562 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
555 563 >
556 564 ${_('Show file before')}
557 565 </a> |
558 566 %else:
559 567 <span
560 568 class="tooltip"
561 569 title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
562 570 >
563 571 ${_('Show file before')}
564 572 </span> |
565 573 %endif
566 574
567 575 ## FILE AFTER CHANGES
568 576 %if filediff.operation in ['A', 'M']:
569 577 <a
570 578 class="tooltip"
571 579 href="${h.route_path('repo_files',repo_name=filediff.diffset.source_repo_name,commit_id=filediff.diffset.target_ref,f_path=filediff.target_file_path)}"
572 580 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
573 581 >
574 582 ${_('Show file after')}
575 583 </a>
576 584 %else:
577 585 <span
578 586 class="tooltip"
579 587 title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
580 588 >
581 589 ${_('Show file after')}
582 590 </span>
583 591 %endif
584 592
585 593 % if use_comments:
586 594 |
587 595 <a href="#" onclick="return Rhodecode.comments.toggleComments(this);">
588 596 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
589 597 </a>
590 598 % endif
591 599
592 600 %endif
593 601
594 602 </div>
595 603 </%def>
596 604
597 605
598 606 <%def name="inline_comments_container(comments, active_pattern_entries=None)">
599 607
600 608 <div class="inline-comments">
601 609 %for comment in comments:
602 610 ${commentblock.comment_block(comment, inline=True, active_pattern_entries=active_pattern_entries)}
603 611 %endfor
604 612 % if comments and comments[-1].outdated:
605 613 <span class="btn btn-secondary cb-comment-add-button comment-outdated}" style="display: none;}">
606 614 ${_('Add another comment')}
607 615 </span>
608 616 % else:
609 617 <span onclick="return Rhodecode.comments.createComment(this)" class="btn btn-secondary cb-comment-add-button">
610 618 ${_('Add another comment')}
611 619 </span>
612 620 % endif
613 621
614 622 </div>
615 623 </%def>
616 624
617 625 <%!
626
627 def get_inline_comments(comments, filename):
628 if hasattr(filename, 'unicode_path'):
629 filename = filename.unicode_path
630
631 if not isinstance(filename, (unicode, str)):
632 return None
633
634 if comments and filename in comments:
635 return comments[filename]
636
637 return None
638
618 639 def get_comments_for(diff_type, comments, filename, line_version, line_number):
619 640 if hasattr(filename, 'unicode_path'):
620 641 filename = filename.unicode_path
621 642
622 643 if not isinstance(filename, (unicode, str)):
623 644 return None
624 645
625 line_key = '{}{}'.format(line_version, line_number) ## e.g o37, n12
646 file_comments = get_inline_comments(comments, filename)
647 if file_comments is None:
648 return None
626 649
627 if comments and filename in comments:
628 file_comments = comments[filename]
629 if line_key in file_comments:
630 data = file_comments.pop(line_key)
631 return data
650 line_key = '{}{}'.format(line_version, line_number) ## e.g o37, n12
651 if line_key in file_comments:
652 data = file_comments.pop(line_key)
653 return data
632 654 %>
633 655
634 656 <%def name="render_hunk_lines_sideside(filediff, hunk, use_comments=False, inline_comments=None, active_pattern_entries=None)">
635 657 %for i, line in enumerate(hunk.sideside):
636 658 <%
637 659 old_line_anchor, new_line_anchor = None, None
638 660
639 661 if line.original.lineno:
640 662 old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, line.original.lineno, 'o')
641 663 if line.modified.lineno:
642 664 new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, line.modified.lineno, 'n')
643 665 %>
644 666
645 667 <tr class="cb-line">
646 668 <td class="cb-data ${action_class(line.original.action)}"
647 669 data-line-no="${line.original.lineno}"
648 670 >
649 671 <div>
650 672
651 673 <% line_old_comments = None %>
652 674 %if line.original.get_comment_args:
653 675 <% line_old_comments = get_comments_for('side-by-side', inline_comments, *line.original.get_comment_args) %>
654 676 %endif
655 677 %if line_old_comments:
656 678 <% has_outdated = any([x.outdated for x in line_old_comments]) %>
657 679 % if has_outdated:
658 <i title="${_('comments including outdated')}:${len(line_old_comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
680 <i class="tooltip" title="${_('comments including outdated, click to show them')}:${len(line_old_comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
659 681 % else:
660 <i title="${_('comments')}: ${len(line_old_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
682 <i class="tooltip" title="${_('comments')}: ${len(line_old_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
661 683 % endif
662 684 %endif
663 685 </div>
664 686 </td>
665 687 <td class="cb-lineno ${action_class(line.original.action)}"
666 688 data-line-no="${line.original.lineno}"
667 689 %if old_line_anchor:
668 690 id="${old_line_anchor}"
669 691 %endif
670 692 >
671 693 %if line.original.lineno:
672 694 <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
673 695 %endif
674 696 </td>
675 697 <td class="cb-content ${action_class(line.original.action)}"
676 698 data-line-no="o${line.original.lineno}"
677 699 >
678 700 %if use_comments and line.original.lineno:
679 701 ${render_add_comment_button()}
680 702 %endif
681 703 <span class="cb-code"><span class="cb-action ${action_class(line.original.action)}"></span>${line.original.content or '' | n}</span>
682 704
683 705 %if use_comments and line.original.lineno and line_old_comments:
684 706 ${inline_comments_container(line_old_comments, active_pattern_entries=active_pattern_entries)}
685 707 %endif
686 708
687 709 </td>
688 710 <td class="cb-data ${action_class(line.modified.action)}"
689 711 data-line-no="${line.modified.lineno}"
690 712 >
691 713 <div>
692 714
693 715 %if line.modified.get_comment_args:
694 716 <% line_new_comments = get_comments_for('side-by-side', inline_comments, *line.modified.get_comment_args) %>
695 717 %else:
696 718 <% line_new_comments = None%>
697 719 %endif
698 720 %if line_new_comments:
699 721 <% has_outdated = any([x.outdated for x in line_new_comments]) %>
700 722 % if has_outdated:
701 <i title="${_('comments including outdated')}:${len(line_new_comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
723 <i class="tooltip" title="${_('comments including outdated, click to show them')}:${len(line_new_comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
702 724 % else:
703 <i title="${_('comments')}: ${len(line_new_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
725 <i class="tooltip" title="${_('comments')}: ${len(line_new_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
704 726 % endif
705 727 %endif
706 728 </div>
707 729 </td>
708 730 <td class="cb-lineno ${action_class(line.modified.action)}"
709 731 data-line-no="${line.modified.lineno}"
710 732 %if new_line_anchor:
711 733 id="${new_line_anchor}"
712 734 %endif
713 735 >
714 736 %if line.modified.lineno:
715 737 <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
716 738 %endif
717 739 </td>
718 740 <td class="cb-content ${action_class(line.modified.action)}"
719 741 data-line-no="n${line.modified.lineno}"
720 742 >
721 743 %if use_comments and line.modified.lineno:
722 744 ${render_add_comment_button()}
723 745 %endif
724 746 <span class="cb-code"><span class="cb-action ${action_class(line.modified.action)}"></span>${line.modified.content or '' | n}</span>
725 747 %if use_comments and line.modified.lineno and line_new_comments:
726 748 ${inline_comments_container(line_new_comments, active_pattern_entries=active_pattern_entries)}
727 749 %endif
728 750 </td>
729 751 </tr>
730 752 %endfor
731 753 </%def>
732 754
733 755
734 756 <%def name="render_hunk_lines_unified(filediff, hunk, use_comments=False, inline_comments=None, active_pattern_entries=None)">
735 757 %for old_line_no, new_line_no, action, content, comments_args in hunk.unified:
736 758
737 759 <%
738 760 old_line_anchor, new_line_anchor = None, None
739 761 if old_line_no:
740 762 old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, old_line_no, 'o')
741 763 if new_line_no:
742 764 new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, new_line_no, 'n')
743 765 %>
744 766 <tr class="cb-line">
745 767 <td class="cb-data ${action_class(action)}">
746 768 <div>
747 769
748 770 %if comments_args:
749 771 <% comments = get_comments_for('unified', inline_comments, *comments_args) %>
750 772 %else:
751 773 <% comments = None %>
752 774 %endif
753 775
754 776 % if comments:
755 777 <% has_outdated = any([x.outdated for x in comments]) %>
756 778 % if has_outdated:
757 <i title="${_('comments including outdated')}:${len(comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
779 <i class="tooltip" title="${_('comments including outdated, click to show them')}:${len(comments)}" class="icon-comment-toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
758 780 % else:
759 <i title="${_('comments')}: ${len(comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
781 <i class="tooltip" title="${_('comments')}: ${len(comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
760 782 % endif
761 783 % endif
762 784 </div>
763 785 </td>
764 786 <td class="cb-lineno ${action_class(action)}"
765 787 data-line-no="${old_line_no}"
766 788 %if old_line_anchor:
767 789 id="${old_line_anchor}"
768 790 %endif
769 791 >
770 792 %if old_line_anchor:
771 793 <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a>
772 794 %endif
773 795 </td>
774 796 <td class="cb-lineno ${action_class(action)}"
775 797 data-line-no="${new_line_no}"
776 798 %if new_line_anchor:
777 799 id="${new_line_anchor}"
778 800 %endif
779 801 >
780 802 %if new_line_anchor:
781 803 <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
782 804 %endif
783 805 </td>
784 806 <td class="cb-content ${action_class(action)}"
785 807 data-line-no="${(new_line_no and 'n' or 'o')}${(new_line_no or old_line_no)}"
786 808 >
787 809 %if use_comments:
788 810 ${render_add_comment_button()}
789 811 %endif
790 812 <span class="cb-code"><span class="cb-action ${action_class(action)}"></span> ${content or '' | n}</span>
791 813 %if use_comments and comments:
792 814 ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)}
793 815 %endif
794 816 </td>
795 817 </tr>
796 818 %endfor
797 819 </%def>
798 820
799 821
800 822 <%def name="render_hunk_lines(filediff, diff_mode, hunk, use_comments, inline_comments, active_pattern_entries)">
801 823 % if diff_mode == 'unified':
802 824 ${render_hunk_lines_unified(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)}
803 825 % elif diff_mode == 'sideside':
804 826 ${render_hunk_lines_sideside(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)}
805 827 % else:
806 828 <tr class="cb-line">
807 829 <td>unknown diff mode</td>
808 830 </tr>
809 831 % endif
810 832 </%def>file changes
811 833
812 834
813 835 <%def name="render_add_comment_button()">
814 836 <button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this)">
815 837 <span><i class="icon-comment"></i></span>
816 838 </button>
817 839 </%def>
818 840
819 841 <%def name="render_diffset_menu(diffset, range_diff_on=None)">
820 842 <% diffset_container_id = h.md5(diffset.target_ref) %>
821 843
822 844 <div id="diff-file-sticky" class="diffset-menu clearinner">
823 845 ## auto adjustable
824 846 <div class="sidebar__inner">
825 847 <div class="sidebar__bar">
826 848 <div class="pull-right">
827 849 <div class="btn-group">
828 850 <a class="btn tooltip toggle-wide-diff" href="#toggle-wide-diff" onclick="toggleWideDiff(this); return false" title="${h.tooltip(_('Toggle wide diff'))}">
829 851 <i class="icon-wide-mode"></i>
830 852 </a>
831 853 </div>
832 854 <div class="btn-group">
833 855
834 856 <a
835 857 class="btn ${(c.user_session_attrs["diffmode"] == 'sideside' and 'btn-active')} tooltip"
836 858 title="${h.tooltip(_('View diff as side by side'))}"
837 859 href="${h.current_route_path(request, diffmode='sideside')}">
838 860 <span>${_('Side by Side')}</span>
839 861 </a>
840 862
841 863 <a
842 864 class="btn ${(c.user_session_attrs["diffmode"] == 'unified' and 'btn-active')} tooltip"
843 865 title="${h.tooltip(_('View diff as unified'))}" href="${h.current_route_path(request, diffmode='unified')}">
844 866 <span>${_('Unified')}</span>
845 867 </a>
846 868
847 869 % if range_diff_on is True:
848 870 <a
849 871 title="${_('Turn off: Show the diff as commit range')}"
850 872 class="btn btn-primary"
851 873 href="${h.current_route_path(request, **{"range-diff":"0"})}">
852 874 <span>${_('Range Diff')}</span>
853 875 </a>
854 876 % elif range_diff_on is False:
855 877 <a
856 878 title="${_('Show the diff as commit range')}"
857 879 class="btn"
858 880 href="${h.current_route_path(request, **{"range-diff":"1"})}">
859 881 <span>${_('Range Diff')}</span>
860 882 </a>
861 883 % endif
862 884 </div>
863 885 <div class="btn-group">
864 886
865 887 <div class="pull-left">
866 888 ${h.hidden('diff_menu_{}'.format(diffset_container_id))}
867 889 </div>
868 890
869 891 </div>
870 892 </div>
871 893 <div class="pull-left">
872 894 <div class="btn-group">
873 895 <div class="pull-left">
874 896 ${h.hidden('file_filter_{}'.format(diffset_container_id))}
875 897 </div>
876 898
877 899 </div>
878 900 </div>
879 901 </div>
880 902 <div class="fpath-placeholder">
881 903 <i class="icon-file-text"></i>
882 904 <strong class="fpath-placeholder-text">
883 905 Context file:
884 906 </strong>
885 907 </div>
886 908 <div class="sidebar_inner_shadow"></div>
887 909 </div>
888 910 </div>
889 911
890 912 % if diffset:
891 913 %if diffset.limited_diff:
892 914 <% file_placeholder = _ungettext('%(num)s file changed', '%(num)s files changed', diffset.changed_files) % {'num': diffset.changed_files} %>
893 915 %else:
894 916 <% file_placeholder = h.literal(_ungettext('%(num)s file changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>', '%(num)s files changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>',
895 917 diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}) %>
896 918
897 919 %endif
898 920 ## case on range-diff placeholder needs to be updated
899 921 % if range_diff_on is True:
900 922 <% file_placeholder = _('Disabled on range diff') %>
901 923 % endif
902 924
903 925 <script type="text/javascript">
904 926 var feedFilesOptions = function (query, initialData) {
905 927 var data = {results: []};
906 928 var isQuery = typeof query.term !== 'undefined';
907 929
908 930 var section = _gettext('Changed files');
909 931 var filteredData = [];
910 932
911 933 //filter results
912 934 $.each(initialData.results, function (idx, value) {
913 935
914 936 if (!isQuery || query.term.length === 0 || value.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
915 937 filteredData.push({
916 938 'id': this.id,
917 939 'text': this.text,
918 940 "ops": this.ops,
919 941 })
920 942 }
921 943
922 944 });
923 945
924 946 data.results = filteredData;
925 947
926 948 query.callback(data);
927 949 };
928 950
929 951 var selectionFormatter = function(data, escapeMarkup) {
930 952 var container = '<div class="filelist" style="padding-right:100px">{0}</div>';
931 953 var tmpl = '<div><strong>{0}</strong></div>'.format(escapeMarkup(data['text']));
932 954 var pill = '<div class="pill-group" style="position: absolute; top:7px; right: 0">' +
933 955 '<span class="pill" op="added">{0}</span>' +
934 956 '<span class="pill" op="deleted">{1}</span>' +
935 957 '</div>'
936 958 ;
937 959 var added = data['ops']['added'];
938 960 if (added === 0) {
939 961 // don't show +0
940 962 added = 0;
941 963 } else {
942 964 added = '+' + added;
943 965 }
944 966
945 967 var deleted = -1*data['ops']['deleted'];
946 968
947 969 tmpl += pill.format(added, deleted);
948 970 return container.format(tmpl);
949 971 };
950 972 var formatFileResult = function(result, container, query, escapeMarkup) {
951 973 return selectionFormatter(result, escapeMarkup);
952 974 };
953 975
954 976 var formatSelection = function (data, container) {
955 977 return '${file_placeholder}'
956 978 };
957 979
958 980 if (window.preloadFileFilterData === undefined) {
959 981 window.preloadFileFilterData = {}
960 982 }
961 983
962 984 preloadFileFilterData["${diffset_container_id}"] = {
963 985 results: [
964 986 % for filediff in diffset.files:
965 987 {id:"a_${h.FID(filediff.raw_id, filediff.patch['filename'])}",
966 988 text:"${filediff.patch['filename']}",
967 989 ops:${h.json.dumps(filediff.patch['stats'])|n}}${('' if loop.last else ',')}
968 990 % endfor
969 991 ]
970 992 };
971 993
972 994 var diffFileFilterId = "#file_filter_" + "${diffset_container_id}";
973 995 var diffFileFilter = $(diffFileFilterId).select2({
974 996 'dropdownAutoWidth': true,
975 997 'width': 'auto',
976 998
977 999 containerCssClass: "drop-menu",
978 1000 dropdownCssClass: "drop-menu-dropdown",
979 1001 data: preloadFileFilterData["${diffset_container_id}"],
980 1002 query: function(query) {
981 1003 feedFilesOptions(query, preloadFileFilterData["${diffset_container_id}"]);
982 1004 },
983 1005 initSelection: function(element, callback) {
984 1006 callback({'init': true});
985 1007 },
986 1008 formatResult: formatFileResult,
987 1009 formatSelection: formatSelection
988 1010 });
989 1011
990 1012 % if range_diff_on is True:
991 1013 diffFileFilter.select2("enable", false);
992 1014 % endif
993 1015
994 1016 $(diffFileFilterId).on('select2-selecting', function (e) {
995 1017 var idSelector = e.choice.id;
996 1018
997 1019 // expand the container if we quick-select the field
998 1020 $('#'+idSelector).next().prop('checked', false);
999 1021 // hide the mast as we later do preventDefault()
1000 1022 $("#select2-drop-mask").click();
1001 1023
1002 1024 window.location.hash = '#'+idSelector;
1003 1025 updateSticky();
1004 1026
1005 1027 e.preventDefault();
1006 1028 });
1007 1029
1008 1030 </script>
1009 1031 % endif
1010 1032
1011 1033 <script type="text/javascript">
1012 1034 $(document).ready(function () {
1013 1035
1014 1036 var contextPrefix = _gettext('Context file: ');
1015 1037 ## sticky sidebar
1016 1038 var sidebarElement = document.getElementById('diff-file-sticky');
1017 1039 sidebar = new StickySidebar(sidebarElement, {
1018 1040 topSpacing: 0,
1019 1041 bottomSpacing: 0,
1020 1042 innerWrapperSelector: '.sidebar__inner'
1021 1043 });
1022 1044 sidebarElement.addEventListener('affixed.static.stickySidebar', function () {
1023 1045 // reset our file so it's not holding new value
1024 1046 $('.fpath-placeholder-text').html(contextPrefix + ' - ')
1025 1047 });
1026 1048
1027 1049 updateSticky = function () {
1028 1050 sidebar.updateSticky();
1029 1051 Waypoint.refreshAll();
1030 1052 };
1031 1053
1032 1054 var animateText = function (fPath, anchorId) {
1033 1055 fPath = Select2.util.escapeMarkup(fPath);
1034 1056 $('.fpath-placeholder-text').html(contextPrefix + '<a href="#a_' + anchorId + '">' + fPath + '</a>')
1035 1057 };
1036 1058
1037 1059 ## dynamic file waypoints
1038 1060 var setFPathInfo = function(fPath, anchorId){
1039 1061 animateText(fPath, anchorId)
1040 1062 };
1041 1063
1042 1064 var codeBlock = $('.filediff');
1043 1065
1044 1066 // forward waypoint
1045 1067 codeBlock.waypoint(
1046 1068 function(direction) {
1047 1069 if (direction === "down"){
1048 1070 setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId'))
1049 1071 }
1050 1072 }, {
1051 1073 offset: function () {
1052 1074 return 70;
1053 1075 },
1054 1076 context: '.fpath-placeholder'
1055 1077 }
1056 1078 );
1057 1079
1058 1080 // backward waypoint
1059 1081 codeBlock.waypoint(
1060 1082 function(direction) {
1061 1083 if (direction === "up"){
1062 1084 setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId'))
1063 1085 }
1064 1086 }, {
1065 1087 offset: function () {
1066 1088 return -this.element.clientHeight + 90;
1067 1089 },
1068 1090 context: '.fpath-placeholder'
1069 1091 }
1070 1092 );
1071 1093
1072 1094 toggleWideDiff = function (el) {
1073 1095 updateSticky();
1074 1096 var wide = Rhodecode.comments.toggleWideMode(this);
1075 1097 storeUserSessionAttr('rc_user_session_attr.wide_diff_mode', wide);
1076 1098 if (wide === true) {
1077 1099 $(el).addClass('btn-active');
1078 1100 } else {
1079 1101 $(el).removeClass('btn-active');
1080 1102 }
1081 1103 return null;
1082 1104 };
1083 1105
1084 1106 var preloadDiffMenuData = {
1085 1107 results: [
1086 1108
1087 1109 ## Whitespace change
1088 1110 % if request.GET.get('ignorews', '') == '1':
1089 1111 {
1090 1112 id: 2,
1091 1113 text: _gettext('Show whitespace changes'),
1092 1114 action: function () {},
1093 1115 url: "${h.current_route_path(request, ignorews=0)|n}"
1094 1116 },
1095 1117 % else:
1096 1118 {
1097 1119 id: 2,
1098 1120 text: _gettext('Hide whitespace changes'),
1099 1121 action: function () {},
1100 1122 url: "${h.current_route_path(request, ignorews=1)|n}"
1101 1123 },
1102 1124 % endif
1103 1125
1104 1126 ## FULL CONTEXT
1105 1127 % if request.GET.get('fullcontext', '') == '1':
1106 1128 {
1107 1129 id: 3,
1108 1130 text: _gettext('Hide full context diff'),
1109 1131 action: function () {},
1110 1132 url: "${h.current_route_path(request, fullcontext=0)|n}"
1111 1133 },
1112 1134 % else:
1113 1135 {
1114 1136 id: 3,
1115 1137 text: _gettext('Show full context diff'),
1116 1138 action: function () {},
1117 1139 url: "${h.current_route_path(request, fullcontext=1)|n}"
1118 1140 },
1119 1141 % endif
1120 1142
1121 1143 ]
1122 1144 };
1123 1145
1124 1146 var diffMenuId = "#diff_menu_" + "${diffset_container_id}";
1125 1147 $(diffMenuId).select2({
1126 1148 minimumResultsForSearch: -1,
1127 1149 containerCssClass: "drop-menu-no-width",
1128 1150 dropdownCssClass: "drop-menu-dropdown",
1129 1151 dropdownAutoWidth: true,
1130 1152 data: preloadDiffMenuData,
1131 1153 placeholder: "${_('...')}",
1132 1154 });
1133 1155 $(diffMenuId).on('select2-selecting', function (e) {
1134 1156 e.choice.action();
1135 1157 if (e.choice.url !== null) {
1136 1158 window.location = e.choice.url
1137 1159 }
1138 1160 });
1139 1161 toggleExpand = function (el, diffsetEl) {
1140 1162 var el = $(el);
1141 1163 if (el.hasClass('collapsed')) {
1142 1164 $('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', false);
1143 1165 el.removeClass('collapsed');
1144 1166 el.html(
1145 1167 '<i class="icon-minus-squared-alt icon-no-margin"></i>' +
1146 1168 _gettext('Collapse all files'));
1147 1169 }
1148 1170 else {
1149 1171 $('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', true);
1150 1172 el.addClass('collapsed');
1151 1173 el.html(
1152 1174 '<i class="icon-plus-squared-alt icon-no-margin"></i>' +
1153 1175 _gettext('Expand all files'));
1154 1176 }
1155 1177 updateSticky()
1156 1178 };
1157 1179
1158 1180 toggleCommitExpand = function (el) {
1159 1181 var $el = $(el);
1160 1182 var commits = $el.data('toggleCommitsCnt');
1161 1183 var collapseMsg = _ngettext('Collapse {0} commit', 'Collapse {0} commits', commits).format(commits);
1162 1184 var expandMsg = _ngettext('Expand {0} commit', 'Expand {0} commits', commits).format(commits);
1163 1185
1164 1186 if ($el.hasClass('collapsed')) {
1165 1187 $('.compare_select').show();
1166 1188 $('.compare_select_hidden').hide();
1167 1189
1168 1190 $el.removeClass('collapsed');
1169 1191 $el.html(
1170 1192 '<i class="icon-minus-squared-alt icon-no-margin"></i>' +
1171 1193 collapseMsg);
1172 1194 }
1173 1195 else {
1174 1196 $('.compare_select').hide();
1175 1197 $('.compare_select_hidden').show();
1176 1198 $el.addClass('collapsed');
1177 1199 $el.html(
1178 1200 '<i class="icon-plus-squared-alt icon-no-margin"></i>' +
1179 1201 expandMsg);
1180 1202 }
1181 1203 updateSticky();
1182 1204 };
1183 1205
1184 1206 // get stored diff mode and pre-enable it
1185 1207 if (templateContext.session_attrs.wide_diff_mode === "true") {
1186 1208 Rhodecode.comments.toggleWideMode(null);
1187 1209 $('.toggle-wide-diff').addClass('btn-active');
1188 1210 updateSticky();
1189 1211 }
1190 1212 });
1191 1213 </script>
1192 1214
1193 1215 </%def>
@@ -1,326 +1,326 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 <%inherit file="/base/base.mako"/>
4 4
5 5 <%def name="title()">
6 6 ${_('%s Changelog') % c.repo_name}
7 7 %if c.changelog_for_path:
8 8 /${c.changelog_for_path}
9 9 %endif
10 10 %if c.rhodecode_name:
11 11 &middot; ${h.branding(c.rhodecode_name)}
12 12 %endif
13 13 </%def>
14 14
15 15 <%def name="breadcrumbs_links()">
16 16 %if c.changelog_for_path:
17 17 /${c.changelog_for_path}
18 18 %endif
19 19 </%def>
20 20
21 21 <%def name="menu_bar_nav()">
22 22 ${self.menu_items(active='repositories')}
23 23 </%def>
24 24
25 25 <%def name="menu_bar_subnav()">
26 26 ${self.repo_menu(active='commits')}
27 27 </%def>
28 28
29 29 <%def name="main()">
30 30
31 31 <div class="box">
32 32
33 33 <div class="title">
34 34 <div id="filter_changelog">
35 35 ${h.hidden('branch_filter')}
36 36 %if c.selected_name:
37 37 <div class="btn btn-default" id="clear_filter" >
38 38 ${_('Clear filter')}
39 39 </div>
40 40 %endif
41 41 </div>
42 42 <div class="pull-left obsolete-toggle">
43 43 % if h.is_hg(c.rhodecode_repo):
44 44 % if c.show_hidden:
45 45 <a class="action-link" href="${h.current_route_path(request, evolve=0)}">${_('Hide obsolete/hidden')}</a>
46 46 % else:
47 47 <a class="action-link" href="${h.current_route_path(request, evolve=1)}">${_('Show obsolete/hidden')}</a>
48 48 % endif
49 49 % else:
50 50 <span class="action-link disabled">${_('Show hidden')}</span>
51 51 % endif
52 52 </div>
53 53 <ul class="links">
54 54 <li>
55 55
56 56 %if c.rhodecode_db_repo.fork:
57 57 <span>
58 58 <a id="compare_fork_button"
59 59 title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
60 60 class="btn btn-small"
61 61 href="${h.route_path('repo_compare',
62 62 repo_name=c.rhodecode_db_repo.fork.repo_name,
63 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
64 source_ref=c.rhodecode_db_repo.landing_rev[1],
65 target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
66 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
63 source_ref_type=c.rhodecode_db_repo.landing_ref_type,
64 source_ref=c.rhodecode_db_repo.landing_ref_name,
65 target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_ref_type,
66 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_ref_name,
67 67 _query=dict(merge=1, target_repo=c.repo_name))}"
68 68 >
69 69 ${_('Compare fork with Parent (%s)' % c.rhodecode_db_repo.fork.repo_name)}
70 70 </a>
71 71 </span>
72 72 %endif
73 73
74 74 ## pr open link
75 75 %if h.is_hg(c.rhodecode_repo) or h.is_git(c.rhodecode_repo):
76 76 <span>
77 77 <a id="open_new_pull_request" class="btn btn-small btn-success" href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">
78 78 ${_('Open new pull request')}
79 79 </a>
80 80 </span>
81 81 %endif
82 82
83 83 </li>
84 84 </ul>
85 85 </div>
86 86
87 87 % if c.pagination:
88 88 <script type="text/javascript" src="${h.asset('js/src/plugins/jquery.commits-graph.js')}"></script>
89 89
90 90 <div class="graph-header">
91 91 ${self.breadcrumbs('breadcrumbs_light')}
92 92 </div>
93 93
94 94 <div id="graph">
95 95 <div class="graph-col-wrapper">
96 96 <div id="graph_nodes">
97 97 <div id="graph_canvas"></div>
98 98 </div>
99 99 <div id="graph_content" class="graph_full_width">
100 100
101 101 <div class="table">
102 102 <table id="changesets" class="rctable">
103 103 <tr>
104 104 ## checkbox
105 105 <th colspan="4">
106 106 ## clear selection
107 107 <div title="${_('Clear selection')}" class="btn btn-sm" id="rev_range_clear" style="display:none">
108 108 <i class="icon-cancel-circled2"></i>
109 109 </div>
110 110 <div class="btn btn-sm disabled" disabled="disabled" id="rev_range_more" style="display:none;">${_('Select second commit')}</div>
111 111 <a href="#" class="btn btn-success btn-sm" id="rev_range_container" style="display:none;"></a>
112 112 </th>
113 113
114 114 ## commit message expand arrow
115 115 <th></th>
116 116 <th>${_('Commit Message')}</th>
117 117
118 118 <th>${_('Age')}</th>
119 119 <th>${_('Author')}</th>
120 120
121 121 <th>${_('Refs')}</th>
122 122 ## comments
123 123 <th></th>
124 124 </tr>
125 125
126 126 <tbody class="commits-range">
127 127 <%include file='changelog_elements.mako'/>
128 128 </tbody>
129 129 </table>
130 130 </div>
131 131 </div>
132 132 <div class="pagination-wh pagination-left">
133 133 ${c.pagination.render()}
134 134 </div>
135 135 <div id="commit-counter" data-total=${c.total_cs} class="pull-right">
136 136 ${_ungettext('showing %d out of %d commit', 'showing %d out of %d commits', c.showing_commits) % (c.showing_commits, c.total_cs)}
137 137 </div>
138 138 </div>
139 139
140 140 <script type="text/javascript">
141 141 var cache = {};
142 142 $(function(){
143 143
144 144 // Create links to commit ranges when range checkboxes are selected
145 145 var $commitCheckboxes = $('.commit-range');
146 146 // cache elements
147 147 var $commitRangeMore = $('#rev_range_more');
148 148 var $commitRangeContainer = $('#rev_range_container');
149 149 var $commitRangeClear = $('#rev_range_clear');
150 150
151 151 var checkboxRangeSelector = function(e){
152 152 var selectedCheckboxes = [];
153 153 for (pos in $commitCheckboxes){
154 154 if($commitCheckboxes[pos].checked){
155 155 selectedCheckboxes.push($commitCheckboxes[pos]);
156 156 }
157 157 }
158 158 var open_new_pull_request = $('#open_new_pull_request');
159 159
160 160 if (open_new_pull_request) {
161 161 var selected_changes = selectedCheckboxes.length;
162 162 open_new_pull_request.hide();
163 163 if (selected_changes == 1) {
164 164 open_new_pull_request.html(_gettext('Open new pull request for selected commit'));
165 165 } else {
166 166 open_new_pull_request.html(_gettext('Open new pull request'));
167 167 }
168 168 open_new_pull_request.show();
169 169 }
170 170
171 171 if (selectedCheckboxes.length > 0) {
172 172 $('#compare_fork_button').hide();
173 173 var commitStart = $(selectedCheckboxes[selectedCheckboxes.length-1]).data();
174 174
175 175 var revStart = commitStart.commitId;
176 176
177 177 var commitEnd = $(selectedCheckboxes[0]).data();
178 178 var revEnd = commitEnd.commitId;
179 179
180 180 var lbl_start = '{0}'.format(commitStart.commitIdx, commitStart.shortId);
181 181 var lbl_end = '{0}'.format(commitEnd.commitIdx, commitEnd.shortId);
182 182
183 183 var url = pyroutes.url('repo_commit', {'repo_name': '${c.repo_name}', 'commit_id': revStart+'...'+revEnd});
184 184 var link = _gettext('Show commit range {0} ... {1}').format(lbl_start, lbl_end);
185 185
186 186 if (selectedCheckboxes.length > 1) {
187 187 $commitRangeClear.show();
188 188 $commitRangeMore.hide();
189 189
190 190 $commitRangeContainer
191 191 .attr('href',url)
192 192 .html(link)
193 193 .show();
194 194
195 195
196 196 } else {
197 197 $commitRangeContainer.hide();
198 198 $commitRangeClear.show();
199 199 $commitRangeMore.show();
200 200 }
201 201
202 202 // pull-request link
203 203 if (selectedCheckboxes.length == 1){
204 204 var _url = pyroutes.url('pullrequest_new', {'repo_name': '${c.repo_name}', 'commit': revEnd});
205 205 open_new_pull_request.attr('href', _url);
206 206 } else {
207 207 var _url = pyroutes.url('pullrequest_new', {'repo_name': '${c.repo_name}'});
208 208 open_new_pull_request.attr('href', _url);
209 209 }
210 210
211 211 } else {
212 212 $commitRangeContainer.hide();
213 213 $commitRangeClear.hide();
214 214 $commitRangeMore.hide();
215 215
216 216 %if c.branch_name:
217 217 var _url = pyroutes.url('pullrequest_new', {'repo_name': '${c.repo_name}', 'branch':'${c.branch_name}'});
218 218 open_new_pull_request.attr('href', _url);
219 219 %else:
220 220 var _url = pyroutes.url('pullrequest_new', {'repo_name': '${c.repo_name}'});
221 221 open_new_pull_request.attr('href', _url);
222 222 %endif
223 223 $('#compare_fork_button').show();
224 224 }
225 225 };
226 226
227 227 $commitCheckboxes.on('click', checkboxRangeSelector);
228 228
229 229 $commitRangeClear.on('click',function(e) {
230 230 $commitCheckboxes.attr('checked', false);
231 231 checkboxRangeSelector();
232 232 e.preventDefault();
233 233 });
234 234
235 235 // make sure the buttons are consistent when navigate back and forth
236 236 checkboxRangeSelector();
237 237
238 238 var msgs = $('.message');
239 239 // get first element height
240 240 var el = $('#graph_content .container')[0];
241 241 var row_h = el.clientHeight;
242 242 for (var i=0; i < msgs.length; i++) {
243 243 var m = msgs[i];
244 244
245 245 var h = m.clientHeight;
246 246 var pad = $(m).css('padding');
247 247 if (h > row_h) {
248 248 var offset = row_h - (h+12);
249 249 $(m.nextElementSibling).css('display','block');
250 250 $(m.nextElementSibling).css('margin-top',offset+'px');
251 251 }
252 252 }
253 253
254 254 $("#clear_filter").on("click", function() {
255 255 var filter = {'repo_name': '${c.repo_name}'};
256 256 window.location = pyroutes.url('repo_commits', filter);
257 257 });
258 258
259 259 $("#branch_filter").select2({
260 260 'dropdownAutoWidth': true,
261 261 'width': 'resolve',
262 262 'placeholder': "${c.selected_name or _('Branch filter')}",
263 263 containerCssClass: "drop-menu",
264 264 dropdownCssClass: "drop-menu-dropdown",
265 265 query: function(query){
266 266 var key = 'cache';
267 267 var cached = cache[key] ;
268 268 if(cached) {
269 269 var data = {results: []};
270 270 //filter results
271 271 $.each(cached.results, function(){
272 272 var section = this.text;
273 273 var children = [];
274 274 $.each(this.children, function(){
275 275 if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
276 276 children.push({'id': this.id, 'text': this.text, 'type': this.type})
277 277 }
278 278 });
279 279 data.results.push({'text': section, 'children': children});
280 280 query.callback({results: data.results});
281 281 });
282 282 }else{
283 283 $.ajax({
284 284 url: pyroutes.url('repo_refs_changelog_data', {'repo_name': '${c.repo_name}'}),
285 285 data: {},
286 286 dataType: 'json',
287 287 type: 'GET',
288 288 success: function(data) {
289 289 cache[key] = data;
290 290 query.callback({results: data.results});
291 291 }
292 292 })
293 293 }
294 294 }
295 295 });
296 296 $('#branch_filter').on('change', function(e){
297 297 var data = $('#branch_filter').select2('data');
298 298 //type: branch_closed
299 299 var selected = data.text;
300 300 var filter = {'repo_name': '${c.repo_name}'};
301 301 if(data.type == 'branch' || data.type == 'branch_closed'){
302 302 filter["branch"] = selected;
303 303 if (data.type == 'branch_closed') {
304 304 filter["evolve"] = '1';
305 305 }
306 306 }
307 307 else if (data.type == 'book'){
308 308 filter["bookmark"] = selected;
309 309 }
310 310 window.location = pyroutes.url('repo_commits', filter);
311 311 });
312 312
313 313 commitsController = new CommitsController();
314 314 % if not c.changelog_for_path:
315 315 commitsController.reloadGraph();
316 316 % endif
317 317
318 318 });
319 319
320 320 </script>
321 321 </div>
322 322 % else:
323 323 ${_('There are no changes yet')}
324 324 % endif
325 325 </div>
326 326 </%def>
@@ -1,308 +1,308 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.mako"/>
3 3 <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
4 4
5 5 <%def name="title()">
6 6 %if c.compare_home:
7 7 ${_('%s Compare') % c.repo_name}
8 8 %else:
9 9 ${_('%s Compare') % c.repo_name} - ${'%s@%s' % (c.source_repo.repo_name, c.source_ref)} &gt; ${'%s@%s' % (c.target_repo.repo_name, c.target_ref)}
10 10 %endif
11 11 %if c.rhodecode_name:
12 12 &middot; ${h.branding(c.rhodecode_name)}
13 13 %endif
14 14 </%def>
15 15
16 16 <%def name="breadcrumbs_links()"></%def>
17 17
18 18 <%def name="menu_bar_nav()">
19 19 ${self.menu_items(active='repositories')}
20 20 </%def>
21 21
22 22 <%def name="menu_bar_subnav()">
23 23 ${self.repo_menu(active='compare')}
24 24 </%def>
25 25
26 26 <%def name="main()">
27 27 <script type="text/javascript">
28 28 // set fake commitId on this commit-range page
29 29 templateContext.commit_data.commit_id = "${h.EmptyCommit().raw_id}";
30 30 </script>
31 31
32 32 <div class="box">
33 33 <div class="summary changeset">
34 34 <div class="summary-detail">
35 35 <div class="summary-detail-header">
36 36 <span class="breadcrumbs files_location">
37 37 <h4>
38 38 ${_('Compare Commits')}
39 39 % if c.file_path:
40 40 ${_('for file')} <a href="#${('a_' + h.FID('',c.file_path))}">${c.file_path}</a>
41 41 % endif
42 42
43 43 % if c.commit_ranges:
44 44 <code>
45 45 r${c.commit_ranges[0].idx}:${h.short_id(c.commit_ranges[0].raw_id)}...r${c.commit_ranges[-1].idx}:${h.short_id(c.commit_ranges[-1].raw_id)}
46 46 </code>
47 47 % endif
48 48 </h4>
49 49 </span>
50 50
51 51 <div class="clear-fix"></div>
52 52 </div>
53 53
54 54 <div class="fieldset">
55 55 <div class="left-label-summary">
56 56 <p class="spacing">${_('Target')}:</p>
57 57 <div class="right-label-summary">
58 58 <div class="code-header" >
59 59 <div class="compare_header">
60 60 ## The hidden elements are replaced with a select2 widget
61 61 ${h.hidden('compare_source')}
62 62 </div>
63 63 </div>
64 64 </div>
65 65 </div>
66 66 </div>
67 67
68 68 <div class="fieldset">
69 69 <div class="left-label-summary">
70 70 <p class="spacing">${_('Source')}:</p>
71 71 <div class="right-label-summary">
72 72 <div class="code-header" >
73 73 <div class="compare_header">
74 74 ## The hidden elements are replaced with a select2 widget
75 75 ${h.hidden('compare_target')}
76 76 </div>
77 77 </div>
78 78 </div>
79 79 </div>
80 80 </div>
81 81
82 82 <div class="fieldset">
83 83 <div class="left-label-summary">
84 84 <p class="spacing">${_('Actions')}:</p>
85 85 <div class="right-label-summary">
86 86 <div class="code-header" >
87 87 <div class="compare_header">
88 88 <div class="compare-buttons">
89 89 % if c.compare_home:
90 90 <a id="compare_revs" class="btn btn-primary"> ${_('Compare Commits')}</a>
91 91 %if c.rhodecode_db_repo.fork:
92 92
93 93 <a class="btn btn-default" title="${h.tooltip(_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name))}"
94 94 href="${h.route_path('repo_compare',
95 95 repo_name=c.rhodecode_db_repo.fork.repo_name,
96 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
97 source_ref=c.rhodecode_db_repo.landing_rev[1],
98 target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
99 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
96 source_ref_type=c.rhodecode_db_repo.landing_ref_type,
97 source_ref=c.rhodecode_db_repo.landing_ref_name,
98 target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_ref_type,
99 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_ref_name,
100 100 _query=dict(merge=1))}"
101 101 >
102 102 ${_('Compare with origin')}
103 103 </a>
104 104
105 105 %endif
106 106
107 107 <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Swap')}</a>
108 108 <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Comment')}</a>
109 109 <div id="changeset_compare_view_content">
110 110 <div class="help-block">${_('Compare commits, branches, bookmarks or tags.')}</div>
111 111 </div>
112 112
113 113 % elif c.preview_mode:
114 114 <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Compare Commits')}</a>
115 115 <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Swap')}</a>
116 116 <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Comment')}</a>
117 117
118 118 % else:
119 119 <a id="compare_revs" class="btn btn-primary"> ${_('Compare Commits')}</a>
120 120 <a id="btn-swap" class="btn btn-primary" href="${c.swap_url}">${_('Swap')}</a>
121 121
122 122 ## allow comment only if there are commits to comment on
123 123 % if c.diffset and c.diffset.files and c.commit_ranges:
124 124 <a id="compare_changeset_status_toggle" class="btn btn-primary">${_('Comment')}</a>
125 125 % else:
126 126 <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Comment')}</a>
127 127 % endif
128 128 % endif
129 129 </div>
130 130 </div>
131 131 </div>
132 132 </div>
133 133 </div>
134 134 </div>
135 135
136 136 ## commit status form
137 137 <div class="fieldset" id="compare_changeset_status" style="display: none; margin-bottom: -80px;">
138 138 <div class="left-label-summary">
139 139 <p class="spacing">${_('Commit status')}:</p>
140 140 <div class="right-label-summary">
141 141 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
142 142 ## main comment form and it status
143 143 <%
144 144 def revs(_revs):
145 145 form_inputs = []
146 146 for cs in _revs:
147 147 tmpl = '<input type="hidden" data-commit-id="%(cid)s" name="commit_ids" value="%(cid)s">' % {'cid': cs.raw_id}
148 148 form_inputs.append(tmpl)
149 149 return form_inputs
150 150 %>
151 151 <div>
152 152 ${comment.comments(h.route_path('repo_commit_comment_create', repo_name=c.repo_name, commit_id='0'*16), None, is_compare=True, form_extras=revs(c.commit_ranges))}
153 153 </div>
154 154 </div>
155 155 </div>
156 156 </div>
157 157 <div class="clear-fix"></div>
158 158 </div> <!-- end summary-detail -->
159 159 </div> <!-- end summary -->
160 160
161 161 ## use JS script to load it quickly before potentially large diffs render long time
162 162 ## this prevents from situation when large diffs block rendering of select2 fields
163 163 <script type="text/javascript">
164 164
165 165 var cache = {};
166 166
167 167 var formatSelection = function(repoName){
168 168 return function(data, container, escapeMarkup) {
169 169 var selection = data ? this.text(data) : "";
170 170 return escapeMarkup('{0}@{1}'.format(repoName, selection));
171 171 }
172 172 };
173 173
174 174 var feedCompareData = function(query, cachedValue){
175 175 var data = {results: []};
176 176 //filter results
177 177 $.each(cachedValue.results, function() {
178 178 var section = this.text;
179 179 var children = [];
180 180 $.each(this.children, function() {
181 181 if (query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
182 182 children.push({
183 183 'id': this.id,
184 184 'text': this.text,
185 185 'type': this.type
186 186 })
187 187 }
188 188 });
189 189 data.results.push({
190 190 'text': section,
191 191 'children': children
192 192 })
193 193 });
194 194 //push the typed in changeset
195 195 data.results.push({
196 196 'text': _gettext('specify commit'),
197 197 'children': [{
198 198 'id': query.term,
199 199 'text': query.term,
200 200 'type': 'rev'
201 201 }]
202 202 });
203 203 query.callback(data);
204 204 };
205 205
206 206 var loadCompareData = function(repoName, query, cache){
207 207 $.ajax({
208 208 url: pyroutes.url('repo_refs_data', {'repo_name': repoName}),
209 209 data: {},
210 210 dataType: 'json',
211 211 type: 'GET',
212 212 success: function(data) {
213 213 cache[repoName] = data;
214 214 query.callback({results: data.results});
215 215 }
216 216 })
217 217 };
218 218
219 219 var enable_fields = ${"false" if c.preview_mode else "true"};
220 220 $("#compare_source").select2({
221 221 placeholder: "${'%s@%s' % (c.source_repo.repo_name, c.source_ref)}",
222 222 containerCssClass: "drop-menu",
223 223 dropdownCssClass: "drop-menu-dropdown",
224 224 formatSelection: formatSelection("${c.source_repo.repo_name}"),
225 225 dropdownAutoWidth: true,
226 226 query: function(query) {
227 227 var repoName = '${c.source_repo.repo_name}';
228 228 var cachedValue = cache[repoName];
229 229
230 230 if (cachedValue){
231 231 feedCompareData(query, cachedValue);
232 232 }
233 233 else {
234 234 loadCompareData(repoName, query, cache);
235 235 }
236 236 }
237 237 }).select2("enable", enable_fields);
238 238
239 239 $("#compare_target").select2({
240 240 placeholder: "${'%s@%s' % (c.target_repo.repo_name, c.target_ref)}",
241 241 dropdownAutoWidth: true,
242 242 containerCssClass: "drop-menu",
243 243 dropdownCssClass: "drop-menu-dropdown",
244 244 formatSelection: formatSelection("${c.target_repo.repo_name}"),
245 245 query: function(query) {
246 246 var repoName = '${c.target_repo.repo_name}';
247 247 var cachedValue = cache[repoName];
248 248
249 249 if (cachedValue){
250 250 feedCompareData(query, cachedValue);
251 251 }
252 252 else {
253 253 loadCompareData(repoName, query, cache);
254 254 }
255 255 }
256 256 }).select2("enable", enable_fields);
257 257 var initial_compare_source = {id: "${c.source_ref}", type:"${c.source_ref_type}"};
258 258 var initial_compare_target = {id: "${c.target_ref}", type:"${c.target_ref_type}"};
259 259
260 260 $('#compare_revs').on('click', function(e) {
261 261 var source = $('#compare_source').select2('data') || initial_compare_source;
262 262 var target = $('#compare_target').select2('data') || initial_compare_target;
263 263 if (source && target) {
264 264 var url_data = {
265 265 repo_name: "${c.repo_name}",
266 266 source_ref: source.id,
267 267 source_ref_type: source.type,
268 268 target_ref: target.id,
269 269 target_ref_type: target.type
270 270 };
271 271 window.location = pyroutes.url('repo_compare', url_data);
272 272 }
273 273 });
274 274 $('#compare_changeset_status_toggle').on('click', function(e) {
275 275 $('#compare_changeset_status').toggle();
276 276 });
277 277
278 278 </script>
279 279
280 280 ## table diff data
281 281 <div class="table">
282 282 % if not c.compare_home:
283 283 <div id="changeset_compare_view_content">
284 284 <div class="pull-left">
285 285 <div class="btn-group">
286 286 <a class="${('collapsed' if c.collapse_all_commits else '')}" href="#expand-commits" onclick="toggleCommitExpand(this); return false" data-toggle-commits-cnt=${len(c.commit_ranges)} >
287 287 % if c.collapse_all_commits:
288 288 <i class="icon-plus-squared-alt icon-no-margin"></i>
289 289 ${_ungettext('Expand {} commit', 'Expand {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
290 290 % else:
291 291 <i class="icon-minus-squared-alt icon-no-margin"></i>
292 292 ${_ungettext('Collapse {} commit', 'Collapse {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
293 293 % endif
294 294 </a>
295 295 </div>
296 296 </div>
297 297 <div style="padding:0 10px 10px 0px" class="pull-left"></div>
298 298 ## commit compare generated below
299 299 <%include file="compare_commits.mako"/>
300 300 ${cbdiffs.render_diffset_menu(c.diffset)}
301 301 ${cbdiffs.render_diffset(c.diffset)}
302 302 </div>
303 303 % endif
304 304
305 305 </div>
306 306 </div>
307 307
308 308 </%def>
@@ -1,603 +1,642 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 ## helpers
4 4 <%def name="tag_button(text, tag_type=None)">
5 5 <%
6 6 color_scheme = {
7 7 'default': 'border:1px solid #979797;color:#666666;background-color:#f9f9f9',
8 8 'approved': 'border:1px solid #0ac878;color:#0ac878;background-color:#f9f9f9',
9 9 'rejected': 'border:1px solid #e85e4d;color:#e85e4d;background-color:#f9f9f9',
10 10 'under_review': 'border:1px solid #ffc854;color:#ffc854;background-color:#f9f9f9',
11 11 }
12 12
13 13 css_style = ';'.join([
14 14 'display:inline',
15 15 'border-radius:2px',
16 16 'font-size:12px',
17 17 'padding:.2em',
18 18 ])
19 19
20 20 %>
21 21 <pre style="${css_style}; ${color_scheme.get(tag_type, color_scheme['default'])}">${text}</pre>
22 22 </%def>
23 23
24 24 <%def name="status_text(text, tag_type=None)">
25 25 <%
26 26 color_scheme = {
27 27 'default': 'color:#666666',
28 28 'approved': 'color:#0ac878',
29 29 'rejected': 'color:#e85e4d',
30 30 'under_review': 'color:#ffc854',
31 31 }
32 32 %>
33 33 <span style="font-weight:bold;font-size:12px;padding:.2em;${color_scheme.get(tag_type, color_scheme['default'])}">${text}</span>
34 34 </%def>
35 35
36 36 <%def name="gravatar_img(email, size=16)">
37 37 <%
38 38 css_style = ';'.join([
39 39 'padding: 0',
40 40 'margin: -4px 0',
41 41 'border-radius: 50%',
42 42 'box-sizing: content-box',
43 43 'display: inline',
44 44 'line-height: 1em',
45 45 'min-width: 16px',
46 46 'min-height: 16px',
47 47 ])
48 48 %>
49 49
50 50 <img alt="gravatar" style="${css_style}" src="${h.gravatar_url(email, size)}" height="${size}" width="${size}">
51 51 </%def>
52 52
53 53 <%def name="link_css()">\
54 54 <%
55 55 css_style = ';'.join([
56 56 'color:#427cc9',
57 57 'text-decoration:none',
58 58 'cursor:pointer'
59 59 ])
60 60 %>\
61 61 ${css_style}\
62 62 </%def>
63 63
64 64 ## Constants
65 65 <%
66 66 text_regular = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', Helvetica, sans-serif"
67 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
71 71 ## headers we additionally can set for email
72 72 <%def name="headers()" filter="n,trim"></%def>
73 73
74 74 <%def name="plaintext_footer()" filter="trim">
75 75 ${_('This is a notification from RhodeCode.')} ${instance_url}
76 76 </%def>
77 77
78 78 <%def name="body_plaintext()" filter="n,trim">
79 79 ## this example is not called itself but overridden in each template
80 80 ## the plaintext_footer should be at the bottom of both html and text emails
81 81 ${self.plaintext_footer()}
82 82 </%def>
83 83
84 84 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
85 85 <html xmlns="http://www.w3.org/1999/xhtml">
86 86 <head>
87 87 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
88 88 <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
89 89 <title>${self.subject()}</title>
90 90 <style type="text/css">
91 91 /* Based on The MailChimp Reset INLINE: Yes. */
92 92 #outlook a {
93 93 padding: 0;
94 94 }
95 95
96 96 /* Force Outlook to provide a "view in browser" menu link. */
97 97 body {
98 98 width: 100% !important;
99 99 -webkit-text-size-adjust: 100%;
100 100 -ms-text-size-adjust: 100%;
101 101 margin: 0;
102 102 padding: 0;
103 103 font-family: ${text_regular|n};
104 color: #000000;
104 105 }
105 106
106 107 /* Prevent Webkit and Windows Mobile platforms from changing default font sizes.*/
107 108 .ExternalClass {
108 109 width: 100%;
109 110 }
110 111
111 112 /* Force Hotmail to display emails at full width */
112 113 .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {
113 114 line-height: 100%;
114 115 }
115 116
116 117 /* Forces Hotmail to display normal line spacing. More on that: http://www.emailonacid.com/forum/viewthread/43/ */
117 118 #backgroundTable {
118 119 margin: 0;
119 120 padding: 0;
120 121 line-height: 100% !important;
121 122 }
122 123
123 124 /* End reset */
124 125
125 126 /* defaults for images*/
126 127 img {
127 128 outline: none;
128 129 text-decoration: none;
129 130 -ms-interpolation-mode: bicubic;
130 131 }
131 132
132 133 a img {
133 134 border: none;
134 135 }
135 136
136 137 .image_fix {
137 138 display: block;
138 139 }
139 140
140 141 body {
141 142 line-height: 1.2em;
142 143 }
143 144
144 145 p {
145 146 margin: 0 0 20px;
146 147 }
147 148
148 149 h1, h2, h3, h4, h5, h6 {
149 150 color: #323232 !important;
150 151 }
151 152
152 153 a {
153 154 color: #427cc9;
154 155 text-decoration: none;
155 156 outline: none;
156 157 cursor: pointer;
157 158 }
158 159
159 160 a:focus {
160 161 outline: none;
161 162 }
162 163
163 164 a:hover {
164 165 color: #305b91;
165 166 }
166 167
167 168 h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
168 169 color: #427cc9 !important;
169 170 text-decoration: none !important;
170 171 }
171 172
172 173 h1 a:active, h2 a:active, h3 a:active, h4 a:active, h5 a:active, h6 a:active {
173 174 color: #305b91 !important;
174 175 }
175 176
176 177 h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited {
177 178 color: #305b91 !important;
178 179 }
179 180
180 181 table {
181 182 font-size: 13px;
182 183 border-collapse: collapse;
183 184 mso-table-lspace: 0pt;
184 185 mso-table-rspace: 0pt;
185 186 }
186 187
187 188 table tr {
188 189 display: table-row;
189 190 vertical-align: inherit;
190 191 border-color: inherit;
191 192 border-spacing: 0 3px;
192 193 }
193 194
194 195 table td {
195 196 padding: .65em 1em .65em 0;
196 197 border-collapse: collapse;
197 198 vertical-align: top;
198 199 text-align: left;
199 200 }
200 201
201 202 input {
202 203 display: inline;
203 204 border-radius: 2px;
204 205 border: 1px solid #dbd9da;
205 206 padding: .5em;
206 207 }
207 208
208 209 input:focus {
209 210 outline: 1px solid #979797
210 211 }
211 212
212 213 code {
213 214 font-family: ${text_monospace|n};
215 white-space: pre-line !important;
216 color: #000000;
217 }
218
219 ul.changes-ul {
220 list-style: none;
221 list-style-type: none;
222 padding: 0;
223 margin: 10px 0;
224 }
225 ul.changes-ul li {
226 list-style: none;
227 list-style-type: none;
228 margin: 2px 0;
214 229 }
215 230
216 231 @media only screen and (-webkit-min-device-pixel-ratio: 2) {
217 232 /* Put your iPhone 4g styles in here */
218 233 }
219 234
220 235 /* Android targeting */
221 236 @media only screen and (-webkit-device-pixel-ratio:.75){
222 237 /* Put CSS for low density (ldpi) Android layouts in here */
223 238 }
224 239 @media only screen and (-webkit-device-pixel-ratio:1){
225 240 /* Put CSS for medium density (mdpi) Android layouts in here */
226 241 }
227 242 @media only screen and (-webkit-device-pixel-ratio:1.5){
228 243 /* Put CSS for high density (hdpi) Android layouts in here */
229 244 }
230 245 /* end Android targeting */
231 246
232 247 /** MARKDOWN styling **/
233 248 div.markdown-block {
234 249 clear: both;
235 250 overflow: hidden;
236 251 margin: 0;
237 252 padding: 3px 5px 3px
238 253 }
239 254
240 div.markdown-block h1, div.markdown-block h2, div.markdown-block h3, div.markdown-block h4, div.markdown-block h5, div.markdown-block h6 {
255 div.markdown-block h1,
256 div.markdown-block h2,
257 div.markdown-block h3,
258 div.markdown-block h4,
259 div.markdown-block h5,
260 div.markdown-block h6 {
241 261 border-bottom: none !important;
242 262 padding: 0 !important;
243 263 overflow: visible !important
244 264 }
245 265
246 div.markdown-block h1, div.markdown-block h2 {
266 div.markdown-block h1,
267 div.markdown-block h2 {
247 268 border-bottom: 1px #e6e5e5 solid !important
248 269 }
249 270
250 271 div.markdown-block h1 {
251 272 font-size: 32px;
252 273 margin: 15px 0 15px 0 !important;
253 274 padding-bottom: 5px !important
254 275 }
255 276
256 277 div.markdown-block h2 {
257 278 font-size: 24px !important;
258 279 margin: 34px 0 10px 0 !important;
259 280 padding-top: 15px !important;
260 281 padding-bottom: 8px !important
261 282 }
262 283
263 284 div.markdown-block h3 {
264 285 font-size: 18px !important;
265 286 margin: 30px 0 8px 0 !important;
266 287 padding-bottom: 2px !important
267 288 }
268 289
269 290 div.markdown-block h4 {
270 291 font-size: 13px !important;
271 292 margin: 18px 0 3px 0 !important
272 293 }
273 294
274 295 div.markdown-block h5 {
275 296 font-size: 12px !important;
276 297 margin: 15px 0 3px 0 !important
277 298 }
278 299
279 300 div.markdown-block h6 {
280 301 font-size: 12px;
281 302 color: #777777;
282 303 margin: 15px 0 3px 0 !important
283 304 }
284 305
285 306 div.markdown-block hr {
286 307 border: 0;
287 308 color: #e6e5e5;
288 309 background-color: #e6e5e5;
289 310 height: 3px;
290 311 margin-bottom: 13px
291 312 }
292 313
293 div.markdown-block ol, div.markdown-block ul, div.markdown-block p, div.markdown-block blockquote, div.markdown-block dl, div.markdown-block li, div.markdown-block table {
314 div.markdown-block ol,
315 div.markdown-block ul,
316 div.markdown-block p,
317 div.markdown-block blockquote,
318 div.markdown-block dl,
319 div.markdown-block li,
320 div.markdown-block table {
294 321 margin: 3px 0 13px 0 !important;
295 322 color: #424242 !important;
296 323 font-size: 13px !important;
297 324 font-family: ${text_regular|n};
298 325 font-weight: normal !important;
299 326 overflow: visible !important;
300 327 line-height: 140% !important
301 328 }
302 329
303 330 div.markdown-block pre {
304 331 margin: 3px 0 13px 0 !important;
305 332 padding: .5em;
306 333 color: #424242 !important;
307 334 font-size: 13px !important;
308 335 overflow: visible !important;
309 336 line-height: 140% !important;
310 337 background-color: #F5F5F5
311 338 }
312 339
313 340 div.markdown-block img {
314 341 border-style: none;
315 342 background-color: #fff;
316 343 padding-right: 20px;
317 344 max-width: 100%
318 345 }
319 346
320 347 div.markdown-block strong {
321 348 font-weight: 600;
322 349 margin: 0
323 350 }
324 351
325 352 div.markdown-block ul.checkbox, div.markdown-block ol.checkbox {
326 353 padding-left: 20px !important;
327 354 margin-top: 0 !important;
328 355 margin-bottom: 18px !important
329 356 }
330 357
331 358 div.markdown-block ul, div.markdown-block ol {
332 359 padding-left: 30px !important;
333 360 margin-top: 0 !important;
334 361 margin-bottom: 18px !important
335 362 }
336 363
337 364 div.markdown-block ul.checkbox li, div.markdown-block ol.checkbox li {
338 365 list-style: none !important;
339 366 margin: 6px !important;
340 367 padding: 0 !important
341 368 }
342 369
343 370 div.markdown-block ul li, div.markdown-block ol li {
344 371 list-style: disc !important;
345 372 margin: 6px !important;
346 373 padding: 0 !important
347 374 }
348 375
349 376 div.markdown-block ol li {
350 377 list-style: decimal !important
351 378 }
352 379
353 380 div.markdown-block #message {
354 381 -webkit-border-radius: 2px;
355 382 -moz-border-radius: 2px;
356 383 border-radius: 2px;
357 384 border: 1px solid #dbd9da;
358 385 display: block;
359 386 width: 100%;
360 387 height: 60px;
361 388 margin: 6px 0
362 389 }
363 390
364 391 div.markdown-block button, div.markdown-block #ws {
365 392 font-size: 13px;
366 393 padding: 4px 6px;
367 394 -webkit-border-radius: 2px;
368 395 -moz-border-radius: 2px;
369 396 border-radius: 2px;
370 397 border: 1px solid #dbd9da;
371 398 background-color: #eeeeee
372 399 }
373 400
374 div.markdown-block code, div.markdown-block pre, div.markdown-block #ws, div.markdown-block #message {
401 div.markdown-block code,
402 div.markdown-block pre,
403 div.markdown-block #ws,
404 div.markdown-block #message {
375 405 font-family: ${text_monospace|n};
376 406 font-size: 11px;
377 407 -webkit-border-radius: 2px;
378 408 -moz-border-radius: 2px;
379 409 border-radius: 2px;
380 background-color: white;
410 background-color: #FFFFFF;
381 411 color: #7E7F7F
382 412 }
383 413
384 414 div.markdown-block code {
385 border: 1px solid #eeeeee;
415 border: 1px solid #7E7F7F;
386 416 margin: 0 2px;
387 417 padding: 0 5px
388 418 }
389 419
390 420 div.markdown-block pre {
391 border: 1px solid #dbd9da;
421 border: 1px solid #7E7F7F;
392 422 overflow: auto;
393 423 padding: .5em;
394 background-color: #F5F5F5
424 background-color: #FFFFFF;
395 425 }
396 426
397 427 div.markdown-block pre > code {
398 428 border: 0;
399 429 margin: 0;
400 430 padding: 0
401 431 }
402 432
403 433 div.rst-block {
404 434 clear: both;
405 435 overflow: hidden;
406 436 margin: 0;
407 437 padding: 3px 5px 3px
408 438 }
409 439
410 440 div.rst-block h2 {
411 441 font-weight: normal
412 442 }
413 443
414 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
444 div.rst-block h1,
445 div.rst-block h2,
446 div.rst-block h3,
447 div.rst-block h4,
448 div.rst-block h5,
449 div.rst-block h6 {
415 450 border-bottom: 0 !important;
416 451 margin: 0 !important;
417 452 padding: 0 !important;
418 453 line-height: 1.5em !important
419 454 }
420 455
421 456 div.rst-block h1:first-child {
422 457 padding-top: .25em !important
423 458 }
424 459
425 460 div.rst-block h2, div.rst-block h3 {
426 461 margin: 1em 0 !important
427 462 }
428 463
429 464 div.rst-block h1, div.rst-block h2 {
430 465 border-bottom: 1px #e6e5e5 solid !important
431 466 }
432 467
433 468 div.rst-block h2 {
434 469 margin-top: 1.5em !important;
435 470 padding-top: .5em !important
436 471 }
437 472
438 473 div.rst-block p {
439 474 color: black !important;
440 475 margin: 1em 0 !important;
441 476 line-height: 1.5em !important
442 477 }
443 478
444 479 div.rst-block ul {
445 480 list-style: disc !important;
446 481 margin: 1em 0 1em 2em !important;
447 482 clear: both
448 483 }
449 484
450 485 div.rst-block ol {
451 486 list-style: decimal;
452 487 margin: 1em 0 1em 2em !important
453 488 }
454 489
455 490 div.rst-block pre, div.rst-block code {
456 491 font: 12px "Bitstream Vera Sans Mono", "Courier", monospace
457 492 }
458 493
459 494 div.rst-block code {
460 495 font-size: 12px !important;
461 496 background-color: ghostWhite !important;
462 497 color: #444 !important;
463 498 padding: 0 .2em !important;
464 border: 1px solid #dedede !important
499 border: 1px solid #7E7F7F !important
465 500 }
466 501
467 502 div.rst-block pre code {
468 503 padding: 0 !important;
469 504 font-size: 12px !important;
470 505 background-color: #eee !important;
471 506 border: none !important
472 507 }
473 508
474 509 div.rst-block pre {
475 510 margin: 1em 0;
476 511 padding: 15px;
477 border: 1px solid #eeeeee;
512 border: 1px solid #7E7F7F;
478 513 -webkit-border-radius: 2px;
479 514 -moz-border-radius: 2px;
480 515 border-radius: 2px;
481 516 overflow: auto;
482 517 font-size: 12px;
483 518 color: #444;
484 background-color: #F5F5F5
519 background-color: #FFFFFF;
520 }
521
522 .clear-both {
523 clear:both;
485 524 }
486 525
487 526 /*elasticmatch is custom rhodecode tag*/
488 527 .codehilite .c-ElasticMatch {
489 background-color: #faffa6;
490 padding: 0.2em;
528 background-color: #faffa6;
529 padding: 0.2em;
491 530 }
492 531
493 532 .codehilite .c-ElasticMatch { background-color: #faffa6; padding: 0.2em;}
494 533 .codehilite .hll { background-color: #ffffcc }
495 534 .codehilite .c { color: #408080; font-style: italic } /* Comment */
496 535 .codehilite .err { border: none } /* Error */
497 536 .codehilite .k { color: #008000; font-weight: bold } /* Keyword */
498 537 .codehilite .o { color: #666666 } /* Operator */
499 538 .codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
500 539 .codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
501 540 .codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
502 541 .codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
503 542 .codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
504 543 .codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
505 544 .codehilite .gd { color: #A00000 } /* Generic.Deleted */
506 545 .codehilite .ge { font-style: italic } /* Generic.Emph */
507 546 .codehilite .gr { color: #FF0000 } /* Generic.Error */
508 547 .codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
509 548 .codehilite .gi { color: #00A000 } /* Generic.Inserted */
510 549 .codehilite .go { color: #888888 } /* Generic.Output */
511 550 .codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
512 551 .codehilite .gs { font-weight: bold } /* Generic.Strong */
513 552 .codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
514 553 .codehilite .gt { color: #0044DD } /* Generic.Traceback */
515 554 .codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
516 555 .codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
517 556 .codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
518 557 .codehilite .kp { color: #008000 } /* Keyword.Pseudo */
519 558 .codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
520 559 .codehilite .kt { color: #B00040 } /* Keyword.Type */
521 560 .codehilite .m { color: #666666 } /* Literal.Number */
522 561 .codehilite .s { color: #BA2121 } /* Literal.String */
523 562 .codehilite .na { color: #7D9029 } /* Name.Attribute */
524 563 .codehilite .nb { color: #008000 } /* Name.Builtin */
525 564 .codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
526 565 .codehilite .no { color: #880000 } /* Name.Constant */
527 566 .codehilite .nd { color: #AA22FF } /* Name.Decorator */
528 567 .codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
529 568 .codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
530 569 .codehilite .nf { color: #0000FF } /* Name.Function */
531 570 .codehilite .nl { color: #A0A000 } /* Name.Label */
532 571 .codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
533 572 .codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
534 573 .codehilite .nv { color: #19177C } /* Name.Variable */
535 574 .codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
536 575 .codehilite .w { color: #bbbbbb } /* Text.Whitespace */
537 576 .codehilite .mb { color: #666666 } /* Literal.Number.Bin */
538 577 .codehilite .mf { color: #666666 } /* Literal.Number.Float */
539 578 .codehilite .mh { color: #666666 } /* Literal.Number.Hex */
540 579 .codehilite .mi { color: #666666 } /* Literal.Number.Integer */
541 580 .codehilite .mo { color: #666666 } /* Literal.Number.Oct */
542 581 .codehilite .sa { color: #BA2121 } /* Literal.String.Affix */
543 582 .codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
544 583 .codehilite .sc { color: #BA2121 } /* Literal.String.Char */
545 584 .codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */
546 585 .codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
547 586 .codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
548 587 .codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
549 588 .codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
550 589 .codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
551 590 .codehilite .sx { color: #008000 } /* Literal.String.Other */
552 591 .codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
553 592 .codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
554 593 .codehilite .ss { color: #19177C } /* Literal.String.Symbol */
555 594 .codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
556 595 .codehilite .fm { color: #0000FF } /* Name.Function.Magic */
557 596 .codehilite .vc { color: #19177C } /* Name.Variable.Class */
558 597 .codehilite .vg { color: #19177C } /* Name.Variable.Global */
559 598 .codehilite .vi { color: #19177C } /* Name.Variable.Instance */
560 599 .codehilite .vm { color: #19177C } /* Name.Variable.Magic */
561 600 .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
562 601
563 602 </style>
564 603
565 604 </head>
566 605 <body>
567 606
568 607 <div>
569 608 <!-- 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. -->
570 609 <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">
571 610 <tr>
572 611 <td valign="top" style="padding:0;">
573 612 <table cellpadding="0" cellspacing="0" border="0" align="left" width="100%">
574 613 <tr>
575 614 <td style="width:100%;padding:10px 15px;background-color:#202020" valign="top">
576 615 <a style="color:#eeeeee;text-decoration:none;" href="${instance_url}">
577 616 ${_('RhodeCode')}
578 617 % if rhodecode_instance_name:
579 618 - ${rhodecode_instance_name}
580 619 % endif
581 620 </a>
582 621 </td>
583 622 </tr>
584 <tr>
623 <tr style="background-color: #fff">
585 624 <td style="padding:15px;" valign="top">${self.body()}</td>
586 625 </tr>
587 626 </table>
588 627 </td>
589 628 </tr>
590 629 </table>
591 630 <!-- End of wrapper table -->
592 631 </div>
593 632
594 633 <div style="width:100%; clear: both; height: 1px">&nbsp;</div>
595 634
596 635 <div style="margin-left:1%;font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace};">
597 636 ${_('This is a notification from RhodeCode.')}
598 637 <a style="font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace};" href="${instance_url}">
599 638 ${instance_url}
600 639 </a>
601 640 </div>
602 641 </body>
603 642 </html>
@@ -1,170 +1,172 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 ## EMAIL SUBJECT
6 6 <%def name="subject()" filter="n,trim,whitespace_filter">
7 7 <%
8 8 data = {
9 9 'user': '@'+h.person(user),
10 10 'repo_name': repo_name,
11 11 'status': status_change,
12 12 'comment_file': comment_file,
13 13 'comment_line': comment_line,
14 14 'comment_type': comment_type,
15 15 'comment_id': comment_id,
16 16
17 17 'commit_id': h.show_id(commit),
18 18 }
19 19 %>
20 20
21 21
22 22 % if comment_file:
23 23 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on file `{comment_file}` in commit `{commit_id}`').format(**data)} ${_('in the `{repo_name}` repository').format(**data) |n}
24 24 % else:
25 25 % if status_change:
26 26 ${(_('[mention]') if mention else '')} ${_('[status: {status}] {user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
27 27 % else:
28 28 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
29 29 % endif
30 30 % endif
31 31
32 32 </%def>
33 33
34 34 ## PLAINTEXT VERSION OF BODY
35 35 <%def name="body_plaintext()" filter="n,trim">
36 36 <%
37 37 data = {
38 38 'user': h.person(user),
39 39 'repo_name': repo_name,
40 40 'status': status_change,
41 41 'comment_file': comment_file,
42 42 'comment_line': comment_line,
43 43 'comment_type': comment_type,
44 44 'comment_id': comment_id,
45 45
46 46 'commit_id': h.show_id(commit),
47 47 }
48 48 %>
49 49
50 50 * ${_('Comment link')}: ${commit_comment_url}
51 51
52 52 %if status_change:
53 53 * ${_('Commit status')}: ${_('Status was changed to')}: *${status_change}*
54 54
55 55 %endif
56 56 * ${_('Commit')}: ${h.show_id(commit)}
57 57
58 58 * ${_('Commit message')}: ${commit.message}
59 59
60 60 %if comment_file:
61 61 * ${_('File: {comment_file} on line {comment_line}').format(**data)}
62 62
63 63 %endif
64 64 % if comment_type == 'todo':
65 65 ${('Inline' if comment_file else 'General')} ${_('`TODO` number')} ${comment_id}:
66 66 % else:
67 67 ${('Inline' if comment_file else 'General')} ${_('`Note` number')} ${comment_id}:
68 68 % endif
69 69
70 70 ${comment_body |n, trim}
71 71
72 72 ---
73 73 ${self.plaintext_footer()}
74 74 </%def>
75 75
76 76
77 77 <%
78 78 data = {
79 79 'user': h.person(user),
80 80 'comment_file': comment_file,
81 81 'comment_line': comment_line,
82 82 'comment_type': comment_type,
83 83 'comment_id': comment_id,
84 84 'renderer_type': renderer_type or 'plain',
85 85
86 86 'repo': commit_target_repo_url,
87 87 'repo_name': repo_name,
88 88 'commit_id': h.show_id(commit),
89 89 }
90 90 %>
91 91
92 ## header
92 93 <table style="text-align:left;vertical-align:middle;width: 100%">
93 94 <tr>
94 95 <td style="width:100%;border-bottom:1px solid #dbd9da;">
95 96
96 <h4 style="margin: 0">
97 <div style="margin-bottom: 4px">
97 <div style="margin: 0; font-weight: bold">
98 <div class="clear-both" style="margin-bottom: 4px">
98 99 <span style="color:#7E7F7F">@${h.person(user.username)}</span>
99 100 ${_('left a')}
100 101 <a href="${commit_comment_url}" style="${base.link_css()}">
101 102 % if comment_file:
102 103 ${_('{comment_type} on file `{comment_file}` in commit.').format(**data)}
103 104 % else:
104 105 ${_('{comment_type} on commit.').format(**data) |n}
105 106 % endif
106 107 </a>
107 108 </div>
108 109 <div style="margin-top: 10px"></div>
109 110 ${_('Commit')} <code>${data['commit_id']}</code> ${_('of repository')}: ${data['repo_name']}
110 </h4>
111 </div>
111 112
112 113 </td>
113 114 </tr>
114 115
115 116 </table>
116
117 <div class="clear-both"></div>
118 ## main body
117 119 <table style="text-align:left;vertical-align:middle;width: 100%">
118 120
119 121 ## spacing def
120 122 <tr>
121 123 <td style="width: 130px"></td>
122 124 <td></td>
123 125 </tr>
124 126
125 127 % if status_change:
126 128 <tr>
127 129 <td style="padding-right:20px;">${_('Commit Status')}:</td>
128 130 <td>
129 131 ${_('Status was changed to')}: ${base.status_text(status_change, tag_type=status_change_type)}
130 132 </td>
131 133 </tr>
132 134 % endif
133 135
134 136 <tr>
135 137 <td style="padding-right:20px;">${_('Commit')}:</td>
136 138 <td>
137 139 <a href="${commit_comment_url}" style="${base.link_css()}">${h.show_id(commit)}</a>
138 140 </td>
139 141 </tr>
140 142 <tr>
141 143 <td style="padding-right:20px;">${_('Commit message')}:</td>
142 144 <td style="white-space:pre-wrap">${h.urlify_commit_message(commit.message, repo_name)}</td>
143 145 </tr>
144 146
145 147 % if comment_file:
146 148 <tr>
147 149 <td style="padding-right:20px;">${_('File')}:</td>
148 150 <td><a href="${commit_comment_url}" style="${base.link_css()}">${_('`{comment_file}` on line {comment_line}').format(**data)}</a></td>
149 151 </tr>
150 152 % endif
151 153
152 154 <tr style="border-bottom:1px solid #dbd9da;">
153 155 <td colspan="2" style="padding-right:20px;">
154 156 % if comment_type == 'todo':
155 157 ${('Inline' if comment_file else 'General')} ${_('`TODO` number')} ${comment_id}:
156 158 % else:
157 159 ${('Inline' if comment_file else 'General')} ${_('`Note` number')} ${comment_id}:
158 160 % endif
159 161 </td>
160 162 </tr>
161 163
162 164 <tr>
163 165 <td colspan="2" style="background: #F7F7F7">${h.render(comment_body, renderer=data['renderer_type'], mentions=True)}</td>
164 166 </tr>
165 167
166 168 <tr>
167 169 <td><a href="${commit_comment_reply_url}">${_('Reply')}</a></td>
168 170 <td></td>
169 171 </tr>
170 172 </table>
@@ -1,201 +1,203 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 ## EMAIL SUBJECT
6 6 <%def name="subject()" filter="n,trim,whitespace_filter">
7 7 <%
8 8 data = {
9 9 'user': '@'+h.person(user),
10 10 'repo_name': repo_name,
11 11 'status': status_change,
12 12 'comment_file': comment_file,
13 13 'comment_line': comment_line,
14 14 'comment_type': comment_type,
15 15 'comment_id': comment_id,
16 16
17 17 'pr_title': pull_request.title,
18 18 'pr_id': pull_request.pull_request_id,
19 19 }
20 20 %>
21 21
22 22
23 23 % if comment_file:
24 24 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on file `{comment_file}` in pull request !{pr_id}: "{pr_title}"').format(**data) |n}
25 25 % else:
26 26 % if status_change:
27 27 ${(_('[mention]') if mention else '')} ${_('[status: {status}] {user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
28 28 % else:
29 29 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
30 30 % endif
31 31 % endif
32 32
33 33 </%def>
34 34
35 35 ## PLAINTEXT VERSION OF BODY
36 36 <%def name="body_plaintext()" filter="n,trim">
37 37 <%
38 38 data = {
39 39 'user': h.person(user),
40 40 'repo_name': repo_name,
41 41 'status': status_change,
42 42 'comment_file': comment_file,
43 43 'comment_line': comment_line,
44 44 'comment_type': comment_type,
45 45 'comment_id': comment_id,
46 46
47 47 'pr_title': pull_request.title,
48 48 'pr_id': pull_request.pull_request_id,
49 49 'source_ref_type': pull_request.source_ref_parts.type,
50 50 'source_ref_name': pull_request.source_ref_parts.name,
51 51 'target_ref_type': pull_request.target_ref_parts.type,
52 52 'target_ref_name': pull_request.target_ref_parts.name,
53 53 'source_repo': pull_request_source_repo.repo_name,
54 54 'target_repo': pull_request_target_repo.repo_name,
55 55 'source_repo_url': pull_request_source_repo_url,
56 56 'target_repo_url': pull_request_target_repo_url,
57 57 }
58 58 %>
59 59
60 60 * ${_('Comment link')}: ${pr_comment_url}
61 61
62 62 * ${_('Pull Request')}: !${pull_request.pull_request_id}
63 63
64 64 * ${h.literal(_('Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}').format(**data))}
65 65
66 66 %if status_change and not closing_pr:
67 67 * ${_('{user} submitted pull request !{pr_id} status: *{status}*').format(**data)}
68 68
69 69 %elif status_change and closing_pr:
70 70 * ${_('{user} submitted pull request !{pr_id} status: *{status} and closed*').format(**data)}
71 71
72 72 %endif
73 73 %if comment_file:
74 74 * ${_('File: {comment_file} on line {comment_line}').format(**data)}
75 75
76 76 %endif
77 77 % if comment_type == 'todo':
78 78 ${('Inline' if comment_file else 'General')} ${_('`TODO` number')} ${comment_id}:
79 79 % else:
80 80 ${('Inline' if comment_file else 'General')} ${_('`Note` number')} ${comment_id}:
81 81 % endif
82 82
83 83 ${comment_body |n, trim}
84 84
85 85 ---
86 86 ${self.plaintext_footer()}
87 87 </%def>
88 88
89 89
90 90 <%
91 91 data = {
92 92 'user': h.person(user),
93 93 'comment_file': comment_file,
94 94 'comment_line': comment_line,
95 95 'comment_type': comment_type,
96 96 'comment_id': comment_id,
97 97 'renderer_type': renderer_type or 'plain',
98 98
99 99 'pr_title': pull_request.title,
100 100 'pr_id': pull_request.pull_request_id,
101 101 'status': status_change,
102 102 'source_ref_type': pull_request.source_ref_parts.type,
103 103 'source_ref_name': pull_request.source_ref_parts.name,
104 104 'target_ref_type': pull_request.target_ref_parts.type,
105 105 'target_ref_name': pull_request.target_ref_parts.name,
106 106 'source_repo': pull_request_source_repo.repo_name,
107 107 'target_repo': pull_request_target_repo.repo_name,
108 108 'source_repo_url': h.link_to(pull_request_source_repo.repo_name, pull_request_source_repo_url),
109 109 'target_repo_url': h.link_to(pull_request_target_repo.repo_name, pull_request_target_repo_url),
110 110 }
111 111 %>
112 112
113 ## header
113 114 <table style="text-align:left;vertical-align:middle;width: 100%">
114 115 <tr>
115 116 <td style="width:100%;border-bottom:1px solid #dbd9da;">
116 117
117 <h4 style="margin: 0">
118 <div style="margin-bottom: 4px">
118 <div style="margin: 0; font-weight: bold">
119 <div class="clear-both" style="margin-bottom: 4px">
119 120 <span style="color:#7E7F7F">@${h.person(user.username)}</span>
120 121 ${_('left a')}
121 122 <a href="${pr_comment_url}" style="${base.link_css()}">
122 123 % if comment_file:
123 124 ${_('{comment_type} on file `{comment_file}` in pull request.').format(**data)}
124 125 % else:
125 126 ${_('{comment_type} on pull request.').format(**data) |n}
126 127 % endif
127 128 </a>
128 129 </div>
129 130 <div style="margin-top: 10px"></div>
130 131 ${_('Pull request')} <code>!${data['pr_id']}: ${data['pr_title']}</code>
131 </h4>
132 </div>
132 133
133 134 </td>
134 135 </tr>
135 136
136 137 </table>
137
138 <div class="clear-both"></div>
139 ## main body
138 140 <table style="text-align:left;vertical-align:middle;width: 100%">
139 141
140 142 ## spacing def
141 143 <tr>
142 144 <td style="width: 130px"></td>
143 145 <td></td>
144 146 </tr>
145 147
146 148 % if status_change:
147 149 <tr>
148 150 <td style="padding-right:20px;">${_('Review Status')}:</td>
149 151 <td>
150 152 % if closing_pr:
151 153 ${_('Closed pull request with status')}: ${base.status_text(status_change, tag_type=status_change_type)}
152 154 % else:
153 155 ${_('Submitted review status')}: ${base.status_text(status_change, tag_type=status_change_type)}
154 156 % endif
155 157 </td>
156 158 </tr>
157 159 % endif
158 160 <tr>
159 161 <td style="padding-right:20px;">${_('Pull request')}:</td>
160 162 <td>
161 163 <a href="${pull_request_url}" style="${base.link_css()}">
162 164 !${pull_request.pull_request_id}
163 165 </a>
164 166 </td>
165 167 </tr>
166 168
167 169 <tr>
168 170 <td style="padding-right:20px;line-height:20px;">${_('Commit Flow')}:</td>
169 171 <td style="line-height:20px;">
170 172 <code>${'{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name)}</code> ${_('of')} ${data['source_repo_url']}
171 173 &rarr;
172 174 <code>${'{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name)}</code> ${_('of')} ${data['target_repo_url']}
173 175 </td>
174 176 </tr>
175 177
176 178 % if comment_file:
177 179 <tr>
178 180 <td style="padding-right:20px;">${_('File')}:</td>
179 181 <td><a href="${pr_comment_url}" style="${base.link_css()}">${_('`{comment_file}` on line {comment_line}').format(**data)}</a></td>
180 182 </tr>
181 183 % endif
182 184
183 185 <tr style="border-bottom:1px solid #dbd9da;">
184 186 <td colspan="2" style="padding-right:20px;">
185 187 % if comment_type == 'todo':
186 188 ${('Inline' if comment_file else 'General')} ${_('`TODO` number')} ${comment_id}:
187 189 % else:
188 190 ${('Inline' if comment_file else 'General')} ${_('`Note` number')} ${comment_id}:
189 191 % endif
190 192 </td>
191 193 </tr>
192 194
193 195 <tr>
194 196 <td colspan="2" style="background: #F7F7F7">${h.render(comment_body, renderer=data['renderer_type'], mentions=True)}</td>
195 197 </tr>
196 198
197 199 <tr>
198 200 <td><a href="${pr_comment_reply_url}">${_('Reply')}</a></td>
199 201 <td></td>
200 202 </tr>
201 203 </table>
@@ -1,143 +1,144 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 ## EMAIL SUBJECT
6 6 <%def name="subject()" filter="n,trim,whitespace_filter">
7 7 <%
8 8 data = {
9 9 'user': '@'+h.person(user),
10 10 'pr_id': pull_request.pull_request_id,
11 11 'pr_title': pull_request.title,
12 12 }
13 13 %>
14 14
15 15 ${_('{user} requested a pull request review. !{pr_id}: "{pr_title}"').format(**data) |n}
16 16 </%def>
17 17
18 18 ## PLAINTEXT VERSION OF BODY
19 19 <%def name="body_plaintext()" filter="n,trim">
20 20 <%
21 21 data = {
22 22 'user': h.person(user),
23 23 'pr_id': pull_request.pull_request_id,
24 24 'pr_title': pull_request.title,
25 25 'source_ref_type': pull_request.source_ref_parts.type,
26 26 'source_ref_name': pull_request.source_ref_parts.name,
27 27 'target_ref_type': pull_request.target_ref_parts.type,
28 28 'target_ref_name': pull_request.target_ref_parts.name,
29 29 'repo_url': pull_request_source_repo_url,
30 30 'source_repo': pull_request_source_repo.repo_name,
31 31 'target_repo': pull_request_target_repo.repo_name,
32 32 'source_repo_url': pull_request_source_repo_url,
33 33 'target_repo_url': pull_request_target_repo_url,
34 34 }
35 35 %>
36 36
37 37 * ${_('Pull Request link')}: ${pull_request_url}
38 38
39 39 * ${h.literal(_('Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}').format(**data))}
40 40
41 41 * ${_('Title')}: ${pull_request.title}
42 42
43 43 * ${_('Description')}:
44 44
45 45 ${pull_request.description | trim}
46 46
47 47
48 48 * ${_ungettext('Commit (%(num)s)', 'Commits (%(num)s)', len(pull_request_commits) ) % {'num': len(pull_request_commits)}}:
49 49
50 50 % for commit_id, message in pull_request_commits:
51 51 - ${h.short_id(commit_id)}
52 52 ${h.chop_at_smart(message, '\n', suffix_if_chopped='...')}
53 53
54 54 % endfor
55 55
56 56 ---
57 57 ${self.plaintext_footer()}
58 58 </%def>
59 59 <%
60 60 data = {
61 61 'user': h.person(user),
62 62 'pr_id': pull_request.pull_request_id,
63 63 'pr_title': pull_request.title,
64 64 'source_ref_type': pull_request.source_ref_parts.type,
65 65 'source_ref_name': pull_request.source_ref_parts.name,
66 66 'target_ref_type': pull_request.target_ref_parts.type,
67 67 'target_ref_name': pull_request.target_ref_parts.name,
68 68 'repo_url': pull_request_source_repo_url,
69 69 'source_repo': pull_request_source_repo.repo_name,
70 70 'target_repo': pull_request_target_repo.repo_name,
71 71 'source_repo_url': h.link_to(pull_request_source_repo.repo_name, pull_request_source_repo_url),
72 72 'target_repo_url': h.link_to(pull_request_target_repo.repo_name, pull_request_target_repo_url),
73 73 }
74 74 %>
75
75 ## header
76 76 <table style="text-align:left;vertical-align:middle;width: 100%">
77 77 <tr>
78 78 <td style="width:100%;border-bottom:1px solid #dbd9da;">
79 79
80 <h4 style="margin: 0">
81 <div style="margin-bottom: 4px">
80 <div style="margin: 0; font-weight: bold">
81 <div class="clear-both" class="clear-both" style="margin-bottom: 4px">
82 82 <span style="color:#7E7F7F">@${h.person(user.username)}</span>
83 83 ${_('requested a')}
84 84 <a href="${pull_request_url}" style="${base.link_css()}">
85 85 ${_('pull request review.').format(**data) }
86 86 </a>
87 87 </div>
88 88 <div style="margin-top: 10px"></div>
89 89 ${_('Pull request')} <code>!${data['pr_id']}: ${data['pr_title']}</code>
90 </h4>
90 </div>
91 91
92 92 </td>
93 93 </tr>
94 94
95 95 </table>
96
96 <div class="clear-both"></div>
97 ## main body
97 98 <table style="text-align:left;vertical-align:middle;width: 100%">
98 99 ## spacing def
99 100 <tr>
100 101 <td style="width: 130px"></td>
101 102 <td></td>
102 103 </tr>
103 104
104 105 <tr>
105 106 <td style="padding-right:20px;">${_('Pull request')}:</td>
106 107 <td>
107 108 <a href="${pull_request_url}" style="${base.link_css()}">
108 109 !${pull_request.pull_request_id}
109 110 </a>
110 111 </td>
111 112 </tr>
112 113
113 114 <tr>
114 115 <td style="padding-right:20px;line-height:20px;">${_('Commit Flow')}:</td>
115 116 <td style="line-height:20px;">
116 117 <code>${'{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name)}</code> ${_('of')} ${data['source_repo_url']}
117 118 &rarr;
118 119 <code>${'{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name)}</code> ${_('of')} ${data['target_repo_url']}
119 120 </td>
120 121 </tr>
121 122
122 123 <tr>
123 124 <td style="padding-right:20px;">${_('Description')}:</td>
124 125 <td style="white-space:pre-wrap"><code>${pull_request.description | trim}</code></td>
125 126 </tr>
126 127 <tr>
127 128 <td style="padding-right:20px;">${_ungettext('Commit (%(num)s)', 'Commits (%(num)s)', len(pull_request_commits)) % {'num': len(pull_request_commits)}}:</td>
128 129 <td></td>
129 130 </tr>
130 131
131 132 <tr>
132 133 <td colspan="2">
133 134 <ol style="margin:0 0 0 1em;padding:0;text-align:left;">
134 135 % for commit_id, message in pull_request_commits:
135 136 <li style="margin:0 0 1em;">
136 137 <pre style="margin:0 0 .5em"><a href="${h.route_path('repo_commit', repo_name=pull_request_source_repo.repo_name, commit_id=commit_id)}" style="${base.link_css()}">${h.short_id(commit_id)}</a></pre>
137 138 ${h.chop_at_smart(message, '\n', suffix_if_chopped='...')}
138 139 </li>
139 140 % endfor
140 141 </ol>
141 142 </td>
142 143 </tr>
143 144 </table>
@@ -1,164 +1,170 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 ## EMAIL SUBJECT
6 6 <%def name="subject()" filter="n,trim,whitespace_filter">
7 7 <%
8 8 data = {
9 9 'updating_user': '@'+h.person(updating_user),
10 10 'pr_id': pull_request.pull_request_id,
11 11 'pr_title': pull_request.title,
12 12 }
13 13 %>
14 14
15 15 ${_('{updating_user} updated pull request. !{pr_id}: "{pr_title}"').format(**data) |n}
16 16 </%def>
17 17
18 18 ## PLAINTEXT VERSION OF BODY
19 19 <%def name="body_plaintext()" filter="n,trim">
20 20 <%
21 21 data = {
22 22 'updating_user': h.person(updating_user),
23 23 'pr_id': pull_request.pull_request_id,
24 24 'pr_title': pull_request.title,
25 25 'source_ref_type': pull_request.source_ref_parts.type,
26 26 'source_ref_name': pull_request.source_ref_parts.name,
27 27 'target_ref_type': pull_request.target_ref_parts.type,
28 28 'target_ref_name': pull_request.target_ref_parts.name,
29 29 'repo_url': pull_request_source_repo_url,
30 30 'source_repo': pull_request_source_repo.repo_name,
31 31 'target_repo': pull_request_target_repo.repo_name,
32 32 'source_repo_url': pull_request_source_repo_url,
33 33 'target_repo_url': pull_request_target_repo_url,
34 34 }
35 35 %>
36 36
37 37 * ${_('Pull Request link')}: ${pull_request_url}
38 38
39 39 * ${h.literal(_('Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}').format(**data))}
40 40
41 41 * ${_('Title')}: ${pull_request.title}
42 42
43 43 * ${_('Description')}:
44 44
45 45 ${pull_request.description | trim}
46 46
47 47 * Changed commits:
48 48
49 49 - Added: ${len(added_commits)}
50 50 - Removed: ${len(removed_commits)}
51 51
52 52 * Changed files:
53 53
54 54 %if not changed_files:
55 55 No file changes found
56 56 %else:
57 57 %for file_name in added_files:
58 58 - A `${file_name}`
59 59 %endfor
60 60 %for file_name in modified_files:
61 61 - M `${file_name}`
62 62 %endfor
63 63 %for file_name in removed_files:
64 64 - R `${file_name}`
65 65 %endfor
66 66 %endif
67 67
68 68 ---
69 69 ${self.plaintext_footer()}
70 70 </%def>
71 71 <%
72 72 data = {
73 73 'updating_user': h.person(updating_user),
74 74 'pr_id': pull_request.pull_request_id,
75 75 'pr_title': pull_request.title,
76 76 'source_ref_type': pull_request.source_ref_parts.type,
77 77 'source_ref_name': pull_request.source_ref_parts.name,
78 78 'target_ref_type': pull_request.target_ref_parts.type,
79 79 'target_ref_name': pull_request.target_ref_parts.name,
80 80 'repo_url': pull_request_source_repo_url,
81 81 'source_repo': pull_request_source_repo.repo_name,
82 82 'target_repo': pull_request_target_repo.repo_name,
83 83 'source_repo_url': h.link_to(pull_request_source_repo.repo_name, pull_request_source_repo_url),
84 84 'target_repo_url': h.link_to(pull_request_target_repo.repo_name, pull_request_target_repo_url),
85 85 }
86 86 %>
87 87
88 ## header
88 89 <table style="text-align:left;vertical-align:middle;width: 100%">
89 90 <tr>
90 91 <td style="width:100%;border-bottom:1px solid #dbd9da;">
91 92
92 <h4 style="margin: 0">
93 <div style="margin-bottom: 4px">
93 <div style="margin: 0; font-weight: bold">
94 <div class="clear-both" style="margin-bottom: 4px">
94 95 <span style="color:#7E7F7F">@${h.person(updating_user.username)}</span>
95 96 ${_('updated')}
96 97 <a href="${pull_request_url}" style="${base.link_css()}">
97 98 ${_('pull request.').format(**data) }
98 99 </a>
99 100 </div>
100 101 <div style="margin-top: 10px"></div>
101 102 ${_('Pull request')} <code>!${data['pr_id']}: ${data['pr_title']}</code>
102 </h4>
103 </div>
103 104
104 105 </td>
105 106 </tr>
106 107
107 108 </table>
108
109 <div class="clear-both"></div>
110 ## main body
109 111 <table style="text-align:left;vertical-align:middle;width: 100%">
110 112 ## spacing def
111 113 <tr>
112 114 <td style="width: 130px"></td>
113 115 <td></td>
114 116 </tr>
115 117
116 118 <tr>
117 119 <td style="padding-right:20px;">${_('Pull request')}:</td>
118 120 <td>
119 121 <a href="${pull_request_url}" style="${base.link_css()}">
120 122 !${pull_request.pull_request_id}
121 123 </a>
122 124 </td>
123 125 </tr>
124 126
125 127 <tr>
126 128 <td style="padding-right:20px;line-height:20px;">${_('Commit Flow')}:</td>
127 129 <td style="line-height:20px;">
128 130 <code>${'{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name)}</code> ${_('of')} ${data['source_repo_url']}
129 131 &rarr;
130 132 <code>${'{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name)}</code> ${_('of')} ${data['target_repo_url']}
131 133 </td>
132 134 </tr>
133 135
134 136 <tr>
135 137 <td style="padding-right:20px;">${_('Description')}:</td>
136 138 <td style="white-space:pre-wrap"><code>${pull_request.description | trim}</code></td>
137 139 </tr>
138 140 <tr>
139 141 <td style="padding-right:20px;">${_('Changes')}:</td>
140 <td style="white-space:pre-line">\
142 <td>
141 143 <strong>Changed commits:</strong>
142
143 - Added: ${len(added_commits)}
144 - Removed: ${len(removed_commits)}
144 <ul class="changes-ul">
145 <li>- Added: ${len(added_commits)}</li>
146 <li>- Removed: ${len(removed_commits)}</li>
147 </ul>
145 148
146 149 <strong>Changed files:</strong>
150 <ul class="changes-ul">
147 151
148 152 %if not changed_files:
149 No file changes found
153 <li>No file changes found</li>
150 154 %else:
151 %for file_name in added_files:
152 - A <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a>
153 %endfor
154 %for file_name in modified_files:
155 - M <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a>
156 %endfor
157 %for file_name in removed_files:
158 - R <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a>
159 %endfor
155 %for file_name in added_files:
156 <li>- A <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a></li>
157 %endfor
158 %for file_name in modified_files:
159 <li>- M <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a></li>
160 %endfor
161 %for file_name in removed_files:
162 <li>- R <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a></li>
163 %endfor
160 164 %endif
165
166 </ul>
161 167 </td>
162 168 </tr>
163 169
164 170 </table>
@@ -1,59 +1,60 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 <%def name="subject()" filter="n,trim,whitespace_filter">
6 6 RhodeCode new user registration: ${user.username}
7 7 </%def>
8 8
9 9 <%def name="body_plaintext()" filter="n,trim">
10 10
11 11 A new user `${user.username}` has registered on ${h.format_date(date)}
12 12
13 13 - Username: ${user.username}
14 14 - Full Name: ${user.first_name} ${user.last_name}
15 15 - Email: ${user.email}
16 16 - Profile link: ${h.route_url('user_profile', username=user.username)}
17 17
18 18 ---
19 19 ${self.plaintext_footer()}
20 20 </%def>
21 21
22
22 ## header
23 23 <table style="text-align:left;vertical-align:middle;width: 100%">
24 24 <tr>
25 25 <td style="width:100%;border-bottom:1px solid #dbd9da;">
26 26 <h4 style="margin: 0">
27 27 <a href="${h.route_url('user_profile', username=user.username)}" style="${base.link_css()}">
28 28 ${_('New user {user} has registered on {date}').format(user=user.username, date=h.format_date(date))}
29 29 </a>
30 30 </h4>
31 31 </td>
32 32 </tr>
33 33 </table>
34
34 <div class="clear-both"></div>
35 ## main body
35 36 <table style="text-align:left;vertical-align:middle;width: 100%">
36 37 ## spacing def
37 38 <tr>
38 39 <td style="width: 130px"></td>
39 40 <td></td>
40 41 </tr>
41 42 <tr>
42 43 <td style="padding-right:20px;padding-top:20px;">${_('Username')}:</td>
43 44 <td style="line-height:1;padding-top:20px;">${user.username}</td>
44 45 </tr>
45 46 <tr>
46 47 <td style="padding-right:20px;">${_('Full Name')}:</td>
47 48 <td>${user.first_name} ${user.last_name}</td>
48 49 </tr>
49 50 <tr>
50 51 <td style="padding-right:20px;">${_('Email')}:</td>
51 52 <td>${user.email}</td>
52 53 </tr>
53 54 <tr>
54 55 <td style="padding-right:20px;">${_('Profile')}:</td>
55 56 <td>
56 57 <a href="${h.route_url('user_profile', username=user.username)}">${h.route_url('user_profile', username=user.username)}</a>
57 58 </td>
58 59 </tr>
59 60 </table>
@@ -1,117 +1,116 b''
1 1 <%inherit file="/base/base.mako"/>
2 2
3 3 <%def name="title()">
4 4 ${_('{} Files Add').format(c.repo_name)}
5 5 %if c.rhodecode_name:
6 6 &middot; ${h.branding(c.rhodecode_name)}
7 7 %endif
8 8 </%def>
9 9
10 10 <%def name="menu_bar_nav()">
11 11 ${self.menu_items(active='repositories')}
12 12 </%def>
13 13
14 14 <%def name="breadcrumbs_links()"></%def>
15 15
16 16 <%def name="menu_bar_subnav()">
17 17 ${self.repo_menu(active='files')}
18 18 </%def>
19 19
20 20 <%def name="main()">
21 21
22 22 <div class="box">
23 23
24 24 <div class="edit-file-title">
25 25 <span class="title-heading">${_('Add new file')} @ <code>${h.show_id(c.commit)}</code></span>
26 26 % if c.commit.branch:
27 27 <span class="tag branchtag">
28 28 <i class="icon-branch"></i> ${c.commit.branch}
29 29 </span>
30 30 % endif
31 31 </div>
32 32
33 33 ${h.secure_form(h.route_path('repo_files_create_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
34 34 <div class="edit-file-fieldset">
35 35 <div class="path-items">
36 36 <ul>
37 37 <li class="breadcrumb-path">
38 38 <div>
39 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
40 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path)}">${c.f_path}</a> ${('/' if c.f_path else '')}
39 ${h.files_breadcrumbs(c.repo_name, c.rhodecode_db_repo.repo_type, c.commit.raw_id, c.f_path, c.rhodecode_db_repo.landing_ref_name, request.GET.get('at'), limit_items=True, hide_last_item=False, linkify_last_item=True, copy_path_icon=False)} /
41 40 </div>
42 41 </li>
43 42 <li class="location-path">
44 43 <input class="file-name-input input-small" type="text" value="${request.GET.get('filename')}" name="filename" id="filename" placeholder="${_('Filename e.g example.py, or docs/readme.md')}">
45 44 </li>
46 45 </ul>
47 46 </div>
48 47
49 48 </div>
50 49
51 50 <div class="table">
52 51 <div>
53 52 <div id="codeblock" class="codeblock">
54 53 <div class="editor-items">
55 54 <div class="editor-action active show-editor pull-left" onclick="fileEditor.showEditor(); return false">
56 55 ${_('Edit')}
57 56 </div>
58 57
59 58 <div class="editor-action show-preview pull-left" onclick="fileEditor.showPreview(); return false">
60 59 ${_('Preview')}
61 60 </div>
62 61
63 62 <div class="pull-right">
64 63 ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off'))], extra_classes=['last-item'])}
65 64 </div>
66 65 <div class="pull-right">
67 66 ${h.dropdownmenu('set_mode','plain',[('plain', _('plain'))], enable_filter=True)}
68 67 </div>
69 68 </div>
70 69
71 70 <div id="editor_container">
72 71 <pre id="editor_pre"></pre>
73 72 <textarea id="editor" name="content" ></textarea>
74 73 <div id="editor_preview"></div>
75 74 </div>
76 75 </div>
77 76 </div>
78 77 </div>
79 78
80 79 <div class="edit-file-fieldset">
81 80 <div class="fieldset">
82 81 <div class="message">
83 82 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
84 83 </div>
85 84 </div>
86 85 <div class="pull-left">
87 86 ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
88 87 </div>
89 88 </div>
90 89 ${h.end_form()}
91 90 </div>
92 91
93 92 <script type="text/javascript">
94 93
95 94 $(document).ready(function () {
96 95 var modes_select = $('#set_mode');
97 96 var filename_selector = '#filename';
98 97 fillCodeMirrorOptions(modes_select);
99 98
100 99 fileEditor = new FileEditor('#editor');
101 100
102 101 // on change of select field set mode
103 102 setCodeMirrorModeFromSelect(modes_select, filename_selector, fileEditor.cm, null);
104 103
105 104 // on entering the new filename set mode, from given extension
106 105 setCodeMirrorModeFromInput(modes_select, filename_selector, fileEditor.cm, null);
107 106
108 107 $('#filename').focus();
109 108
110 109 var commit_id = "${c.commit.raw_id}";
111 110 var f_path = "${c.f_path}";
112 111
113 112 checkFileHead($('#eform'), commit_id, f_path, 'create')
114 113 });
115 114
116 115 </script>
117 116 </%def>
@@ -1,84 +1,84 b''
1 1
2 2 <div id="codeblock" class="browserblock">
3 3 <div class="browser-header">
4 4 <div class="browser-nav">
5 5
6 6 <div class="info_box">
7 7
8 8 <div class="info_box_elem previous">
9 9 <a id="prev_commit_link" data-commit-id="${c.prev_commit.raw_id}" class=" ${('disabled' if c.url_prev == '#' else '')}" href="${c.url_prev}" title="${_('Previous commit')}"><i class="icon-left"></i></a>
10 10 </div>
11 11
12 12 ${h.hidden('refs_filter')}
13 13
14 14 <div class="info_box_elem next">
15 15 <a id="next_commit_link" data-commit-id="${c.next_commit.raw_id}" class=" ${('disabled' if c.url_next == '#' else '')}" href="${c.url_next}" title="${_('Next commit')}"><i class="icon-right"></i></a>
16 16 </div>
17 17 </div>
18 18
19 19 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
20 20 <div>
21 21 <a class="btn btn-primary new-file" href="${h.route_path('repo_files_upload_file',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}">
22 22 ${_('Upload File')}
23 23 </a>
24 24 <a class="btn btn-primary new-file" href="${h.route_path('repo_files_add_file',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}">
25 25 ${_('Add File')}
26 26 </a>
27 27 </div>
28 28 % endif
29 29
30 30 % if c.enable_downloads:
31 31 <% at_path = '{}'.format(request.GET.get('at') or c.commit.raw_id[:6]) %>
32 32 <div class="btn btn-default new-file">
33 33 % if c.f_path == '/':
34 34 <a href="${h.route_path('repo_archivefile',repo_name=c.repo_name, fname='{}.zip'.format(c.commit.raw_id))}">
35 35 ${_('Download full tree ZIP')}
36 36 </a>
37 37 % else:
38 38 <a href="${h.route_path('repo_archivefile',repo_name=c.repo_name, fname='{}.zip'.format(c.commit.raw_id), _query={'at_path':c.f_path})}">
39 39 ${_('Download this tree ZIP')}
40 40 </a>
41 41 % endif
42 42 </div>
43 43 % endif
44 44
45 45 <div class="files-quick-filter">
46 46 <ul class="files-filter-box">
47 47 <li class="files-filter-box-path">
48 48 <i class="icon-search"></i>
49 49 </li>
50 50 <li class="files-filter-box-input">
51 51 <input onkeydown="NodeFilter.initFilter(event)" class="init" type="text" placeholder="Quick filter" name="filter" size="25" id="node_filter" autocomplete="off">
52 52 </li>
53 53 </ul>
54 54 </div>
55 55 </div>
56 56
57 57 </div>
58 58
59 59 ## file tree is computed from caches, and filled in
60 60 <div id="file-tree">
61 61 ${c.file_tree |n}
62 62 </div>
63 63
64 64 %if c.readme_data:
65 65 <div id="readme" class="anchor">
66 66 <div class="box">
67 <div class="readme-title" title="${h.tooltip(_('Readme file from commit %s:%s') % (c.rhodecode_db_repo.landing_rev[0], c.rhodecode_db_repo.landing_rev[1]))}">
67 <div class="readme-title" title="${h.tooltip(_('Readme file from commit %s:%s') % (c.rhodecode_db_repo.landing_ref_type, c.rhodecode_db_repo.landing_ref_name))}">
68 68 <div>
69 69 <i class="icon-file-text"></i>
70 <a href="${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.rhodecode_db_repo.landing_rev[1],f_path=c.readme_file)}">
70 <a href="${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.rhodecode_db_repo.landing_ref_name,f_path=c.readme_file)}">
71 71 ${c.readme_file}
72 72 </a>
73 73 </div>
74 74 </div>
75 75 <div class="readme codeblock">
76 76 <div class="readme_box">
77 77 ${c.readme_data|n}
78 78 </div>
79 79 </div>
80 80 </div>
81 81 </div>
82 82 %endif
83 83
84 84 </div>
@@ -1,95 +1,98 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <%
4 if request.GET.get('at'):
5 query={'at': request.GET.get('at')}
4 at_ref = request.GET.get('at')
5 if at_ref:
6 query={'at': at_ref}
7 default_landing_ref = at_ref or c.rhodecode_db_repo.landing_ref_name
6 8 else:
7 9 query=None
10 default_landing_ref = c.commit.raw_id
8 11 %>
9 12 <div id="file-tree-wrapper" class="browser-body ${('full-load' if c.full_load else '')}">
10 13 <table class="code-browser rctable repo_summary">
11 14 <thead>
12 15 <tr>
13 16 <th>${_('Name')}</th>
14 17 <th>${_('Size')}</th>
15 18 <th>${_('Modified')}</th>
16 19 <th>${_('Last Commit')}</th>
17 20 <th>${_('Author')}</th>
18 21 </tr>
19 22 </thead>
20 23
21 24 <tbody id="tbody">
22 25 <tr>
23 26 <td colspan="5">
24 ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.file.path, request.GET.get('at'), limit_items=True)}
27 ${h.files_breadcrumbs(c.repo_name, c.rhodecode_db_repo.repo_type, c.commit.raw_id, c.file.path, c.rhodecode_db_repo.landing_ref_name, request.GET.get('at'), limit_items=True)}
25 28 </td>
26 29 </tr>
27 30
28 31 <% has_files = False %>
29 32 % for cnt,node in enumerate(c.file):
30 33 <% has_files = True %>
31 34 <tr class="parity${(cnt % 2)}">
32 35 <td class="td-componentname">
33 36 % if node.is_submodule():
34 37 <span class="submodule-dir">
35 38 % if node.url.startswith('http://') or node.url.startswith('https://'):
36 39 <a href="${node.url}">
37 40 <i class="icon-directory browser-dir"></i>${node.name}
38 41 </a>
39 42 % else:
40 43 <i class="icon-directory browser-dir"></i>${node.name}
41 44 % endif
42 45 </span>
43 46 % else:
44 <a href="${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=h.safe_unicode(node.path), _query=query)}">
47 <a href="${h.repo_files_by_ref_url(c.repo_name, c.rhodecode_db_repo.repo_type, f_path=h.safe_unicode(node.path), ref_name=default_landing_ref, commit_id=c.commit.raw_id, query=query)}">
45 48 <i class="${('icon-file-text browser-file' if node.is_file() else 'icon-directory browser-dir')}"></i>${node.name}
46 49 </a>
47 50 % endif
48 51 </td>
49 52 %if node.is_file():
50 53 <td class="td-size" data-attr-name="size">
51 54 % if c.full_load:
52 55 <span data-size="${node.size}">${h.format_byte_size_binary(node.size)}</span>
53 56 % else:
54 57 ${_('Loading ...')}
55 58 % endif
56 59 </td>
57 60 <td class="td-time" data-attr-name="modified_at">
58 61 % if c.full_load:
59 62 <span data-date="${node.last_commit.date}">${h.age_component(node.last_commit.date)}</span>
60 63 % endif
61 64 </td>
62 65 <td class="td-hash" data-attr-name="commit_id">
63 66 % if c.full_load:
64 67 <div class="tooltip-hovercard" data-hovercard-alt="${node.last_commit.message}" data-hovercard-url="${h.route_path('hovercard_repo_commit', repo_name=c.repo_name, commit_id=node.last_commit.raw_id)}">
65 68 <pre data-commit-id="${node.last_commit.raw_id}">r${node.last_commit.idx}:${node.last_commit.short_id}</pre>
66 69 </div>
67 70 % endif
68 71 </td>
69 72 <td class="td-user" data-attr-name="author">
70 73 % if c.full_load:
71 74 <span data-author="${node.last_commit.author}">${h.gravatar_with_user(request, node.last_commit.author, tooltip=True)|n}</span>
72 75 % endif
73 76 </td>
74 77 %else:
75 78 <td></td>
76 79 <td></td>
77 80 <td></td>
78 81 <td></td>
79 82 %endif
80 83 </tr>
81 84 % endfor
82 85
83 86 % if not has_files:
84 87 <tr>
85 88 <td colspan="5">
86 89 ##empty-dir mostly SVN
87 90 &nbsp;
88 91 </td>
89 92 </tr>
90 93 % endif
91 94
92 95 </tbody>
93 96 <tbody id="tbody_filtered"></tbody>
94 97 </table>
95 98 </div>
@@ -1,93 +1,92 b''
1 1 <%inherit file="/base/base.mako"/>
2 2
3 3 <%def name="title()">
4 4 ${_('{} Files Delete').format(c.repo_name)}
5 5 %if c.rhodecode_name:
6 6 &middot; ${h.branding(c.rhodecode_name)}
7 7 %endif
8 8 </%def>
9 9
10 10 <%def name="menu_bar_nav()">
11 11 ${self.menu_items(active='repositories')}
12 12 </%def>
13 13
14 14 <%def name="breadcrumbs_links()"></%def>
15 15
16 16 <%def name="menu_bar_subnav()">
17 17 ${self.repo_menu(active='files')}
18 18 </%def>
19 19
20 20 <%def name="main()">
21 21
22 22 <div class="box">
23 23
24 24 <div class="edit-file-title">
25 25 <span class="title-heading">${_('Delete file')} @ <code>${h.show_id(c.commit)}</code></span>
26 26 % if c.commit.branch:
27 27 <span class="tag branchtag">
28 28 <i class="icon-branch"></i> ${c.commit.branch}
29 29 </span>
30 30 % endif
31 31 </div>
32 32
33 33 ${h.secure_form(h.route_path('repo_files_delete_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
34 34 <div class="edit-file-fieldset">
35 35 <div class="path-items">
36 36 <li class="breadcrumb-path">
37 37 <div>
38 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
39 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.file.dir_path)}">${c.file.dir_path}</a> ${('/' if c.file.dir_path else '')}
38 ${h.files_breadcrumbs(c.repo_name, c.rhodecode_db_repo.repo_type, c.commit.raw_id, c.file.path, c.rhodecode_db_repo.landing_ref_name, request.GET.get('at'), limit_items=True, hide_last_item=True, copy_path_icon=False)} /
40 39 </div>
41 40 </li>
42 41 <li class="location-path">
43 42 <input type="hidden" value="${c.f_path}" name="root_path">
44 43 <input class="file-name-input input-small" type="text" value="${c.file.name}" name="filename" id="filename" disabled="disabled">
45 44 </li>
46 45 </div>
47 46
48 47 </div>
49 48
50 49 <div id="codeblock" class="codeblock delete-file-preview">
51 50 <div class="code-body">
52 51 %if c.file.is_binary:
53 52 ${_('Binary file (%s)') % c.file.mimetype}
54 53 %else:
55 54 %if c.file.size < c.visual.cut_off_limit_file:
56 55 ${h.pygmentize(c.file,linenos=True,anchorlinenos=False,cssclass="code-highlight")}
57 56 %else:
58 57 ${_('File size {} is bigger then allowed limit {}. ').format(h.format_byte_size_binary(c.file.size), h.format_byte_size_binary(c.visual.cut_off_limit_file))} ${h.link_to(_('Show as raw'),
59 58 h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
60 59 %endif
61 60 %endif
62 61 </div>
63 62 </div>
64 63
65 64 <div class="edit-file-fieldset">
66 65 <div class="fieldset">
67 66 <div class="message">
68 67 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
69 68 </div>
70 69 </div>
71 70 <div class="pull-left">
72 71 ${h.submit('commit_btn',_('Commit changes'),class_="btn btn-small btn-danger-action")}
73 72 </div>
74 73 </div>
75 74 ${h.end_form()}
76 75 </div>
77 76
78 77
79 78 <script type="text/javascript">
80 79
81 80 $(document).ready(function () {
82 81
83 82 fileEditor = new FileEditor('#editor');
84 83
85 84 var commit_id = "${c.commit.raw_id}";
86 85 var f_path = "${c.f_path}";
87 86
88 87 checkFileHead($('#eform'), commit_id, f_path, 'delete');
89 88 });
90 89
91 90 </script>
92 91
93 92 </%def>
@@ -1,129 +1,128 b''
1 1 <%inherit file="/base/base.mako"/>
2 2
3 3 <%def name="title()">
4 4 ${_('{} Files Edit').format(c.repo_name)}
5 5 %if c.rhodecode_name:
6 6 &middot; ${h.branding(c.rhodecode_name)}
7 7 %endif
8 8 </%def>
9 9
10 10 <%def name="menu_bar_nav()">
11 11 ${self.menu_items(active='repositories')}
12 12 </%def>
13 13
14 14 <%def name="breadcrumbs_links()"></%def>
15 15
16 16 <%def name="menu_bar_subnav()">
17 17 ${self.repo_menu(active='files')}
18 18 </%def>
19 19
20 20 <%def name="main()">
21 21
22 22 <div class="box">
23 23
24 24 <div class="edit-file-title">
25 25 <span class="title-heading">${_('Edit file')} @ <code>${h.show_id(c.commit)}</code></span>
26 26 % if c.commit.branch:
27 27 <span class="tag branchtag">
28 28 <i class="icon-branch"></i> ${c.commit.branch}
29 29 </span>
30 30 % endif
31 31 </div>
32 32
33 33 ${h.secure_form(h.route_path('repo_files_update_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
34 34 <div class="edit-file-fieldset">
35 35 <div class="path-items">
36 36 <ul>
37 37 <li class="breadcrumb-path">
38 38 <div>
39 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
40 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.file.dir_path)}">${c.file.dir_path}</a> ${('/' if c.file.dir_path else '')}
39 ${h.files_breadcrumbs(c.repo_name, c.rhodecode_db_repo.repo_type, c.commit.raw_id, c.file.path, c.rhodecode_db_repo.landing_ref_name, request.GET.get('at'), limit_items=True, hide_last_item=True, copy_path_icon=False)} /
41 40 </div>
42 41 </li>
43 42 <li class="location-path">
44 43 <input type="hidden" value="${c.f_path}" name="root_path">
45 44 <input class="file-name-input input-small" type="text" value="${c.file.name}" name="filename" id="filename" placeholder="${_('Filename e.g example.py, or docs/readme.md')}">
46 45 </li>
47 46 </ul>
48 47 </div>
49 48
50 49 </div>
51 50
52 51 <div class="table">
53 52 <div>
54 53
55 54 <div id="codeblock" class="codeblock">
56 55 <div class="editor-items">
57 56 <div class="editor-action active show-editor pull-left" onclick="fileEditor.showEditor(); return false">
58 57 ${_('Edit')}
59 58 </div>
60 59
61 60 <div class="editor-action show-preview pull-left" onclick="fileEditor.showPreview(); return false">
62 61 ${_('Preview')}
63 62 </div>
64 63
65 64 <div class="pull-right">
66 65 ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off')),])}
67 66 </div>
68 67 <div class="pull-right">
69 68 ${h.dropdownmenu('set_mode','plain',[('plain', _('plain'))],enable_filter=True)}
70 69 </div>
71 70 </div>
72 71
73 72 <div id="editor_container">
74 73 <pre id="editor_pre"></pre>
75 74 <textarea id="editor" name="content" >${h.escape(c.file.content)|n}</textarea>
76 75 <div id="editor_preview" ></div>
77 76 </div>
78 77 </div>
79 78 </div>
80 79 </div>
81 80
82 81 <div class="edit-file-fieldset">
83 82 <div class="fieldset">
84 83 <div class="message">
85 84 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
86 85 </div>
87 86 </div>
88 87 <div class="pull-left">
89 88 ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
90 89 </div>
91 90 </div>
92 91 ${h.end_form()}
93 92 </div>
94 93
95 94 <script type="text/javascript">
96 95
97 96 $(document).ready(function() {
98 97 var modes_select = $('#set_mode');
99 98 var filename_selector = '#filename';
100 99 fillCodeMirrorOptions(modes_select);
101 100
102 101 fileEditor = new FileEditor('#editor');
103 102
104 103 // try to detect the mode based on the file we edit
105 104 var detected_mode = detectCodeMirrorMode("${c.file.name}", "${c.file.mimetype}");
106 105
107 106 if (detected_mode) {
108 107 setCodeMirrorMode(fileEditor.cm, detected_mode);
109 108
110 109 var mimetype = $(modes_select).find("option[mode={0}]".format(detected_mode)).val();
111 110 $(modes_select).select2("val", mimetype).trigger('change');
112 111 }
113 112
114 113 // on change of select field set mode
115 114 setCodeMirrorModeFromSelect(modes_select, filename_selector, fileEditor.cm, null);
116 115
117 116 // on entering the new filename set mode, from given extension
118 117 setCodeMirrorModeFromInput(modes_select, filename_selector, fileEditor.cm, null);
119 118
120 119 var commit_id = "${c.commit.raw_id}";
121 120 var f_path = "${c.f_path}";
122 121
123 122 checkFileHead($('#eform'), commit_id, f_path, 'edit')
124 123
125 124 });
126 125
127 126
128 127 </script>
129 128 </%def>
@@ -1,179 +1,189 b''
1 1 <%namespace name="sourceblock" file="/codeblocks/source.mako"/>
2 2
3 <%
4 at_ref = request.GET.get('at')
5 if at_ref:
6 query={'at': at_ref}
7 default_commit_id = at_ref or c.rhodecode_db_repo.landing_ref_name
8 else:
9 query=None
10 default_commit_id = c.commit.raw_id
11 %>
12
3 13 <div id="codeblock" class="browserblock">
4 14 <div class="browser-header">
5 15 <div class="browser-nav">
6 16 <div class="pull-left">
7 17 ## loads the history for a file
8 18 ${h.hidden('file_refs_filter')}
9 19 </div>
10 20
11 21 <div class="pull-right">
12 22
13 23 ## Download
14 24 % if c.lf_node:
15 25 <a class="btn btn-default" href="${h.route_path('repo_file_download',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path, _query=dict(lf=1))}">
16 26 ${_('Download largefile')}
17 27 </a>
18 28 % else:
19 29 <a class="btn btn-default" href="${h.route_path('repo_file_download',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}">
20 30 ${_('Download file')}
21 31 </a>
22 32 % endif
23 33
24 34 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
25 35 ## on branch head, can edit files
26 36 %if c.on_branch_head and c.branch_or_raw_id:
27 37 ## binary files are delete only
28 38 % if c.file.is_binary:
29 39 ${h.link_to(_('Edit'), '#Edit', class_="btn btn-default disabled tooltip", title=_('Editing binary files not allowed'))}
30 ${h.link_to(_('Delete'), h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path),class_="btn btn-danger")}
40 ${h.link_to(_('Delete'), h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _query=query),class_="btn btn-danger")}
31 41 % else:
32 <a class="btn btn-default" href="${h.route_path('repo_files_edit_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path)}">
42 <a class="btn btn-default" href="${h.route_path('repo_files_edit_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _query=query)}">
33 43 ${_('Edit on branch: ')}<code>${c.branch_name}</code>
34 44 </a>
35 45
36 <a class="btn btn-danger" href="${h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path)}">
46 <a class="btn btn-danger" href="${h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _query=query)}">
37 47 ${_('Delete')}
38 48 </a>
39 49 % endif
40 50 ## not on head, forbid all
41 51 % else:
42 52 ${h.link_to(_('Edit'), '#Edit', class_="btn btn-default disabled tooltip", title=_('Editing files allowed only when on branch head commit'))}
43 53 ${h.link_to(_('Delete'), '#Delete', class_="btn btn-default btn-danger disabled tooltip", title=_('Deleting files allowed only when on branch head commit'))}
44 54 % endif
45 55 %endif
46 56
47 57 </div>
48 58 </div>
49 59 <div id="file_history_container"></div>
50 60
51 61 </div>
52 62 </div>
53 63
54 64 <div class="codeblock">
55 65 <div class=" codeblock-header">
56 66 <div class="file-filename">
57 67 <i class="icon-file"></i> ${c.file}
58 68 </div>
59 69
60 70 <div class="file-stats">
61 71
62 72 <div class="stats-info">
63 73 <span class="stats-first-item">
64 74 % if c.file_size_too_big:
65 75 0 ${(_('lines'))}
66 76 % else:
67 77 ${c.file.lines()[0]} ${_ungettext('line', 'lines', c.file.lines()[0])}
68 78 % endif
69 79 </span>
70 80
71 81 <span> | ${h.format_byte_size_binary(c.file.size)}</span>
72 82 % if c.lf_node:
73 83 <span title="${_('This file is a pointer to large binary file')}"> | ${_('LargeFile')} ${h.format_byte_size_binary(c.lf_node.size)} </span>
74 84 % endif
75 85 <span>
76 86 | ${c.file.mimetype}
77 87 </span>
78 88
79 89 % if not c.file_size_too_big:
80 90 <span> |
81 91 ${h.get_lexer_for_filenode(c.file).__class__.__name__}
82 92 </span>
83 93 % endif
84 94
85 95 </div>
86 96 </div>
87 97 </div>
88 98
89 99 <div class="path clear-fix">
90 100 <div class="pull-left">
91 ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.file.path, request.GET.get('at'))}
101 ${h.files_breadcrumbs(c.repo_name, c.rhodecode_db_repo.repo_type, c.commit.raw_id, c.file.path, c.rhodecode_db_repo.landing_ref_name, request.GET.get('at'))}
92 102 </div>
93 103
94 104 <div class="pull-right stats">
95 105 <a id="file_history_overview" href="#loadHistory">
96 106 ${_('History')}
97 107 </a>
98 108 |
99 109 %if c.annotate:
100 110 ${h.link_to(_('Source'), h.route_path('repo_files', repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
101 111 %else:
102 112 ${h.link_to(_('Annotation'), h.route_path('repo_files:annotated',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
103 113 %endif
104 114 | ${h.link_to(_('Raw'), h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
105 115 % if not c.file.is_binary:
106 116 |<a href="#copySource" onclick="return false;" class="no-grey clipboard-action" data-clipboard-text="${c.file.content}">${_('Copy content')}</a>
107 |<a href="#copySource" onclick="return false;" class="no-grey clipboard-action" data-clipboard-text="${h.route_url('repo_files', repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}">${_('Copy permalink')}</a>
117 |<a href="#copyPermaLink" onclick="return false;" class="no-grey clipboard-action" data-clipboard-text="${h.route_url('repo_files', repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}">${_('Copy permalink')}</a>
108 118 % endif
109 119
110 120 </div>
111 121 <div class="clear-fix"></div>
112 122 </div>
113 123
114 124 <div class="code-body clear-fix ">
115 125 %if c.file.is_binary:
116 126 <% rendered_binary = h.render_binary(c.repo_name, c.file)%>
117 127 % if rendered_binary:
118 128 <div class="text-center">
119 129 ${rendered_binary}
120 130 </div>
121 131 % else:
122 132 <div>
123 133 ${_('Binary file ({})').format(c.file.mimetype)}
124 134 </div>
125 135 % endif
126 136 %else:
127 137 % if c.file_size_too_big:
128 138 ${_('File size {} is bigger then allowed limit {}. ').format(h.format_byte_size_binary(c.file.size), h.format_byte_size_binary(c.visual.cut_off_limit_file))} ${h.link_to(_('Show as raw'),
129 139 h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
130 140 % else:
131 141 %if c.renderer and not c.annotate:
132 142 ## pick relative url based on renderer
133 143 <%
134 144 relative_urls = {
135 145 'raw': h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path),
136 146 'standard': h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path),
137 147 }
138 148 %>
139 149 ${h.render(c.file.content, renderer=c.renderer, relative_urls=relative_urls)}
140 150 %else:
141 151 <table class="cb codehilite">
142 152 %if c.annotate:
143 153 <% color_hasher = h.color_hasher() %>
144 154 %for annotation, lines in c.annotated_lines:
145 155 ${sourceblock.render_annotation_lines(annotation, lines, color_hasher)}
146 156 %endfor
147 157 %else:
148 158 %for line_num, tokens in enumerate(c.lines, 1):
149 159 ${sourceblock.render_line(line_num, tokens)}
150 160 %endfor
151 161 %endif
152 162 </table>
153 163 %endif
154 164 % endif
155 165 %endif
156 166 </div>
157 167
158 168 </div>
159 169
160 170 <script type="text/javascript">
161 171 % if request.GET.get('mark'):
162 172
163 173 $(function(){
164 174 $(".codehilite").mark(
165 175 "${request.GET.get('mark')}",
166 176 {
167 177 "className": 'match',
168 178 "accuracy": "complementary",
169 179 "ignorePunctuation": ":._(){}[]!'+=".split(""),
170 180 "each": function(el) {
171 181 // and also highlight lines !
172 182 $($(el).closest('tr')).find('td.cb-lineno').addClass('cb-line-selected');
173 183 }
174 184 }
175 185 );
176 186
177 187 });
178 188 % endif
179 189 </script>
@@ -1,922 +1,922 b''
1 1 <%inherit file="/base/base.mako"/>
2 2 <%namespace name="base" file="/base/base.mako"/>
3 3 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
4 4
5 5 <%def name="title()">
6 6 ${_('{} Pull Request !{}').format(c.repo_name, c.pull_request.pull_request_id)}
7 7 %if c.rhodecode_name:
8 8 &middot; ${h.branding(c.rhodecode_name)}
9 9 %endif
10 10 </%def>
11 11
12 12 <%def name="breadcrumbs_links()">
13 13
14 14 </%def>
15 15
16 16 <%def name="menu_bar_nav()">
17 17 ${self.menu_items(active='repositories')}
18 18 </%def>
19 19
20 20 <%def name="menu_bar_subnav()">
21 21 ${self.repo_menu(active='showpullrequest')}
22 22 </%def>
23 23
24 24 <%def name="main()">
25 25
26 26 <script type="text/javascript">
27 27 // TODO: marcink switch this to pyroutes
28 28 AJAX_COMMENT_DELETE_URL = "${h.route_path('pullrequest_comment_delete',repo_name=c.repo_name,pull_request_id=c.pull_request.pull_request_id,comment_id='__COMMENT_ID__')}";
29 29 templateContext.pull_request_data.pull_request_id = ${c.pull_request.pull_request_id};
30 30 </script>
31 31
32 32 <div class="box">
33 33
34 34 <div class="box pr-summary">
35 35
36 36 <div class="summary-details block-left">
37 37 <div id="pr-title">
38 38 % if c.pull_request.is_closed():
39 39 <span class="pr-title-closed-tag tag">${_('Closed')}</span>
40 40 % endif
41 41 <input class="pr-title-input large disabled" disabled="disabled" name="pullrequest_title" type="text" value="${c.pull_request.title}">
42 42 </div>
43 43 <div id="pr-title-edit" class="input" style="display: none;">
44 44 <input class="pr-title-input large" id="pr-title-input" name="pullrequest_title" type="text" value="${c.pull_request.title}">
45 45 </div>
46 46
47 47 <% summary = lambda n:{False:'summary-short'}.get(n) %>
48 48 <div class="pr-details-title">
49 49 <div class="pull-left">
50 50 <a href="${h.route_path('pull_requests_global', pull_request_id=c.pull_request.pull_request_id)}">${_('Pull request !{}').format(c.pull_request.pull_request_id)}</a>
51 51 ${_('Created on')}
52 52 <span class="tooltip" title="${_('Last updated on')} ${h.format_date(c.pull_request.updated_on)}">${h.format_date(c.pull_request.created_on)},</span>
53 53 <span class="pr-details-title-author-pref">${_('by')}</span>
54 54 </div>
55 55
56 56 <div class="pull-left">
57 57 ${self.gravatar_with_user(c.pull_request.author.email, 16, tooltip=True)}
58 58 </div>
59 59
60 60 %if c.allowed_to_update:
61 61 <div class="pull-right">
62 62 <div id="edit_pull_request" class="action_button pr-save" style="display: none;">${_('Update title & description')}</div>
63 63 <div id="delete_pullrequest" class="action_button pr-save ${('' if c.allowed_to_delete else 'disabled' )}" style="display: none;">
64 64 % if c.allowed_to_delete:
65 65 ${h.secure_form(h.route_path('pullrequest_delete', repo_name=c.pull_request.target_repo.repo_name, pull_request_id=c.pull_request.pull_request_id), request=request)}
66 66 <input class="btn btn-link btn-danger no-margin" id="remove_${c.pull_request.pull_request_id}" name="remove_${c.pull_request.pull_request_id}"
67 67 onclick="submitConfirm(event, this, _gettext('Confirm to delete this pull request'), _gettext('Delete'), '${'!{}'.format(c.pull_request.pull_request_id)}')"
68 68 type="submit" value="${_('Delete pull request')}">
69 69 ${h.end_form()}
70 70 % else:
71 71 <span class="tooltip" title="${_('Not allowed to delete this pull request')}">${_('Delete pull request')}</span>
72 72 % endif
73 73 </div>
74 74 <div id="open_edit_pullrequest" class="action_button">${_('Edit')}</div>
75 75 <div id="close_edit_pullrequest" class="action_button" style="display: none;">${_('Cancel')}</div>
76 76 </div>
77 77
78 78 %endif
79 79 </div>
80 80
81 81 <div id="pr-desc" class="input" title="${_('Rendered using {} renderer').format(c.renderer)}">
82 82 ${h.render(c.pull_request.description, renderer=c.renderer, repo_name=c.repo_name)}
83 83 </div>
84 84
85 85 <div id="pr-desc-edit" class="input textarea" style="display: none;">
86 86 <input id="pr-renderer-input" type="hidden" name="description_renderer" value="${c.visual.default_renderer}">
87 87 ${dt.markup_form('pr-description-input', form_text=c.pull_request.description)}
88 88 </div>
89 89
90 90 <div id="summary" class="fields pr-details-content">
91 91
92 92 ## review
93 93 <div class="field">
94 94 <div class="label-pr-detail">
95 95 <label>${_('Review status')}:</label>
96 96 </div>
97 97 <div class="input">
98 98 %if c.pull_request_review_status:
99 99 <div class="tag status-tag-${c.pull_request_review_status}">
100 100 <i class="icon-circle review-status-${c.pull_request_review_status}"></i>
101 101 <span class="changeset-status-lbl">
102 102 %if c.pull_request.is_closed():
103 103 ${_('Closed')},
104 104 %endif
105 105
106 106 ${h.commit_status_lbl(c.pull_request_review_status)}
107 107
108 108 </span>
109 109 </div>
110 110 - ${_ungettext('calculated based on {} reviewer vote', 'calculated based on {} reviewers votes', len(c.pull_request_reviewers)).format(len(c.pull_request_reviewers))}
111 111 %endif
112 112 </div>
113 113 </div>
114 114
115 115 ## source
116 116 <div class="field">
117 117 <div class="label-pr-detail">
118 118 <label>${_('Commit flow')}:</label>
119 119 </div>
120 120 <div class="input">
121 121 <div class="pr-commit-flow">
122 122 ## Source
123 123 %if c.pull_request.source_ref_parts.type == 'branch':
124 124 <a href="${h.route_path('repo_commits', repo_name=c.pull_request.source_repo.repo_name, _query=dict(branch=c.pull_request.source_ref_parts.name))}"><code class="pr-source-info">${c.pull_request.source_ref_parts.type}:${c.pull_request.source_ref_parts.name}</code></a>
125 125 %else:
126 126 <code class="pr-source-info">${'{}:{}'.format(c.pull_request.source_ref_parts.type, c.pull_request.source_ref_parts.name)}</code>
127 127 %endif
128 128 ${_('of')} <a href="${h.route_path('repo_summary', repo_name=c.pull_request.source_repo.repo_name)}">${c.pull_request.source_repo.repo_name}</a>
129 129 &rarr;
130 130 ## Target
131 131 %if c.pull_request.target_ref_parts.type == 'branch':
132 132 <a href="${h.route_path('repo_commits', repo_name=c.pull_request.target_repo.repo_name, _query=dict(branch=c.pull_request.target_ref_parts.name))}"><code class="pr-target-info">${c.pull_request.target_ref_parts.type}:${c.pull_request.target_ref_parts.name}</code></a>
133 133 %else:
134 134 <code class="pr-target-info">${'{}:{}'.format(c.pull_request.target_ref_parts.type, c.pull_request.target_ref_parts.name)}</code>
135 135 %endif
136 136
137 137 ${_('of')} <a href="${h.route_path('repo_summary', repo_name=c.pull_request.target_repo.repo_name)}">${c.pull_request.target_repo.repo_name}</a>
138 138
139 139 <a class="source-details-action" href="#expand-source-details" onclick="return versionController.toggleElement(this, '.source-details')" data-toggle-on='<i class="icon-angle-down">more details</i>' data-toggle-off='<i class="icon-angle-up">less details</i>'>
140 140 <i class="icon-angle-down">more details</i>
141 141 </a>
142 142
143 143 </div>
144 144
145 145 <div class="source-details" style="display: none">
146 146
147 147 <ul>
148 148
149 149 ## common ancestor
150 150 <li>
151 151 ${_('Common ancestor')}:
152 152 % if c.ancestor_commit:
153 153 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=c.ancestor_commit.raw_id)}">${h.show_id(c.ancestor_commit)}</a>
154 154 % else:
155 155 ${_('not available')}
156 156 % endif
157 157 </li>
158 158
159 159 ## pull url
160 160 <li>
161 161 %if h.is_hg(c.pull_request.source_repo):
162 162 <% clone_url = 'hg pull -r {} {}'.format(h.short_id(c.source_ref), c.pull_request.source_repo.clone_url()) %>
163 163 %elif h.is_git(c.pull_request.source_repo):
164 164 <% clone_url = 'git pull {} {}'.format(c.pull_request.source_repo.clone_url(), c.pull_request.source_ref_parts.name) %>
165 165 %endif
166 166
167 167 <span>${_('Pull changes from source')}</span>: <input type="text" class="input-monospace pr-pullinfo" value="${clone_url}" readonly="readonly">
168 168 <i class="tooltip icon-clipboard clipboard-action pull-right pr-pullinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the pull url')}"></i>
169 169 </li>
170 170
171 171 ## Shadow repo
172 172 <li>
173 173 % if not c.pull_request.is_closed() and c.pull_request.shadow_merge_ref:
174 174 %if h.is_hg(c.pull_request.target_repo):
175 175 <% clone_url = 'hg clone --update {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
176 176 %elif h.is_git(c.pull_request.target_repo):
177 177 <% clone_url = 'git clone --branch {} {} pull-request-{}'.format(c.pull_request.shadow_merge_ref.name, c.shadow_clone_url, c.pull_request.pull_request_id) %>
178 178 %endif
179 179
180 180 <span class="tooltip" title="${_('Clone repository in its merged state using shadow repository')}">${_('Clone from shadow repository')}</span>: <input type="text" class="input-monospace pr-mergeinfo" value="${clone_url}" readonly="readonly">
181 181 <i class="tooltip icon-clipboard clipboard-action pull-right pr-mergeinfo-copy" data-clipboard-text="${clone_url}" title="${_('Copy the clone url')}"></i>
182 182
183 183 % else:
184 184 <div class="">
185 185 ${_('Shadow repository data not available')}.
186 186 </div>
187 187 % endif
188 188 </li>
189 189
190 190 </ul>
191 191
192 192 </div>
193 193
194 194 </div>
195 195
196 196 </div>
197 197
198 198 ## versions
199 199 <div class="field">
200 200 <div class="label-pr-detail">
201 201 <label>${_('Versions')}:</label>
202 202 </div>
203 203
204 204 <% outdated_comm_count_ver = len(c.inline_versions[None]['outdated']) %>
205 205 <% general_outdated_comm_count_ver = len(c.comment_versions[None]['outdated']) %>
206 206
207 207 <div class="pr-versions">
208 208 % if c.show_version_changes:
209 209 <% outdated_comm_count_ver = len(c.inline_versions[c.at_version_num]['outdated']) %>
210 210 <% general_outdated_comm_count_ver = len(c.comment_versions[c.at_version_num]['outdated']) %>
211 211 ${_ungettext('{} version available for this pull request, ', '{} versions available for this pull request, ', len(c.versions)).format(len(c.versions))}
212 212 <a id="show-pr-versions" onclick="return versionController.toggleVersionView(this)" href="#show-pr-versions"
213 213 data-toggle-on="${_('show versions')}."
214 214 data-toggle-off="${_('hide versions')}.">
215 215 ${_('show versions')}.
216 216 </a>
217 217 <table>
218 218 ## SHOW ALL VERSIONS OF PR
219 219 <% ver_pr = None %>
220 220
221 221 % for data in reversed(list(enumerate(c.versions, 1))):
222 222 <% ver_pos = data[0] %>
223 223 <% ver = data[1] %>
224 224 <% ver_pr = ver.pull_request_version_id %>
225 225 <% display_row = '' if c.at_version and (c.at_version_num == ver_pr or c.from_version_num == ver_pr) else 'none' %>
226 226
227 227 <tr class="version-pr" style="display: ${display_row}">
228 228 <td>
229 229 <code>
230 230 <a href="${request.current_route_path(_query=dict(version=ver_pr or 'latest'))}">v${ver_pos}</a>
231 231 </code>
232 232 </td>
233 233 <td>
234 234 <input ${('checked="checked"' if c.from_version_num == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_source" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
235 235 <input ${('checked="checked"' if c.at_version_num == ver_pr else '')} class="compare-radio-button" type="radio" name="ver_target" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/>
236 236 </td>
237 237 <td>
238 238 <% review_status = c.review_versions[ver_pr].status if ver_pr in c.review_versions else 'not_reviewed' %>
239 239 <i class="tooltip icon-circle review-status-${review_status}" title="${_('Your review status at this version')}"></i>
240 240
241 241 </td>
242 242 <td>
243 243 % if c.at_version_num != ver_pr:
244 244 <i class="tooltip icon-comment" title="${_('Comments from pull request version v{0}').format(ver_pos)}"></i>
245 245 <code>
246 246 General:${len(c.comment_versions[ver_pr]['at'])} / Inline:${len(c.inline_versions[ver_pr]['at'])}
247 247 </code>
248 248 % endif
249 249 </td>
250 250 <td>
251 251 ##<code>${ver.source_ref_parts.commit_id[:6]}</code>
252 252 </td>
253 253 <td>
254 254 <code>${h.age_component(ver.updated_on, time_is_local=True, tooltip=False)}</code>
255 255 </td>
256 256 </tr>
257 257 % endfor
258 258
259 259 <tr>
260 260 <td colspan="6">
261 261 <button id="show-version-diff" onclick="return versionController.showVersionDiff()" class="btn btn-sm" style="display: none"
262 262 data-label-text-locked="${_('select versions to show changes')}"
263 263 data-label-text-diff="${_('show changes between versions')}"
264 264 data-label-text-show="${_('show pull request for this version')}"
265 265 >
266 266 ${_('select versions to show changes')}
267 267 </button>
268 268 </td>
269 269 </tr>
270 270 </table>
271 271 % else:
272 272 <div>
273 273 ${_('Pull request versions not available')}.
274 274 </div>
275 275 % endif
276 276 </div>
277 277 </div>
278 278
279 279 </div>
280 280
281 281 </div>
282 282
283 283 ## REVIEW RULES
284 284 <div id="review_rules" style="display: none" class="reviewers-title block-right">
285 285 <div class="pr-details-title">
286 286 ${_('Reviewer rules')}
287 287 %if c.allowed_to_update:
288 288 <span id="close_edit_reviewers" class="block-right action_button last-item" style="display: none;">${_('Close')}</span>
289 289 %endif
290 290 </div>
291 291 <div class="pr-reviewer-rules">
292 292 ## review rules will be appended here, by default reviewers logic
293 293 </div>
294 294 <input id="review_data" type="hidden" name="review_data" value="">
295 295 </div>
296 296
297 297 ## REVIEWERS
298 298 <div class="reviewers-title first-panel block-right">
299 299 <div class="pr-details-title">
300 300 ${_('Pull request reviewers')}
301 301 %if c.allowed_to_update:
302 302 <span id="open_edit_reviewers" class="block-right action_button last-item">${_('Edit')}</span>
303 303 %endif
304 304 </div>
305 305 </div>
306 306 <div id="reviewers" class="block-right pr-details-content reviewers">
307 307
308 308 ## members redering block
309 309 <input type="hidden" name="__start__" value="review_members:sequence">
310 310 <ul id="review_members" class="group_members">
311 311
312 312 % for review_obj, member, reasons, mandatory, status in c.pull_request_reviewers:
313 313 <script>
314 314 var member = ${h.json.dumps(h.reviewer_as_json(member, reasons=reasons, mandatory=mandatory, user_group=review_obj.rule_user_group_data()))|n};
315 315 var status = "${(status[0][1].status if status else 'not_reviewed')}";
316 316 var status_lbl = "${h.commit_status_lbl(status[0][1].status if status else 'not_reviewed')}";
317 317 var allowed_to_update = ${h.json.dumps(c.allowed_to_update)};
318 318
319 319 var entry = renderTemplate('reviewMemberEntry', {
320 320 'member': member,
321 321 'mandatory': member.mandatory,
322 322 'reasons': member.reasons,
323 323 'allowed_to_update': allowed_to_update,
324 324 'review_status': status,
325 325 'review_status_label': status_lbl,
326 326 'user_group': member.user_group,
327 327 'create': false
328 328 });
329 329 $('#review_members').append(entry)
330 330 </script>
331 331
332 332 % endfor
333 333
334 334 </ul>
335 335
336 336 <input type="hidden" name="__end__" value="review_members:sequence">
337 337 ## end members redering block
338 338
339 339 %if not c.pull_request.is_closed():
340 340 <div id="add_reviewer" class="ac" style="display: none;">
341 341 %if c.allowed_to_update:
342 342 % if not c.forbid_adding_reviewers:
343 343 <div id="add_reviewer_input" class="reviewer_ac">
344 344 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
345 345 <div id="reviewers_container"></div>
346 346 </div>
347 347 % endif
348 348 <div class="pull-right">
349 349 <button id="update_pull_request" class="btn btn-small no-margin">${_('Save Changes')}</button>
350 350 </div>
351 351 %endif
352 352 </div>
353 353 %endif
354 354 </div>
355 355
356 356 ## TODOs will be listed here
357 357 <div class="reviewers-title block-right">
358 358 <div class="pr-details-title">
359 359 ## Only show unresolved, that is only what matters
360 360 TODO Comments - ${len(c.unresolved_comments)} / ${(len(c.unresolved_comments) + len(c.resolved_comments))}
361 361
362 362 % if not c.at_version:
363 363 % if c.resolved_comments:
364 364 <span class="block-right action_button last-item noselect" onclick="$('.unresolved-todo-text').toggle(); return versionController.toggleElement(this, '.unresolved-todo');" data-toggle-on="Show resolved" data-toggle-off="Hide resolved">Show resolved</span>
365 365 % else:
366 366 <span class="block-right last-item noselect">Show resolved</span>
367 367 % endif
368 368 % endif
369 369 </div>
370 370 </div>
371 371 <div class="block-right pr-details-content reviewers">
372 372
373 373 <table class="todo-table">
374 374 <%
375 375 def sorter(entry):
376 376 user_id = entry.author.user_id
377 377 resolved = '1' if entry.resolved else '0'
378 378 if user_id == c.rhodecode_user.user_id:
379 379 # own comments first
380 380 user_id = 0
381 381 return '{}_{}_{}'.format(resolved, user_id, str(entry.comment_id).zfill(100))
382 382 %>
383 383
384 384 % if c.at_version:
385 385 <tr>
386 386 <td class="unresolved-todo-text">${_('unresolved TODOs unavailable in this view')}.</td>
387 387 </tr>
388 388 % else:
389 389 % for todo_comment in sorted(c.unresolved_comments + c.resolved_comments, key=sorter):
390 390 <% resolved = todo_comment.resolved %>
391 391 % if inline:
392 392 <% outdated_at_ver = todo_comment.outdated_at_version(getattr(c, 'at_version_num', None)) %>
393 393 % else:
394 394 <% outdated_at_ver = todo_comment.older_than_version(getattr(c, 'at_version_num', None)) %>
395 395 % endif
396 396
397 397 <tr ${('class="unresolved-todo" style="display: none"' if resolved else '') |n}>
398 398
399 399 <td class="td-todo-number">
400 400 % if resolved:
401 401 <a class="permalink todo-resolved tooltip" title="${_('Resolved by comment #{}').format(todo_comment.resolved.comment_id)}" href="#comment-${todo_comment.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${todo_comment.comment_id}'), 0, ${h.json.dumps(outdated_at_ver)})">
402 402 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
403 403 % else:
404 404 <a class="permalink" href="#comment-${todo_comment.comment_id}" onclick="return Rhodecode.comments.scrollToComment($('#comment-${todo_comment.comment_id}'), 0, ${h.json.dumps(outdated_at_ver)})">
405 405 <i class="icon-flag-filled"></i> ${todo_comment.comment_id}</a>
406 406 % endif
407 407 </td>
408 408 <td class="td-todo-gravatar">
409 409 ${base.gravatar(todo_comment.author.email, 16, user=todo_comment.author, tooltip=True, extra_class=['no-margin'])}
410 410 </td>
411 411 <td class="todo-comment-text-wrapper">
412 412 <div class="todo-comment-text">
413 413 <code>${h.chop_at_smart(todo_comment.text, '\n', suffix_if_chopped='...')}</code>
414 414 </div>
415 415 </td>
416 416
417 417 </tr>
418 418 % endfor
419 419
420 420 % if len(c.unresolved_comments) == 0:
421 421 <tr>
422 422 <td class="unresolved-todo-text">${_('No unresolved TODOs')}.</td>
423 423 </tr>
424 424 % endif
425 425
426 426 % endif
427 427
428 428 </table>
429 429
430 430 </div>
431 431 </div>
432 432
433 433 </div>
434 434
435 435 <div class="box">
436 436
437 437 % if c.state_progressing:
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 441
442 442 % if c.is_super_admin:
443 443 <br/>
444 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 445 % endif
446 446 </h2>
447 447
448 448 % else:
449 449
450 450 ## Diffs rendered here
451 451 <div class="table" >
452 452 <div id="changeset_compare_view_content">
453 453 ##CS
454 454 % if c.missing_requirements:
455 455 <div class="box">
456 456 <div class="alert alert-warning">
457 457 <div>
458 458 <strong>${_('Missing requirements:')}</strong>
459 459 ${_('These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled.')}
460 460 </div>
461 461 </div>
462 462 </div>
463 463 % elif c.missing_commits:
464 464 <div class="box">
465 465 <div class="alert alert-warning">
466 466 <div>
467 467 <strong>${_('Missing commits')}:</strong>
468 468 ${_('This pull request cannot be displayed, because one or more commits no longer exist in the source repository.')}
469 469 ${_('Please update this pull request, push the commits back into the source repository, or consider closing this pull request.')}
470 470 ${_('Consider doing a {force_refresh_url} in case you think this is an error.').format(force_refresh_url=h.link_to('force refresh', h.current_route_path(request, force_refresh='1')))|n}
471 471 </div>
472 472 </div>
473 473 </div>
474 474 % elif c.pr_merge_source_commit.changed:
475 475 <div class="box">
476 476 <div class="alert alert-info">
477 477 <div>
478 478 % if c.pr_merge_source_commit.changed:
479 <strong>${_('There are new changes for {}:{} in source repository, please consider updating this pull request.').format(c.pr_merge_source_commit.ref_spec.type, c.pr_merge_source_commit.ref_spec.name)}</strong>
479 <strong>${_('There are new changes for `{}:{}` in source repository, please consider updating this pull request.').format(c.pr_merge_source_commit.ref_spec.type, c.pr_merge_source_commit.ref_spec.name)}</strong>
480 480 % endif
481 481 </div>
482 482 </div>
483 483 </div>
484 484 % endif
485 485
486 486 <div class="compare_view_commits_title">
487 487 % if not c.compare_mode:
488 488
489 489 % if c.at_version_pos:
490 490 <h4>
491 491 ${_('Showing changes at v%d, commenting is disabled.') % c.at_version_pos}
492 492 </h4>
493 493 % endif
494 494
495 495 <div class="pull-left">
496 496 <div class="btn-group">
497 497 <a class="${('collapsed' if c.collapse_all_commits else '')}" href="#expand-commits" onclick="toggleCommitExpand(this); return false" data-toggle-commits-cnt=${len(c.commit_ranges)} >
498 498 % if c.collapse_all_commits:
499 499 <i class="icon-plus-squared-alt icon-no-margin"></i>
500 500 ${_ungettext('Expand {} commit', 'Expand {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
501 501 % else:
502 502 <i class="icon-minus-squared-alt icon-no-margin"></i>
503 503 ${_ungettext('Collapse {} commit', 'Collapse {} commits', len(c.commit_ranges)).format(len(c.commit_ranges))}
504 504 % endif
505 505 </a>
506 506 </div>
507 507 </div>
508 508
509 509 <div class="pull-right">
510 510 % if c.allowed_to_update and not c.pull_request.is_closed():
511 511
512 512 <div class="btn-group btn-group-actions">
513 513 <a id="update_commits" class="btn btn-primary no-margin" onclick="updateController.updateCommits(this); return false">
514 514 ${_('Update commits')}
515 515 </a>
516 516
517 517 <a id="update_commits_switcher" class="tooltip btn btn-primary" style="margin-left: -1px" data-toggle="dropdown" aria-pressed="false" role="button" title="${_('more update options')}">
518 518 <i class="icon-down"></i>
519 519 </a>
520 520
521 521 <div class="btn-action-switcher-container" id="update-commits-switcher">
522 522 <ul class="btn-action-switcher" role="menu">
523 523 <li>
524 524 <a href="#forceUpdate" onclick="updateController.forceUpdateCommits(this); return false">
525 525 ${_('Force update commits')}
526 526 </a>
527 527 <div class="action-help-block">
528 528 ${_('Update commits and force refresh this pull request.')}
529 529 </div>
530 530 </li>
531 531 </ul>
532 532 </div>
533 533 </div>
534 534
535 535 % else:
536 536 <a class="tooltip btn disabled pull-right" disabled="disabled" title="${_('Update is disabled for current view')}">${_('Update commits')}</a>
537 537 % endif
538 538
539 539 </div>
540 540 % endif
541 541 </div>
542 542
543 543 % if not c.missing_commits:
544 544 % if c.compare_mode:
545 545 % if c.at_version:
546 546 <h4>
547 547 ${_('Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled').format(ver_from=c.from_version_pos, ver_to=c.at_version_pos if c.at_version_pos else 'latest')}:
548 548 </h4>
549 549
550 550 <div class="subtitle-compare">
551 551 ${_('commits added: {}, removed: {}').format(len(c.commit_changes_summary.added), len(c.commit_changes_summary.removed))}
552 552 </div>
553 553
554 554 <div class="container">
555 555 <table class="rctable compare_view_commits">
556 556 <tr>
557 557 <th></th>
558 558 <th>${_('Time')}</th>
559 559 <th>${_('Author')}</th>
560 560 <th>${_('Commit')}</th>
561 561 <th></th>
562 562 <th>${_('Description')}</th>
563 563 </tr>
564 564
565 565 % for c_type, commit in c.commit_changes:
566 566 % if c_type in ['a', 'r']:
567 567 <%
568 568 if c_type == 'a':
569 569 cc_title = _('Commit added in displayed changes')
570 570 elif c_type == 'r':
571 571 cc_title = _('Commit removed in displayed changes')
572 572 else:
573 573 cc_title = ''
574 574 %>
575 575 <tr id="row-${commit.raw_id}" commit_id="${commit.raw_id}" class="compare_select">
576 576 <td>
577 577 <div class="commit-change-indicator color-${c_type}-border">
578 578 <div class="commit-change-content color-${c_type} tooltip" title="${h.tooltip(cc_title)}">
579 579 ${c_type.upper()}
580 580 </div>
581 581 </div>
582 582 </td>
583 583 <td class="td-time">
584 584 ${h.age_component(commit.date)}
585 585 </td>
586 586 <td class="td-user">
587 587 ${base.gravatar_with_user(commit.author, 16, tooltip=True)}
588 588 </td>
589 589 <td class="td-hash">
590 590 <code>
591 591 <a href="${h.route_path('repo_commit', repo_name=c.target_repo.repo_name, commit_id=commit.raw_id)}">
592 592 r${commit.idx}:${h.short_id(commit.raw_id)}
593 593 </a>
594 594 ${h.hidden('revisions', commit.raw_id)}
595 595 </code>
596 596 </td>
597 597 <td class="td-message expand_commit" data-commit-id="${commit.raw_id}" title="${_( 'Expand commit message')}" onclick="commitsController.expandCommit(this); return false">
598 598 <i class="icon-expand-linked"></i>
599 599 </td>
600 600 <td class="mid td-description">
601 601 <div class="log-container truncate-wrap">
602 602 <div class="message truncate" id="c-${commit.raw_id}" data-message-raw="${commit.message}">${h.urlify_commit_message(commit.message, c.repo_name)}</div>
603 603 </div>
604 604 </td>
605 605 </tr>
606 606 % endif
607 607 % endfor
608 608 </table>
609 609 </div>
610 610
611 611 % endif
612 612
613 613 % else:
614 614 <%include file="/compare/compare_commits.mako" />
615 615 % endif
616 616
617 617 <div class="cs_files">
618 618 <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/>
619 619 % if c.at_version:
620 620 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['display']) %>
621 621 <% c.comments = c.comment_versions[c.at_version_num]['display'] %>
622 622 % else:
623 623 <% c.inline_cnt = len(c.inline_versions[c.at_version_num]['until']) %>
624 624 <% c.comments = c.comment_versions[c.at_version_num]['until'] %>
625 625 % endif
626 626
627 627 <%
628 628 pr_menu_data = {
629 629 'outdated_comm_count_ver': outdated_comm_count_ver
630 630 }
631 631 %>
632 632
633 633 ${cbdiffs.render_diffset_menu(c.diffset, range_diff_on=c.range_diff_on)}
634 634
635 635 % if c.range_diff_on:
636 636 % for commit in c.commit_ranges:
637 637 ${cbdiffs.render_diffset(
638 638 c.changes[commit.raw_id],
639 639 commit=commit, use_comments=True,
640 640 collapse_when_files_over=5,
641 641 disable_new_comments=True,
642 642 deleted_files_comments=c.deleted_files_comments,
643 643 inline_comments=c.inline_comments,
644 644 pull_request_menu=pr_menu_data, show_todos=False)}
645 645 % endfor
646 646 % else:
647 647 ${cbdiffs.render_diffset(
648 648 c.diffset, use_comments=True,
649 649 collapse_when_files_over=30,
650 650 disable_new_comments=not c.allowed_to_comment,
651 651 deleted_files_comments=c.deleted_files_comments,
652 652 inline_comments=c.inline_comments,
653 653 pull_request_menu=pr_menu_data, show_todos=False)}
654 654 % endif
655 655
656 656 </div>
657 657 % else:
658 658 ## skipping commits we need to clear the view for missing commits
659 659 <div style="clear:both;"></div>
660 660 % endif
661 661
662 662 </div>
663 663 </div>
664 664
665 665 ## template for inline comment form
666 666 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
667 667
668 668 ## comments heading with count
669 669 <div class="comments-heading">
670 670 <i class="icon-comment"></i>
671 671 ${_('Comments')} ${len(c.comments)}
672 672 </div>
673 673
674 674 ## render general comments
675 675 <div id="comment-tr-show">
676 676 % if general_outdated_comm_count_ver:
677 677 <div class="info-box">
678 678 % if general_outdated_comm_count_ver == 1:
679 679 ${_('there is {num} general comment from older versions').format(num=general_outdated_comm_count_ver)},
680 680 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show it')}</a>
681 681 % else:
682 682 ${_('there are {num} general comments from older versions').format(num=general_outdated_comm_count_ver)},
683 683 <a href="#show-hidden-comments" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show them')}</a>
684 684 % endif
685 685 </div>
686 686 % endif
687 687 </div>
688 688
689 689 ${comment.generate_comments(c.comments, include_pull_request=True, is_pull_request=True)}
690 690
691 691 % if not c.pull_request.is_closed():
692 692 ## main comment form and it status
693 693 ${comment.comments(h.route_path('pullrequest_comment_create', repo_name=c.repo_name,
694 694 pull_request_id=c.pull_request.pull_request_id),
695 695 c.pull_request_review_status,
696 696 is_pull_request=True, change_status=c.allowed_to_change_status)}
697 697
698 698 ## merge status, and merge action
699 699 <div class="pull-request-merge">
700 700 <%include file="/pullrequests/pullrequest_merge_checks.mako"/>
701 701 </div>
702 702
703 703 %endif
704 704
705 705 % endif
706 706 </div>
707 707
708 708 <script type="text/javascript">
709 709
710 710 versionController = new VersionController();
711 711 versionController.init();
712 712
713 713 reviewersController = new ReviewersController();
714 714 commitsController = new CommitsController();
715 715
716 716 updateController = new UpdatePrController();
717 717
718 718 $(function () {
719 719
720 720 // custom code mirror
721 721 var codeMirrorInstance = $('#pr-description-input').get(0).MarkupForm.cm;
722 722
723 723 var PRDetails = {
724 724 editButton: $('#open_edit_pullrequest'),
725 725 closeButton: $('#close_edit_pullrequest'),
726 726 deleteButton: $('#delete_pullrequest'),
727 727 viewFields: $('#pr-desc, #pr-title'),
728 728 editFields: $('#pr-desc-edit, #pr-title-edit, .pr-save'),
729 729
730 730 init: function () {
731 731 var that = this;
732 732 this.editButton.on('click', function (e) {
733 733 that.edit();
734 734 });
735 735 this.closeButton.on('click', function (e) {
736 736 that.view();
737 737 });
738 738 },
739 739
740 740 edit: function (event) {
741 741 this.viewFields.hide();
742 742 this.editButton.hide();
743 743 this.deleteButton.hide();
744 744 this.closeButton.show();
745 745 this.editFields.show();
746 746 codeMirrorInstance.refresh();
747 747 },
748 748
749 749 view: function (event) {
750 750 this.editButton.show();
751 751 this.deleteButton.show();
752 752 this.editFields.hide();
753 753 this.closeButton.hide();
754 754 this.viewFields.show();
755 755 }
756 756 };
757 757
758 758 var ReviewersPanel = {
759 759 editButton: $('#open_edit_reviewers'),
760 760 closeButton: $('#close_edit_reviewers'),
761 761 addButton: $('#add_reviewer'),
762 762 removeButtons: $('.reviewer_member_remove,.reviewer_member_mandatory_remove'),
763 763
764 764 init: function () {
765 765 var self = this;
766 766 this.editButton.on('click', function (e) {
767 767 self.edit();
768 768 });
769 769 this.closeButton.on('click', function (e) {
770 770 self.close();
771 771 });
772 772 },
773 773
774 774 edit: function (event) {
775 775 this.editButton.hide();
776 776 this.closeButton.show();
777 777 this.addButton.show();
778 778 this.removeButtons.css('visibility', 'visible');
779 779 // review rules
780 780 reviewersController.loadReviewRules(
781 781 ${c.pull_request.reviewer_data_json | n});
782 782 },
783 783
784 784 close: function (event) {
785 785 this.editButton.show();
786 786 this.closeButton.hide();
787 787 this.addButton.hide();
788 788 this.removeButtons.css('visibility', 'hidden');
789 789 // hide review rules
790 790 reviewersController.hideReviewRules()
791 791 }
792 792 };
793 793
794 794 PRDetails.init();
795 795 ReviewersPanel.init();
796 796
797 797 showOutdated = function (self) {
798 798 $('.comment-inline.comment-outdated').show();
799 799 $('.filediff-outdated').show();
800 800 $('.showOutdatedComments').hide();
801 801 $('.hideOutdatedComments').show();
802 802 };
803 803
804 804 hideOutdated = function (self) {
805 805 $('.comment-inline.comment-outdated').hide();
806 806 $('.filediff-outdated').hide();
807 807 $('.hideOutdatedComments').hide();
808 808 $('.showOutdatedComments').show();
809 809 };
810 810
811 811 refreshMergeChecks = function () {
812 812 var loadUrl = "${request.current_route_path(_query=dict(merge_checks=1))}";
813 813 $('.pull-request-merge').css('opacity', 0.3);
814 814 $('.action-buttons-extra').css('opacity', 0.3);
815 815
816 816 $('.pull-request-merge').load(
817 817 loadUrl, function () {
818 818 $('.pull-request-merge').css('opacity', 1);
819 819
820 820 $('.action-buttons-extra').css('opacity', 1);
821 821 }
822 822 );
823 823 };
824 824
825 825 closePullRequest = function (status) {
826 826 if (!confirm(_gettext('Are you sure to close this pull request without merging?'))) {
827 827 return false;
828 828 }
829 829 // inject closing flag
830 830 $('.action-buttons-extra').append('<input type="hidden" class="close-pr-input" id="close_pull_request" value="1">');
831 831 $(generalCommentForm.statusChange).select2("val", status).trigger('change');
832 832 $(generalCommentForm.submitForm).submit();
833 833 };
834 834
835 835 $('#show-outdated-comments').on('click', function (e) {
836 836 var button = $(this);
837 837 var outdated = $('.comment-outdated');
838 838
839 839 if (button.html() === "(Show)") {
840 840 button.html("(Hide)");
841 841 outdated.show();
842 842 } else {
843 843 button.html("(Show)");
844 844 outdated.hide();
845 845 }
846 846 });
847 847
848 848 $('.show-inline-comments').on('change', function (e) {
849 849 var show = 'none';
850 850 var target = e.currentTarget;
851 851 if (target.checked) {
852 852 show = ''
853 853 }
854 854 var boxid = $(target).attr('id_for');
855 855 var comments = $('#{0} .inline-comments'.format(boxid));
856 856 var fn_display = function (idx) {
857 857 $(this).css('display', show);
858 858 };
859 859 $(comments).each(fn_display);
860 860 var btns = $('#{0} .inline-comments-button'.format(boxid));
861 861 $(btns).each(fn_display);
862 862 });
863 863
864 864 $('#merge_pull_request_form').submit(function () {
865 865 if (!$('#merge_pull_request').attr('disabled')) {
866 866 $('#merge_pull_request').attr('disabled', 'disabled');
867 867 }
868 868 return true;
869 869 });
870 870
871 871 $('#edit_pull_request').on('click', function (e) {
872 872 var title = $('#pr-title-input').val();
873 873 var description = codeMirrorInstance.getValue();
874 874 var renderer = $('#pr-renderer-input').val();
875 875 editPullRequest(
876 876 "${c.repo_name}", "${c.pull_request.pull_request_id}",
877 877 title, description, renderer);
878 878 });
879 879
880 880 $('#update_pull_request').on('click', function (e) {
881 881 $(this).attr('disabled', 'disabled');
882 882 $(this).addClass('disabled');
883 883 $(this).html(_gettext('Saving...'));
884 884 reviewersController.updateReviewers(
885 885 "${c.repo_name}", "${c.pull_request.pull_request_id}");
886 886 });
887 887
888 888
889 889 // fixing issue with caches on firefox
890 890 $('#update_commits').removeAttr("disabled");
891 891
892 892 $('.show-inline-comments').on('click', function (e) {
893 893 var boxid = $(this).attr('data-comment-id');
894 894 var button = $(this);
895 895
896 896 if (button.hasClass("comments-visible")) {
897 897 $('#{0} .inline-comments'.format(boxid)).each(function (index) {
898 898 $(this).hide();
899 899 });
900 900 button.removeClass("comments-visible");
901 901 } else {
902 902 $('#{0} .inline-comments'.format(boxid)).each(function (index) {
903 903 $(this).show();
904 904 });
905 905 button.addClass("comments-visible");
906 906 }
907 907 });
908 908
909 909 // register submit callback on commentForm form to track TODOs
910 910 window.commentFormGlobalSubmitSuccessCallback = function () {
911 911 refreshMergeChecks();
912 912 };
913 913
914 914 ReviewerAutoComplete('#user');
915 915
916 916 })
917 917
918 918 </script>
919 919
920 920 </div>
921 921
922 922 </%def>
@@ -1,165 +1,165 b''
1 1 <%namespace name="search" file="/search/search.mako"/>
2 2
3 3 <%def name="highlight_text_file(has_matched_content, file_content, lexer, html_formatter, matching_lines, shown_matching_lines, url, use_hl_filter)">
4 4 % if has_matched_content:
5 5 ${h.code_highlight(file_content, lexer, html_formatter, use_hl_filter=use_hl_filter)|n}
6 6 % else:
7 7 ${_('No content matched')} <br/>
8 8 % endif
9 9
10 10 %if len(matching_lines) > shown_matching_lines:
11 11 <a href="${url}">
12 12 ${len(matching_lines) - shown_matching_lines} ${_('more matches in this file')}
13 13 </a>
14 14 %endif
15 15 </%def>
16 16
17 17 <div class="search-results">
18 18 <% query_mark = c.searcher.query_to_mark(c.cur_query, 'content') %>
19 19
20 20 %for entry in c.formatted_results:
21 21
22 22 <%
23 23 file_content = entry['content_highlight'] or entry['content']
24 24 mimetype = entry.get('mimetype')
25 25 filepath = entry.get('path')
26 26 max_lines = h.safe_int(request.GET.get('max_lines', '10'))
27 27 line_context = h.safe_int(request.GET.get('line_contenxt', '3'))
28 28
29 29 match_file_url=h.route_path('repo_files',repo_name=entry['repository'], commit_id=entry.get('commit_id', 'tip'),f_path=entry['f_path'], _query={"mark": query_mark})
30 30 terms = c.cur_query
31 31
32 32 if c.searcher.is_es_6:
33 33 # use empty terms so we default to markers usage
34 34 total_lines, matching_lines = h.get_matching_line_offsets(file_content, terms=None)
35 35 else:
36 36 total_lines, matching_lines = h.get_matching_line_offsets(file_content, terms)
37 37
38 38 shown_matching_lines = 0
39 39 lines_of_interest = set()
40 40 for line_number in matching_lines:
41 41 if len(lines_of_interest) < max_lines:
42 42 lines_of_interest |= set(range(
43 43 max(line_number - line_context, 0),
44 44 min(line_number + line_context, total_lines + 1)))
45 45 shown_matching_lines += 1
46 46 lexer = h.get_lexer_safe(mimetype=mimetype, filepath=filepath)
47 47
48 48 html_formatter = h.SearchContentCodeHtmlFormatter(
49 49 linenos=True,
50 50 cssclass="code-highlight",
51 51 url=match_file_url,
52 52 query_terms=terms,
53 53 only_line_numbers=lines_of_interest
54 54 )
55 55
56 56 has_matched_content = len(lines_of_interest) >= 1
57 57
58 58 %>
59 59 ## search results are additionally filtered, and this check is just a safe gate
60 60 % if c.rhodecode_user.is_admin or h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(entry['repository'], 'search results content check'):
61 61 <div class="codeblock">
62 62 <h1>
63 63 <% repo_type = entry.get('repo_type') or h.get_repo_type_by_name(entry.get('repository')) %>
64 64 ${search.repo_icon(repo_type)}
65 65 ${h.link_to(entry['repository'], h.route_path('repo_summary', repo_name=entry['repository']))}
66 66 </h1>
67 67
68 68 <div class="codeblock-header">
69 69
70 70 <div class="file-filename">
71 71 <i class="icon-file"></i> ${entry['f_path'].split('/')[-1]}
72 72 </div>
73 73
74 74 <div class="file-stats">
75 75 <div class="stats-info">
76 76 <span class="stats-first-item">
77 77 ${entry.get('lines', 0.)} ${_ungettext('line', 'lines', entry.get('lines', 0.))}
78 78 (${len(matching_lines)} ${_ungettext('matched', 'matched', len(matching_lines))})
79 79 </span>
80 80 <span>
81 81 % if entry.get('size'):
82 82 | ${h.format_byte_size_binary(entry['size'])}
83 83 % endif
84 84 </span>
85 85 <span>
86 86 % if entry.get('mimetype'):
87 87 | ${entry.get('mimetype', "unknown mimetype")}
88 88 % endif
89 89 </span>
90 90 </div>
91 91 </div>
92 92 </div>
93 93
94 94 <div class="path clear-fix">
95 95 <div class="pull-left">
96 ${h.files_breadcrumbs(entry['repository'],entry.get('commit_id', 'tip'),entry['f_path'], linkify_last_item=True)}
96 ${h.files_breadcrumbs(entry['repository'], repo_type, entry.get('commit_id', 'tip'), entry['f_path'], linkify_last_item=True)}
97 97 </div>
98 98
99 99 <div class="pull-right stats">
100 100 ## <a id="file_history_overview_full" href="${h.route_path('repo_commits_file',repo_name=entry.get('repository',''),commit_id=entry.get('commit_id', 'tip'),f_path=entry.get('f_path',''))}">
101 101 ## ${_('Show Full History')}
102 102 ## </a>
103 103 ## | ${h.link_to(_('Annotation'), h.route_path('repo_files:annotated', repo_name=entry.get('repository',''),commit_id=entry.get('commit_id', 'tip'),f_path=entry.get('f_path','')))}
104 104 ## | ${h.link_to(_('Raw'), h.route_path('repo_file_raw', repo_name=entry.get('repository',''),commit_id=entry.get('commit_id', 'tip'),f_path=entry.get('f_path','')))}
105 105 <div class="search-tags">
106 106
107 107 <% repo_group = entry.get('repository_group')%>
108 108 ## hiden if in repo group view
109 109 % if repo_group and not c.repo_group_name:
110 110 <span class="tag tag8">
111 111 ${search.repo_group_icon()}
112 112 <a href="${h.route_path('search_repo_group', repo_group_name=repo_group, _query={'q': c.cur_query})}">${_('Narrow to this repository group')}</a>
113 113 </span>
114 114 % endif
115 115 ## hiden if in repo view
116 116 % if not c.repo_name:
117 117 <span class="tag tag8">
118 118 ${search.repo_icon(repo_type)}
119 119 <a href="${h.route_path('search_repo', repo_name=entry.get('repo_name'), _query={'q': c.cur_query})}">${_('Narrow to this repository')}</a>
120 120 </span>
121 121 % endif
122 122 </div>
123 123
124 124 </div>
125 125 <div class="clear-fix"></div>
126 126 </div>
127 127
128 128
129 129 <div class="code-body search-code-body clear-fix">
130 130 ${highlight_text_file(
131 131 has_matched_content=has_matched_content,
132 132 file_content=file_content,
133 133 lexer=lexer,
134 134 html_formatter=html_formatter,
135 135 matching_lines=matching_lines,
136 136 shown_matching_lines=shown_matching_lines,
137 137 url=match_file_url,
138 138 use_hl_filter=c.searcher.is_es_6
139 139 )}
140 140 </div>
141 141
142 142 </div>
143 143 % endif
144 144 %endfor
145 145 </div>
146 146 %if c.cur_query and c.formatted_results:
147 147 <div class="pagination-wh pagination-left" >
148 148 ${c.formatted_results.render()}
149 149 </div>
150 150 %endif
151 151
152 152 %if c.cur_query:
153 153 <script type="text/javascript">
154 154 $(function(){
155 155 $(".search-code-body").mark(
156 156 "${query_mark}",
157 157 {
158 158 "className": 'match',
159 159 "accuracy": "complementary",
160 160 "ignorePunctuation": ":._(){}[]!'+=".split("")
161 161 }
162 162 );
163 163 })
164 164 </script>
165 165 %endif
@@ -1,53 +1,53 b''
1 1 <%namespace name="search" file="/search/search.mako"/>
2 2
3 3 % if c.formatted_results:
4 4
5 5 <table class="rctable search-results">
6 6 <tr>
7 7 <th>${_('Repository')}</th>
8 8 <th>
9 9 <a href="${search.field_sort('file')}">${_('File')}</a>
10 10 </th>
11 11 <th>
12 12 <a href="${search.field_sort('size')}">${_('Size')}</a>
13 13 </th>
14 14 <th>
15 15 <a href="${search.field_sort('lines')}">${_('Lines')}</a>
16 16 </th>
17 17 </tr>
18 18 %for entry in c.formatted_results:
19 19 ## search results are additionally filtered, and this check is just a safe gate
20 20 % if c.rhodecode_user.is_admin or h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(entry['repository'], 'search results path check'):
21 21 <tr class="body">
22 22 <td class="td-componentname">
23 23 <% repo_type = entry.get('repo_type') or h.get_repo_type_by_name(entry.get('repository')) %>
24 24 ${search.repo_icon(repo_type)}
25 25 ${h.link_to(entry['repository'], h.route_path('repo_summary',repo_name=entry['repository']))}
26 26 </td>
27 27 <td class="td-componentname">
28 28 <i class="icon-file"></i>
29 29 ${h.link_to(h.literal(entry['f_path']),
30 h.route_path('repo_files',repo_name=entry['repository'],commit_id='tip',f_path=entry['f_path']))}
30 h.route_path('repo_files',repo_name=entry['repository'],commit_id=entry.get('commit_id', 'tip'),f_path=entry['f_path']))}
31 31 </td>
32 32 <td>
33 33 %if entry.get('size'):
34 34 ${h.format_byte_size_binary(entry['size'])}
35 35 %endif
36 36 </td>
37 37 <td>
38 38 %if entry.get('lines'):
39 39 ${entry.get('lines', 0.)}
40 40 %endif
41 41 </td>
42 42 </tr>
43 43 % endif
44 44 %endfor
45 45 </table>
46 46
47 47 %if c.cur_query:
48 48 <div class="pagination-wh pagination-left">
49 49 ${c.formatted_results.render()}
50 50 </div>
51 51 %endif
52 52
53 53 % endif
@@ -1,118 +1,118 b''
1 1 <%inherit file="/summary/summary_base.mako"/>
2 2
3 3 <%namespace name="components" file="/summary/components.mako"/>
4 4
5 5
6 6 <%def name="menu_bar_subnav()">
7 7 ${self.repo_menu(active='summary')}
8 8 </%def>
9 9
10 10 <%def name="main()">
11 11
12 12 <div id="repo-summary" class="summary">
13 13 ${components.summary_detail(breadcrumbs_links=self.breadcrumbs_links(), show_downloads=True)}
14 14 </div><!--end repo-summary-->
15 15
16 16
17 17 <div class="box">
18 18 %if not c.repo_commits:
19 19 <div class="empty-repo">
20 20 <div class="title">
21 21 <h3>${_('Quick start')}</h3>
22 22 </div>
23 23 <div class="clear-fix"></div>
24 24 </div>
25 25 %endif
26 26 <div class="table">
27 27 <div id="shortlog_data">
28 28 <%include file='summary_commits.mako'/>
29 29 </div>
30 30 </div>
31 31 </div>
32 32
33 33 %if c.readme_data:
34 34 <div id="readme" class="anchor">
35 35 <div class="box">
36 36
37 <div class="readme-title" title="${h.tooltip(_('Readme file from commit %s:%s') % (c.rhodecode_db_repo.landing_rev[0], c.rhodecode_db_repo.landing_rev[1]))}">
37 <div class="readme-title" title="${h.tooltip(_('Readme file from commit %s:%s') % (c.rhodecode_db_repo.landing_ref_type, c.rhodecode_db_repo.landing_ref_name))}">
38 38 <div>
39 39 <i class="icon-file-text"></i>
40 <a href="${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.rhodecode_db_repo.landing_rev[1],f_path=c.readme_file)}">
40 <a href="${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.rhodecode_db_repo.landing_ref_name,f_path=c.readme_file)}">
41 41 ${c.readme_file}
42 42 </a>
43 43 </div>
44 44 </div>
45 45 <div class="readme codeblock">
46 46 <div class="readme_box">
47 47 ${c.readme_data|n}
48 48 </div>
49 49 </div>
50 50 </div>
51 51 </div>
52 52 %endif
53 53
54 54 <script type="text/javascript">
55 55 $(document).ready(function(){
56 56
57 57 var showCloneField = function(clone_url_format){
58 58 $.each(['http', 'http_id', 'ssh'], function (idx, val) {
59 59 if(val === clone_url_format){
60 60 $('#clone_option_' + val).show();
61 61 $('#clone_option').val(val)
62 62 } else {
63 63 $('#clone_option_' + val).hide();
64 64 }
65 65 });
66 66 };
67 67 // default taken from session
68 68 showCloneField(templateContext.session_attrs.clone_url_format);
69 69
70 70 $('#clone_option').on('change', function(e) {
71 71 var selected = $(this).val();
72 72
73 73 storeUserSessionAttr('rc_user_session_attr.clone_url_format', selected);
74 74 showCloneField(selected)
75 75 });
76 76
77 77 var initialCommitData = {
78 78 id: null,
79 79 text: 'tip',
80 80 type: 'tag',
81 81 raw_id: null,
82 82 files_url: null
83 83 };
84 84
85 85 select2RefSwitcher('#download_options', initialCommitData);
86 86
87 87 // on change of download options
88 88 $('#download_options').on('change', function(e) {
89 89 // format of Object {text: "v0.0.3", type: "tag", id: "rev"}
90 90 var ext = '.zip';
91 91 var selected_cs = e.added;
92 92 var fname = e.added.raw_id + ext;
93 93 var href = pyroutes.url('repo_archivefile', {'repo_name': templateContext.repo_name, 'fname':fname});
94 94 // set new label
95 95 $('#archive_link').html('{0}{1}'.format(escapeHtml(e.added.text), ext));
96 96
97 97 // set new url to button,
98 98 $('#archive_link').attr('href', href)
99 99 });
100 100
101 101
102 102 // calculate size of repository
103 103 calculateSize = function () {
104 104
105 105 var callback = function (data) {
106 106 % if c.show_stats:
107 107 showRepoStats('lang_stats', data);
108 108 % endif
109 109 };
110 110
111 111 showRepoSize('repo_size_container', templateContext.repo_name, templateContext.repo_landing_commit, callback);
112 112
113 113 }
114 114
115 115 })
116 116 </script>
117 117
118 118 </%def>
@@ -1,242 +1,241 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
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 21 import copy
22 22 import mock
23 23 import pytest
24 24
25 25 from rhodecode.lib import helpers
26 26 from rhodecode.lib.utils2 import AttributeDict
27 27 from rhodecode.model.settings import IssueTrackerSettingsModel
28 28 from rhodecode.tests import no_newline_id_generator
29 29
30 30
31 31 @pytest.mark.parametrize('url, expected_url', [
32 32 ('http://rc.com', '<a href="http://rc.com">http://rc.com</a>'),
33 33 ('http://rc.com/test', '<a href="http://rc.com/test">http://rc.com/test</a>'),
34 34 ('http://rc.com/!foo', '<a href="http://rc.com/!foo">http://rc.com/!foo</a>'),
35 35 ('http://rc.com/&foo', '<a href="http://rc.com/&amp;foo">http://rc.com/&amp;foo</a>'),
36 36 ('http://rc.com/?foo-1&bar=1', '<a href="http://rc.com/?foo-1&amp;bar=1">http://rc.com/?foo-1&amp;bar=1</a>'),
37 37 ('http://rc.com?foo-1&bar=1', '<a href="http://rc.com?foo-1&amp;bar=1">http://rc.com?foo-1&amp;bar=1</a>'),
38 38 ('http://rc.com/#foo', '<a href="http://rc.com/#foo">http://rc.com/#foo</a>'),
39 39 ('http://rc.com/@foo', '<a href="http://rc.com/@foo">http://rc.com/@foo</a>'),
40 40 ])
41 41 def test_urlify_text(url, expected_url):
42 42 assert helpers.urlify_text(url) == expected_url
43 43
44 44
45 45 @pytest.mark.parametrize('repo_name, commit_id, path, expected_result', [
46 46 # Simple case 1
47 47 ('repo', 'commit', 'a/b',
48 48 '<a href="/repo/files/commit/"><i class="icon-home"></i></a>'
49 49 ' / '
50 50 '<a href="/repo/files/commit/a">a</a>'
51 51 ' / '
52 52 'b'),
53 53
54 54 # Simple case
55 55 ('rX<X', 'cX<X', 'pX<X/aX<X/bX<X',
56 56 '<a href="/rX%3CX/files/cX%3CX/"><i class="icon-home"></i></a>'
57 57 ' / '
58 58 '<a href="/rX%3CX/files/cX%3CX/pX%3CX">pX&lt;X</a>'
59 59 ' / '
60 60 '<a href="/rX%3CX/files/cX%3CX/pX%3CX/aX%3CX">aX&lt;X</a>'
61 61 ' / '
62 62 'bX&lt;X'),
63 63
64 64 # Path with only one segment
65 65 ('rX<X', 'cX<X', 'pX<X',
66 66 '<a href="/rX%3CX/files/cX%3CX/"><i class="icon-home"></i></a>'
67 67 ' / '
68 68 'pX&lt;X'),
69 69
70 70 # Empty path
71 71 ('rX<X', 'cX<X', '',
72 72 '<i class="icon-home"></i>'),
73 73
74 74 # simple quote
75 75 ('rX"X', 'cX"X', 'pX"X/aX"X/bX"X',
76 76 '<a href="/rX%22X/files/cX%22X/"><i class="icon-home"></i></a>'
77 77 ' / '
78 78 '<a href="/rX%22X/files/cX%22X/pX%22X">pX&#34;X</a>'
79 79 ' / '
80 80 '<a href="/rX%22X/files/cX%22X/pX%22X/aX%22X">aX&#34;X</a>'
81 81 ' / '
82 82 'bX&#34;X'),
83 83
84 84 ], ids=['simple1', 'simple2', 'one_segment', 'empty_path', 'simple_quote'])
85 def test_files_breadcrumbs_xss(
86 repo_name, commit_id, path, app, expected_result):
87 result = helpers.files_breadcrumbs(repo_name, commit_id, path)
85 def test_files_breadcrumbs_xss(repo_name, commit_id, path, app, expected_result):
86 result = helpers.files_breadcrumbs(repo_name, 'hg', commit_id, path)
88 87 # Expect it to encode all path fragments properly. This is important
89 88 # because it returns an instance of `literal`.
90 89 if path != '':
91 90 expected_result = expected_result + helpers.files_icon.format(helpers.escape(path))
92 91 assert result == expected_result
93 92
94 93
95 94 def test_format_binary():
96 95 assert helpers.format_byte_size_binary(298489462784) == '278.0 GiB'
97 96
98 97
99 98 @pytest.mark.parametrize('text_string, pattern, expected', [
100 99 ('No issue here', '(?:#)(?P<issue_id>\d+)', []),
101 100 ('Fix #42', '(?:#)(?P<issue_id>\d+)',
102 101 [{'url': 'http://r.io/{repo}/i/42', 'id': '42'}]),
103 102 ('Fix #42, #53', '(?:#)(?P<issue_id>\d+)', [
104 103 {'url': 'http://r.io/{repo}/i/42', 'id': '42'},
105 104 {'url': 'http://r.io/{repo}/i/53', 'id': '53'}]),
106 105 ('Fix #42', '(?:#)?<issue_id>\d+)', []), # Broken regex
107 106 ])
108 107 def test_extract_issues(backend, text_string, pattern, expected):
109 108 repo = backend.create_repo()
110 109 config = {
111 110 '123': {
112 111 'uid': '123',
113 112 'pat': pattern,
114 113 'url': 'http://r.io/${repo}/i/${issue_id}',
115 114 'pref': '#',
116 115 'desc': 'Test Pattern'
117 116 }
118 117 }
119 118
120 119 def get_settings_mock(self, cache=True):
121 120 return config
122 121
123 122 with mock.patch.object(IssueTrackerSettingsModel,
124 123 'get_settings', get_settings_mock):
125 124 text, issues = helpers.process_patterns(text_string, repo.repo_name)
126 125
127 126 expected = copy.deepcopy(expected)
128 127 for item in expected:
129 128 item['url'] = item['url'].format(repo=repo.repo_name)
130 129
131 130 assert issues == expected
132 131
133 132
134 133 @pytest.mark.parametrize('text_string, pattern, link_format, expected_text', [
135 134 ('Fix #42', '(?:#)(?P<issue_id>\d+)', 'html',
136 135 'Fix <a class="tooltip issue-tracker-link" href="http://r.io/{repo}/i/42" title="Test Pattern">#42</a>'),
137 136
138 137 ('Fix #42', '(?:#)(?P<issue_id>\d+)', 'markdown',
139 138 'Fix [#42](http://r.io/{repo}/i/42)'),
140 139
141 140 ('Fix #42', '(?:#)(?P<issue_id>\d+)', 'rst',
142 141 'Fix `#42 <http://r.io/{repo}/i/42>`_'),
143 142
144 143 ('Fix #42', '(?:#)?<issue_id>\d+)', 'html',
145 144 'Fix #42'), # Broken regex
146 145 ])
147 146 def test_process_patterns_repo(backend, text_string, pattern, expected_text, link_format):
148 147 repo = backend.create_repo()
149 148
150 149 def get_settings_mock(self, cache=True):
151 150 return {
152 151 '123': {
153 152 'uid': '123',
154 153 'pat': pattern,
155 154 'url': 'http://r.io/${repo}/i/${issue_id}',
156 155 'pref': '#',
157 156 'desc': 'Test Pattern'
158 157 }
159 158 }
160 159
161 160 with mock.patch.object(IssueTrackerSettingsModel,
162 161 'get_settings', get_settings_mock):
163 162 processed_text, issues = helpers.process_patterns(
164 163 text_string, repo.repo_name, link_format)
165 164
166 165 assert processed_text == expected_text.format(repo=repo.repo_name)
167 166
168 167
169 168 @pytest.mark.parametrize('text_string, pattern, expected_text', [
170 169 ('Fix #42', '(?:#)(?P<issue_id>\d+)',
171 170 'Fix <a class="tooltip issue-tracker-link" href="http://r.io/i/42" title="Test Pattern">#42</a>'),
172 171 ('Fix #42', '(?:#)?<issue_id>\d+)',
173 172 'Fix #42'), # Broken regex
174 173 ])
175 174 def test_process_patterns_no_repo(text_string, pattern, expected_text):
176 175
177 176 def get_settings_mock(self, cache=True):
178 177 return {
179 178 '123': {
180 179 'uid': '123',
181 180 'pat': pattern,
182 181 'url': 'http://r.io/i/${issue_id}',
183 182 'pref': '#',
184 183 'desc': 'Test Pattern'
185 184 }
186 185 }
187 186
188 187 with mock.patch.object(IssueTrackerSettingsModel,
189 188 'get_global_settings', get_settings_mock):
190 189 processed_text, issues = helpers.process_patterns(
191 190 text_string, '')
192 191
193 192 assert processed_text == expected_text
194 193
195 194
196 195 def test_process_patterns_non_existent_repo_name(backend):
197 196 text_string = 'Fix #42'
198 197 pattern = '(?:#)(?P<issue_id>\d+)'
199 198 expected_text = ('Fix <a class="tooltip issue-tracker-link" '
200 199 'href="http://r.io/do-not-exist/i/42" title="Test Pattern">#42</a>')
201 200
202 201 def get_settings_mock(self, cache=True):
203 202 return {
204 203 '123': {
205 204 'uid': '123',
206 205 'pat': pattern,
207 206 'url': 'http://r.io/${repo}/i/${issue_id}',
208 207 'pref': '#',
209 208 'desc': 'Test Pattern'
210 209 }
211 210 }
212 211
213 212 with mock.patch.object(IssueTrackerSettingsModel,
214 213 'get_global_settings', get_settings_mock):
215 214 processed_text, issues = helpers.process_patterns(
216 215 text_string, 'do-not-exist')
217 216
218 217 assert processed_text == expected_text
219 218
220 219
221 220 def test_get_visual_attr(baseapp):
222 221 from rhodecode.apps._base import TemplateArgs
223 222 c = TemplateArgs()
224 223 assert None is helpers.get_visual_attr(c, 'fakse')
225 224
226 225 # emulate the c.visual behaviour
227 226 c.visual = AttributeDict({})
228 227 assert None is helpers.get_visual_attr(c, 'some_var')
229 228
230 229 c.visual.some_var = 'foobar'
231 230 assert 'foobar' == helpers.get_visual_attr(c, 'some_var')
232 231
233 232
234 233 @pytest.mark.parametrize('test_text, inclusive, expected_text', [
235 234 ('just a string', False, 'just a string'),
236 235 ('just a string\n', False, 'just a string'),
237 236 ('just a string\n next line', False, 'just a string...'),
238 237 ('just a string\n next line', True, 'just a string\n...'),
239 238 ], ids=no_newline_id_generator)
240 239 def test_chop_at(test_text, inclusive, expected_text):
241 240 assert helpers.chop_at_smart(
242 241 test_text, '\n', inclusive, '...') == expected_text
General Comments 0
You need to be logged in to leave comments. Login now