release: merge back stable branch into default
This commit is contained in:
commit
54de45c2dd
125 changed files with 3361 additions and 2113 deletions
|
|
@ -57,5 +57,5 @@ Each lines should represent a single name e.g `repo_name_1` or `repo_group/repo_
|
|||
Run this line from CLI to execute the code from the `repo_delete_task.py` file and
|
||||
exit the ishell after the execution::
|
||||
|
||||
echo "%run repo_delete_task.py" | rccontrol ishell Enterprise-1
|
||||
echo "%run repo_delete_task.py" | rccontrol ishell enterprise-1
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ permission issues could occur. To do this edit the ``/etc/apache2/envvars``
|
|||
LogLevel info
|
||||
# allows custom host names, prevents 400 errors on checkout
|
||||
HttpProtocolOptions Unsafe
|
||||
# Most likely this will be: /home/user/.rccontrol/enterprise-1/mod_dav_svn.conf
|
||||
Include /home/user/.rccontrol/enterprise-1/mod_dav_svn.conf
|
||||
</VirtualHost>
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ uses, or if required it can be a different one. We recommend to use the same dat
|
|||
|
||||
|
||||
|
||||
To switch to reds-based user sessions uncomment the following section in
|
||||
To switch to redis-based user sessions uncomment the following section in
|
||||
your :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file.
|
||||
|
||||
.. code-block:: ini
|
||||
|
|
|
|||
|
|
@ -33,6 +33,15 @@ To get |RCE| up and running, run through the below steps:
|
|||
Do you accept the RhodeCode Control license?
|
||||
Press [Y] to accept license and [V] to view license text: y
|
||||
|
||||
|
||||
.. important::
|
||||
|
||||
We recommend running RhodeCode as a non-root user, such as `rhodecode`;
|
||||
this user must have a proper home directory.
|
||||
Either log in as that user to install the software, or do it as root
|
||||
with `sudo -i -u rhodecode ./RhodeCode-installer-linux-*`
|
||||
|
||||
|
||||
3. Install a VCS Server, and configure it to start at boot.
|
||||
|
||||
.. code-block:: bash
|
||||
|
|
|
|||
|
|
@ -193,6 +193,10 @@ Fixes
|
|||
Upgrade notes
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
- Major Celery Version upgrade. The 4.18.X release includes a major Celery version.
|
||||
It's recommended to run `rccontrol self-stop && rccontrol self-init` after the
|
||||
upgrade to ensure celery workers are restarted and updated.
|
||||
|
||||
- New Automation task. We've changed the logic for updating latest change inside repository group.
|
||||
New logic includes scanning for changes in all nested objects. Since this is a heavy task
|
||||
a new dedicated scheduler task has been created to update it automatically on a scheduled base.
|
||||
|
|
@ -218,6 +222,11 @@ Upgrade notes
|
|||
Please review vcsserver.ini settings under:
|
||||
`rc_cache.repo_object.backend = dogpile.cache.rc.redis_msgpack`
|
||||
|
||||
- Gunicorn configuration now moved to .ini files.
|
||||
Upgrading to 4.18.X will overwrite the gunicorn_conf.py file. If there are any custom changes in that file
|
||||
they will be lost. Recommended way to configure gunicorn is now via the .ini files. Please check `rhodecode.template.ini` file
|
||||
for example gunicorn configuration.
|
||||
|
||||
- New memory monitoring for Gunicorn workers. Starting from 4.18 release a option was added
|
||||
to limit the maximum amount of memory used by a worker.
|
||||
Please review new settings in `[server:main]` section for memory management in both
|
||||
|
|
|
|||
60
docs/release-notes/release-notes-4.18.1.rst
Normal file
60
docs/release-notes/release-notes-4.18.1.rst
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
|RCE| 4.18.1 |RNS|
|
||||
------------------
|
||||
|
||||
Release Date
|
||||
^^^^^^^^^^^^
|
||||
|
||||
- 2020-01-20
|
||||
|
||||
|
||||
New Features
|
||||
^^^^^^^^^^^^
|
||||
|
||||
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
|
||||
- API: invalidate license cache on set_license_key call.
|
||||
- API: add send_email flag for comments api to allow commenting without email notification.
|
||||
- API: added pull requests versions into returned API data.
|
||||
- Dashboard: fixed jumping of text in grid loading by new loading indicator.
|
||||
- Installation: add few extra defaults that makes RhodeCode nicer out of the box.
|
||||
- Pull Requests: small code cleanup to define other type of merge username.
|
||||
RC_MERGE_USER_NAME_ATTR env variable defines what should be used from user as merge username.
|
||||
- Gists: cleanup UI and make the gist access id use monospace according to the new UI.
|
||||
|
||||
|
||||
Security
|
||||
^^^^^^^^
|
||||
|
||||
- Repository permission: properly flush permission caches on set private mode of repository.
|
||||
Otherwise we get cached values still in place until it expires.
|
||||
- Repository permission: add set/un-set of private repository from permissions page.
|
||||
- Permissions: flush all user permissions in case of default user permission changes.
|
||||
|
||||
|
||||
Performance
|
||||
^^^^^^^^^^^
|
||||
|
||||
- Caches: used more efficient way of fetching all users for permissions invalidation.
|
||||
- Issue trackers: optimized performance of fetching issue tracker patterns.
|
||||
|
||||
|
||||
Fixes
|
||||
^^^^^
|
||||
|
||||
- SSH: fixed SSH problems with EE edition.
|
||||
- Branch permissions: remove emtpy tooltips on branch permission entries.
|
||||
- Core: fixed cython compat inspect that caused some API calls to not work correctly in EE release.
|
||||
- Audit logger: use copy of params we later modify to prevent from modification by the store
|
||||
function of parameters that we only use for reading.
|
||||
- Users: fixed wrong mention of readme in user description help block.
|
||||
- Issue trackers: fixed wrong examples in patterns.
|
||||
- Issue trackers: fixed missing option to get back to inherited settings.
|
||||
|
||||
|
||||
Upgrade notes
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
- Scheduled release addressing problems in 4.18.X releases.
|
||||
49
docs/release-notes/release-notes-4.18.2.rst
Normal file
49
docs/release-notes/release-notes-4.18.2.rst
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
|RCE| 4.18.2 |RNS|
|
||||
------------------
|
||||
|
||||
Release Date
|
||||
^^^^^^^^^^^^
|
||||
|
||||
- 2020-01-28
|
||||
|
||||
|
||||
New Features
|
||||
^^^^^^^^^^^^
|
||||
|
||||
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
|
||||
- Permissions: add better help text about default permissions, and correlation with anonymous access enabled.
|
||||
- Mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user.
|
||||
- Documentation: added note about hard restart due to celery update.
|
||||
- Maintenance: run rebuildfncache for Mercurial in maintenance command.
|
||||
|
||||
|
||||
Security
|
||||
^^^^^^^^
|
||||
|
||||
|
||||
|
||||
Performance
|
||||
^^^^^^^^^^^
|
||||
|
||||
- Authentication: cache plugins for auth and their settings in the auth_registry for single request.
|
||||
This heavily influences SVN performance on multiple-file commits.
|
||||
|
||||
|
||||
Fixes
|
||||
^^^^^
|
||||
|
||||
- Descriptions: fixed rendering problem with certain meta-tags in repo description.
|
||||
- Emails: fixed fonts rendering problems in Outlook.
|
||||
- Emails: fixed bug in test email sending.
|
||||
- Summary: fixed styling of readme indicator.
|
||||
- Flash: fixed display problem with flash messages on error pages.
|
||||
|
||||
|
||||
Upgrade notes
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
- Scheduled release addressing problems in 4.18.X releases.
|
||||
64
docs/release-notes/release-notes-4.18.3.rst
Normal file
64
docs/release-notes/release-notes-4.18.3.rst
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
|RCE| 4.18.3 |RNS|
|
||||
------------------
|
||||
|
||||
Release Date
|
||||
^^^^^^^^^^^^
|
||||
|
||||
- 2020-03-24
|
||||
|
||||
|
||||
New Features
|
||||
^^^^^^^^^^^^
|
||||
|
||||
- LDAP: added nested user groups sync which was planned in 4.18.X but didn't
|
||||
make it to the release. New option for sync is available in the LDAP configuration.
|
||||
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
|
||||
- API: added branch permissions functions.
|
||||
- Pull requests: added creating indicator to let users know they should wait until PR is creating.
|
||||
- Pull requests: allow super-admins to force change state of locked PRs.
|
||||
- Users/User groups: in edit mode we now show the actual name of what we're editing.
|
||||
- SSH: allow generation of legacy SSH keys for older systems and Windows users.
|
||||
- File store: don't response with cookie data on file-store download response.
|
||||
- File store: use our own logic for setting content-type. This solves a problem
|
||||
when previously used resolver set different content-type+content-encoding which
|
||||
is an incorrect behaviour.
|
||||
- My Account: show info about password usage for external accounts e.g github/google etc
|
||||
We now recommend using auth-tokens instead of actual passwords.
|
||||
- Repositories: in description field we now show mention of metatags only if they
|
||||
are enabled.
|
||||
|
||||
|
||||
Security
|
||||
^^^^^^^^
|
||||
|
||||
- Remote sync: don't expose credentials in displayed URLs.
|
||||
Remote links url had visible credentials displayed in the link.
|
||||
This was used for web-view and not needed anymore.
|
||||
|
||||
|
||||
Performance
|
||||
^^^^^^^^^^^
|
||||
|
||||
- Full text search: significantly improved GIT commit indexing performance by reducing
|
||||
number of calls to the vcsserver.
|
||||
|
||||
|
||||
Fixes
|
||||
^^^^^
|
||||
|
||||
- Mercurial: fixed cases of lookup of branches that are exactly 20 character long.
|
||||
- SVN: allow legacy (pre SVN 1.7) extraction of post commit data.
|
||||
- GIT: use non-unicode author extraction as it's returned as bytes from backend, and
|
||||
we can get an unicode errors while there's some non-ascii characters.
|
||||
- GIT: use safe configparser for git submodules to prevent from errors on submodules with % sign.
|
||||
- System info: fixed UI problem with new version update info screen.
|
||||
|
||||
|
||||
Upgrade notes
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
- Scheduled release addressing problems in 4.18.X releases.
|
||||
|
|
@ -9,6 +9,9 @@ Release Notes
|
|||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
release-notes-4.18.3.rst
|
||||
release-notes-4.18.2.rst
|
||||
release-notes-4.18.1.rst
|
||||
release-notes-4.18.0.rst
|
||||
release-notes-4.17.4.rst
|
||||
release-notes-4.17.3.rst
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import inspect
|
||||
import itertools
|
||||
import logging
|
||||
import sys
|
||||
|
|
@ -186,10 +185,12 @@ def request_view(request):
|
|||
Main request handling method. It handles all logic to call a specific
|
||||
exposed method
|
||||
"""
|
||||
# cython compatible inspect
|
||||
from rhodecode.config.patches import inspect_getargspec
|
||||
inspect = inspect_getargspec()
|
||||
|
||||
# check if we can find this session using api_key, get_by_auth_token
|
||||
# search not expired tokens only
|
||||
|
||||
try:
|
||||
api_user = User.get_by_auth_token(request.rpc_api_key)
|
||||
|
||||
|
|
|
|||
|
|
@ -56,5 +56,6 @@ class TestGetMethod(object):
|
|||
'request': '<RequiredType>',
|
||||
'resolves_comment_id': '<Optional:None>',
|
||||
'status': '<Optional:None>',
|
||||
'userid': '<Optional:<OptionalAttr:apiuser>>'}]
|
||||
'userid': '<Optional:<OptionalAttr:apiuser>>',
|
||||
'send_email': '<Optional:True>'}]
|
||||
assert_ok(id_, expected, given=response.body)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class TestGrantUserGroupPermission(object):
|
|||
perm=perm)
|
||||
response = api_call(self.app, params)
|
||||
|
||||
expected = 'permission `%s` does not exist' % (perm,)
|
||||
expected = 'permission `%s` does not exist.' % (perm,)
|
||||
assert_error(id_, expected, given=response.body)
|
||||
|
||||
@mock.patch.object(RepoModel, 'grant_user_group_permission', crash)
|
||||
|
|
|
|||
|
|
@ -132,8 +132,7 @@ class TestGrantUserGroupPermissionFromRepoGroup(object):
|
|||
RepoGroupModel().revoke_user_group_permission(
|
||||
repo_group.group_id, user_group.users_group_id)
|
||||
else:
|
||||
expected = 'repository group `%s` does not exist' % (
|
||||
repo_group.name,)
|
||||
expected = 'repository group `%s` does not exist' % (repo_group.name,)
|
||||
assert_error(id_, expected, given=response.body)
|
||||
|
||||
def test_api_grant_user_group_permission_to_repo_group_wrong_permission(
|
||||
|
|
@ -149,7 +148,7 @@ class TestGrantUserGroupPermissionFromRepoGroup(object):
|
|||
perm=perm)
|
||||
response = api_call(self.app, params)
|
||||
|
||||
expected = 'permission `%s` does not exist' % (perm,)
|
||||
expected = 'permission `%s` does not exist. Permission should start with prefix: `group.`' % (perm,)
|
||||
assert_error(id_, expected, given=response.body)
|
||||
|
||||
@mock.patch.object(RepoGroupModel, 'grant_user_group_permission', crash)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class TestGrantUserPermission(object):
|
|||
perm=perm)
|
||||
response = api_call(self.app, params)
|
||||
|
||||
expected = 'permission `%s` does not exist' % (perm,)
|
||||
expected = 'permission `%s` does not exist.' % (perm,)
|
||||
assert_error(id_, expected, given=response.body)
|
||||
|
||||
@mock.patch.object(RepoModel, 'grant_user_permission', crash)
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ class TestGrantUserPermissionFromRepoGroup(object):
|
|||
perm=perm)
|
||||
response = api_call(self.app, params)
|
||||
|
||||
expected = 'permission `%s` does not exist' % (perm,)
|
||||
expected = 'permission `%s` does not exist. Permission should start with prefix: `group.`' % (perm,)
|
||||
assert_error(id_, expected, given=response.body)
|
||||
|
||||
@mock.patch.object(RepoGroupModel, 'grant_user_permission', crash)
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ class TestGrantUserPermissionFromUserGroup(object):
|
|||
perm=perm)
|
||||
response = api_call(self.app, params)
|
||||
|
||||
expected = 'permission `%s` does not exist' % perm
|
||||
expected = 'permission `%s` does not exist. Permission should start with prefix: `usergroup.`' % perm
|
||||
assert_error(id_, expected, given=response.body)
|
||||
|
||||
def test_api_grant_user_permission_to_user_group_exception_when_adding(
|
||||
|
|
|
|||
|
|
@ -308,7 +308,11 @@ def get_perm_or_error(permid, prefix=None):
|
|||
|
||||
perm = PermissionModel.cls.get_by_key(permid)
|
||||
if perm is None:
|
||||
raise JSONRPCError('permission `%s` does not exist' % (permid,))
|
||||
msg = 'permission `{}` does not exist.'.format(permid)
|
||||
if prefix:
|
||||
msg += ' Permission should start with prefix: `{}`'.format(prefix)
|
||||
raise JSONRPCError(msg)
|
||||
|
||||
if prefix:
|
||||
if not perm.permission_name.startswith(prefix):
|
||||
raise JSONRPCError('permission `%s` is invalid, '
|
||||
|
|
@ -351,12 +355,12 @@ def get_pull_request_or_error(pullrequestid):
|
|||
def build_commit_data(commit, detail_level):
|
||||
parsed_diff = []
|
||||
if detail_level == 'extended':
|
||||
for f in commit.added:
|
||||
parsed_diff.append(_get_commit_dict(filename=f.path, op='A'))
|
||||
for f in commit.changed:
|
||||
parsed_diff.append(_get_commit_dict(filename=f.path, op='M'))
|
||||
for f in commit.removed:
|
||||
parsed_diff.append(_get_commit_dict(filename=f.path, op='D'))
|
||||
for f_path in commit.added_paths:
|
||||
parsed_diff.append(_get_commit_dict(filename=f_path, op='A'))
|
||||
for f_path in commit.changed_paths:
|
||||
parsed_diff.append(_get_commit_dict(filename=f_path, op='M'))
|
||||
for f_path in commit.removed_paths:
|
||||
parsed_diff.append(_get_commit_dict(filename=f_path, op='D'))
|
||||
|
||||
elif detail_level == 'full':
|
||||
from rhodecode.lib.diffs import DiffProcessor
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ def get_pull_request(request, apiuser, pullrequestid, repoid=Optional(None),
|
|||
"status" : "<status>",
|
||||
"created_on": "<date_time_created>",
|
||||
"updated_on": "<date_time_updated>",
|
||||
"versions": "<number_or_versions_of_pr>",
|
||||
"commit_ids": [
|
||||
...
|
||||
"<commit_id>",
|
||||
|
|
@ -452,7 +453,7 @@ def comment_pull_request(
|
|||
message=Optional(None), commit_id=Optional(None), status=Optional(None),
|
||||
comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
|
||||
resolves_comment_id=Optional(None), extra_recipients=Optional([]),
|
||||
userid=Optional(OAttr('apiuser'))):
|
||||
userid=Optional(OAttr('apiuser')), send_email=Optional(True)):
|
||||
"""
|
||||
Comment on the pull request specified with the `pullrequestid`,
|
||||
in the |repo| specified by the `repoid`, and optionally change the
|
||||
|
|
@ -483,6 +484,8 @@ def comment_pull_request(
|
|||
:type extra_recipients: Optional(list)
|
||||
:param userid: Comment on the pull request as this user
|
||||
:type userid: Optional(str or int)
|
||||
:param send_email: Define if this comment should also send email notification
|
||||
:type send_email: Optional(bool)
|
||||
|
||||
Example output:
|
||||
|
||||
|
|
@ -527,6 +530,7 @@ def comment_pull_request(
|
|||
comment_type = Optional.extract(comment_type)
|
||||
resolves_comment_id = Optional.extract(resolves_comment_id)
|
||||
extra_recipients = Optional.extract(extra_recipients)
|
||||
send_email = Optional.extract(send_email, binary=True)
|
||||
|
||||
if not message and not status:
|
||||
raise JSONRPCError(
|
||||
|
|
@ -587,7 +591,8 @@ def comment_pull_request(
|
|||
comment_type=comment_type,
|
||||
resolves_comment_id=resolves_comment_id,
|
||||
auth_user=auth_user,
|
||||
extra_recipients=extra_recipients
|
||||
extra_recipients=extra_recipients,
|
||||
send_email=send_email
|
||||
)
|
||||
|
||||
if allowed_to_change_status and status:
|
||||
|
|
|
|||
|
|
@ -1551,7 +1551,7 @@ def comment_commit(
|
|||
request, apiuser, repoid, commit_id, message, status=Optional(None),
|
||||
comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
|
||||
resolves_comment_id=Optional(None), extra_recipients=Optional([]),
|
||||
userid=Optional(OAttr('apiuser'))):
|
||||
userid=Optional(OAttr('apiuser')), send_email=Optional(True)):
|
||||
"""
|
||||
Set a commit comment, and optionally change the status of the commit.
|
||||
|
||||
|
|
@ -1575,6 +1575,8 @@ def comment_commit(
|
|||
:type extra_recipients: Optional(list)
|
||||
:param userid: Set the user name of the comment creator.
|
||||
:type userid: Optional(str or int)
|
||||
:param send_email: Define if this comment should also send email notification
|
||||
:type send_email: Optional(bool)
|
||||
|
||||
Example error output:
|
||||
|
||||
|
|
@ -1610,6 +1612,7 @@ def comment_commit(
|
|||
comment_type = Optional.extract(comment_type)
|
||||
resolves_comment_id = Optional.extract(resolves_comment_id)
|
||||
extra_recipients = Optional.extract(extra_recipients)
|
||||
send_email = Optional.extract(send_email, binary=True)
|
||||
|
||||
allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
|
||||
if status and status not in allowed_statuses:
|
||||
|
|
@ -1639,7 +1642,8 @@ def comment_commit(
|
|||
comment_type=comment_type,
|
||||
resolves_comment_id=resolves_comment_id,
|
||||
auth_user=apiuser,
|
||||
extra_recipients=extra_recipients
|
||||
extra_recipients=extra_recipients,
|
||||
send_email=send_email
|
||||
)
|
||||
if status:
|
||||
# also do a status change
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import inspect
|
||||
import logging
|
||||
import itertools
|
||||
import base64
|
||||
|
|
@ -334,6 +333,9 @@ def get_method(request, apiuser, pattern=Optional('*')):
|
|||
]
|
||||
error : null
|
||||
"""
|
||||
from rhodecode.config.patches import inspect_getargspec
|
||||
inspect = inspect_getargspec()
|
||||
|
||||
if not has_superadmin_permission(apiuser):
|
||||
raise JSONRPCForbidden()
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ from rhodecode.model import user_group
|
|||
from rhodecode.model import user
|
||||
from rhodecode.model.db import User
|
||||
from rhodecode.model.scm import ScmModel
|
||||
from rhodecode.model.settings import VcsSettingsModel
|
||||
from rhodecode.model.settings import VcsSettingsModel, IssueTrackerSettingsModel
|
||||
from rhodecode.model.repo import ReadmeFinder
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
@ -226,6 +226,7 @@ class RepoAppView(BaseAppView):
|
|||
self.db_repo_name = self.db_repo.repo_name
|
||||
self.db_repo_pull_requests = ScmModel().get_pull_requests(self.db_repo)
|
||||
self.db_repo_artifacts = ScmModel().get_artifacts(self.db_repo)
|
||||
self.db_repo_patterns = IssueTrackerSettingsModel(repo=self.db_repo)
|
||||
|
||||
def _handle_missing_requirements(self, error):
|
||||
log.error(
|
||||
|
|
|
|||
|
|
@ -573,7 +573,7 @@ class AdminSettingsView(BaseAppView):
|
|||
|
||||
email_kwargs = {
|
||||
'date': datetime.datetime.now(),
|
||||
'user': c.rhodecode_user
|
||||
'user': self._rhodecode_db_user
|
||||
}
|
||||
|
||||
(subject, headers, email_body,
|
||||
|
|
|
|||
|
|
@ -872,7 +872,10 @@ class UsersView(UserAppView):
|
|||
|
||||
c.active = 'ssh_keys_generate'
|
||||
comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
|
||||
c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
|
||||
private_format = self.request.GET.get('private_format') \
|
||||
or SshKeyModel.DEFAULT_PRIVATE_KEY_FORMAT
|
||||
c.private, c.public = SshKeyModel().generate_keypair(
|
||||
comment=comment, private_format=private_format)
|
||||
|
||||
return self._get_template_context(c)
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ from rhodecode.lib import audit_logger
|
|||
from rhodecode.lib.auth import (
|
||||
CSRFRequired, NotAnonymous, HasRepoPermissionAny, HasRepoGroupPermissionAny,
|
||||
LoginRequired)
|
||||
from rhodecode.lib.vcs.conf.mtypes import get_mimetypes_db
|
||||
from rhodecode.model.db import Session, FileStore, UserApiKeys
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
@ -46,6 +47,15 @@ class FileStoreView(BaseAppView):
|
|||
self.storage = utils.get_file_storage(self.request.registry.settings)
|
||||
return c
|
||||
|
||||
def _guess_type(self, file_name):
|
||||
"""
|
||||
Our own type guesser for mimetypes using the rich DB
|
||||
"""
|
||||
if not hasattr(self, 'db'):
|
||||
self.db = get_mimetypes_db()
|
||||
_content_type, _encoding = self.db.guess_type(file_name, strict=False)
|
||||
return _content_type, _encoding
|
||||
|
||||
def _serve_file(self, file_uid):
|
||||
|
||||
if not self.storage.exists(file_uid):
|
||||
|
|
@ -92,7 +102,18 @@ class FileStoreView(BaseAppView):
|
|||
FileStore.bump_access_counter(file_uid)
|
||||
|
||||
file_path = self.storage.store_path(file_uid)
|
||||
return FileResponse(file_path)
|
||||
content_type = 'application/octet-stream'
|
||||
content_encoding = None
|
||||
|
||||
_content_type, _encoding = self._guess_type(file_path)
|
||||
if _content_type:
|
||||
content_type = _content_type
|
||||
|
||||
# For file store we don't submit any session data, this logic tells the
|
||||
# Session lib to skip it
|
||||
setattr(self.request, '_file_response', True)
|
||||
return FileResponse(file_path, request=self.request,
|
||||
content_type=content_type, content_encoding=content_encoding)
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
|
|
|
|||
|
|
@ -105,11 +105,11 @@ class TestGistsController(TestController):
|
|||
g4 = create_gist('gist4', gist_type='private').gist_access_id
|
||||
response = self.app.get(route_path('gists_show'))
|
||||
|
||||
response.mustcontain('gist: %s' % g1.gist_access_id)
|
||||
response.mustcontain('gist: %s' % g2.gist_access_id)
|
||||
response.mustcontain('gist: %s' % g3.gist_access_id)
|
||||
response.mustcontain(g1.gist_access_id)
|
||||
response.mustcontain(g2.gist_access_id)
|
||||
response.mustcontain(g3.gist_access_id)
|
||||
response.mustcontain('gist3-desc')
|
||||
response.mustcontain(no=['gist: %s' % g4])
|
||||
response.mustcontain(no=[g4])
|
||||
|
||||
# Expiration information should be visible
|
||||
expires_tag = '%s' % h.age_component(
|
||||
|
|
@ -122,7 +122,7 @@ class TestGistsController(TestController):
|
|||
response = self.app.get(route_path('gists_show', params=dict(private=1)))
|
||||
|
||||
# and privates
|
||||
response.mustcontain('gist: %s' % gist.gist_access_id)
|
||||
response.mustcontain(gist.gist_access_id)
|
||||
|
||||
def test_index_show_all(self, create_gist):
|
||||
self.log_user()
|
||||
|
|
@ -136,7 +136,7 @@ class TestGistsController(TestController):
|
|||
assert len(GistModel.get_all()) == 4
|
||||
# and privates
|
||||
for gist in GistModel.get_all():
|
||||
response.mustcontain('gist: %s' % gist.gist_access_id)
|
||||
response.mustcontain(gist.gist_access_id)
|
||||
|
||||
def test_index_show_all_hidden_from_regular(self, create_gist):
|
||||
self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
|
||||
|
|
@ -150,7 +150,7 @@ class TestGistsController(TestController):
|
|||
# since we don't have access to private in this view, we
|
||||
# should see nothing
|
||||
for gist in GistModel.get_all():
|
||||
response.mustcontain(no=['gist: %s' % gist.gist_access_id])
|
||||
response.mustcontain(no=[gist.gist_access_id])
|
||||
|
||||
def test_create(self):
|
||||
self.log_user()
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ def assert_and_get_main_filter_content(result):
|
|||
if data_item['type'] == 'search':
|
||||
display_val = data_item['value_display']
|
||||
if data_item['id'] == -1:
|
||||
assert 'File search for:' in display_val, display_val
|
||||
assert 'File content search for:' in display_val, display_val
|
||||
elif data_item['id'] == -2:
|
||||
assert 'Commit search for:' in display_val, display_val
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ class HomeView(BaseAppView, DataGridAppView):
|
|||
qry = query
|
||||
return {'q': qry, 'type': 'content'}
|
||||
|
||||
label = u'File search for `{}`'.format(h.escape(query))
|
||||
label = u'File content search for `{}`'.format(h.escape(query))
|
||||
file_qry = {
|
||||
'id': -10,
|
||||
'value': query,
|
||||
|
|
@ -497,7 +497,7 @@ class HomeView(BaseAppView, DataGridAppView):
|
|||
qry = query
|
||||
return {'q': qry, 'type': 'content'}
|
||||
|
||||
label = u'File search for `{}`'.format(query)
|
||||
label = u'File content search for `{}`'.format(query)
|
||||
file_qry = {
|
||||
'id': -30,
|
||||
'value': query,
|
||||
|
|
@ -541,7 +541,7 @@ class HomeView(BaseAppView, DataGridAppView):
|
|||
{
|
||||
'id': -1,
|
||||
'value': query,
|
||||
'value_display': u'File search for: `{}`'.format(query),
|
||||
'value_display': u'File content search for: `{}`'.format(query),
|
||||
'value_icon': '<i class="icon-code"></i>',
|
||||
'type': 'search',
|
||||
'subtype': 'global',
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ def includeme(config):
|
|||
name='hovercard_user',
|
||||
pattern='/_hovercard/user/{user_id}')
|
||||
|
||||
config.add_route(
|
||||
name='hovercard_username',
|
||||
pattern='/_hovercard/username/{username}')
|
||||
|
||||
config.add_route(
|
||||
name='hovercard_user_group',
|
||||
pattern='/_hovercard/user_group/{user_group_id}')
|
||||
|
|
|
|||
|
|
@ -63,6 +63,19 @@ class HoverCardsView(BaseAppView):
|
|||
c.user = User.get_or_404(user_id)
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@view_config(
|
||||
route_name='hovercard_username', request_method='GET', xhr=True,
|
||||
renderer='rhodecode:templates/hovercards/hovercard_user.mako')
|
||||
def hovercard_username(self):
|
||||
c = self.load_default_context()
|
||||
username = self.request.matchdict['username']
|
||||
c.user = User.get_by_username(username)
|
||||
if not c.user:
|
||||
raise HTTPNotFound()
|
||||
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@view_config(
|
||||
route_name='hovercard_user_group', request_method='GET', xhr=True,
|
||||
|
|
|
|||
|
|
@ -108,7 +108,8 @@ class TestLoginController(object):
|
|||
|
||||
def test_login_regular_forbidden_when_super_admin_restriction(self):
|
||||
from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin
|
||||
with fixture.auth_restriction(RhodeCodeAuthPlugin.AUTH_RESTRICTION_SUPER_ADMIN):
|
||||
with fixture.auth_restriction(self.app._pyramid_registry,
|
||||
RhodeCodeAuthPlugin.AUTH_RESTRICTION_SUPER_ADMIN):
|
||||
response = self.app.post(route_path('login'),
|
||||
{'username': 'test_regular',
|
||||
'password': 'test12'})
|
||||
|
|
@ -118,7 +119,8 @@ class TestLoginController(object):
|
|||
|
||||
def test_login_regular_forbidden_when_scope_restriction(self):
|
||||
from rhodecode.authentication.plugins.auth_rhodecode import RhodeCodeAuthPlugin
|
||||
with fixture.scope_restriction(RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_VCS):
|
||||
with fixture.scope_restriction(self.app._pyramid_registry,
|
||||
RhodeCodeAuthPlugin.AUTH_RESTRICTION_SCOPE_VCS):
|
||||
response = self.app.post(route_path('login'),
|
||||
{'username': 'test_regular',
|
||||
'password': 'test12'})
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ class MyAccountView(BaseAppView, DataGridAppView):
|
|||
def my_account_profile(self):
|
||||
c = self.load_default_context()
|
||||
c.active = 'profile'
|
||||
c.extern_type = c.user.extern_type
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
|
|
|
|||
|
|
@ -72,8 +72,11 @@ class MyAccountSshKeysView(BaseAppView, DataGridAppView):
|
|||
|
||||
c.active = 'ssh_keys_generate'
|
||||
if c.ssh_key_generator_enabled:
|
||||
private_format = self.request.GET.get('private_format') \
|
||||
or SshKeyModel.DEFAULT_PRIVATE_KEY_FORMAT
|
||||
comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
|
||||
c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
|
||||
c.private, c.public = SshKeyModel().generate_keypair(
|
||||
comment=comment, private_format=private_format)
|
||||
c.target_form_url = h.route_path(
|
||||
'my_account_ssh_keys', _query=dict(default_key=c.public))
|
||||
return self._get_template_context(c)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ from rhodecode.lib import helpers as h
|
|||
from rhodecode.lib import audit_logger
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
|
||||
from rhodecode.model.db import User
|
||||
from rhodecode.model.permission import PermissionModel
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.forms import RepoGroupPermsForm
|
||||
|
|
@ -96,7 +97,13 @@ class RepoGroupPermissionsView(RepoGroupAppView):
|
|||
|
||||
Session().commit()
|
||||
h.flash(_('Repository Group permissions updated'), category='success')
|
||||
PermissionModel().flush_user_permission_caches(changes)
|
||||
|
||||
affected_user_ids = None
|
||||
if changes.get('default_user_changed', False):
|
||||
# if we change the default user, we need to flush everyone permissions
|
||||
affected_user_ids = User.get_all_user_ids()
|
||||
PermissionModel().flush_user_permission_caches(
|
||||
changes, affected_user_ids=affected_user_ids)
|
||||
|
||||
raise HTTPFound(
|
||||
h.route_path('edit_repo_group_perms',
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ from rhodecode.lib import helpers as h
|
|||
from rhodecode.lib import audit_logger
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
|
||||
from rhodecode.lib.utils2 import str2bool
|
||||
from rhodecode.model.db import User
|
||||
from rhodecode.model.forms import RepoPermsForm
|
||||
from rhodecode.model.meta import Session
|
||||
from rhodecode.model.permission import PermissionModel
|
||||
|
|
@ -89,7 +91,12 @@ class RepoSettingsPermissionsView(RepoAppView):
|
|||
Session().commit()
|
||||
h.flash(_('Repository access permissions updated'), category='success')
|
||||
|
||||
PermissionModel().flush_user_permission_caches(changes)
|
||||
affected_user_ids = None
|
||||
if changes.get('default_user_changed', False):
|
||||
# if we change the default user, we need to flush everyone permissions
|
||||
affected_user_ids = User.get_all_user_ids()
|
||||
PermissionModel().flush_user_permission_caches(
|
||||
changes, affected_user_ids=affected_user_ids)
|
||||
|
||||
raise HTTPFound(
|
||||
h.route_path('edit_repo_perms', repo_name=self.db_repo_name))
|
||||
|
|
@ -104,9 +111,11 @@ class RepoSettingsPermissionsView(RepoAppView):
|
|||
_ = self.request.translate
|
||||
self.load_default_context()
|
||||
|
||||
private_flag = str2bool(self.request.POST.get('private'))
|
||||
|
||||
try:
|
||||
RepoModel().update(
|
||||
self.db_repo, **{'repo_private': True, 'repo_name': self.db_repo_name})
|
||||
self.db_repo, **{'repo_private': private_flag, 'repo_name': self.db_repo_name})
|
||||
Session().commit()
|
||||
|
||||
h.flash(_('Repository `{}` private mode set successfully').format(self.db_repo_name),
|
||||
|
|
@ -116,7 +125,11 @@ class RepoSettingsPermissionsView(RepoAppView):
|
|||
h.flash(_('Error occurred during update of repository {}').format(
|
||||
self.db_repo_name), category='error')
|
||||
|
||||
# NOTE(dan): we change repo private mode we need to notify all USERS
|
||||
affected_user_ids = User.get_all_user_ids()
|
||||
PermissionModel().trigger_permission_flush(affected_user_ids)
|
||||
|
||||
return {
|
||||
'redirect_url': h.route_path('edit_repo_perms', repo_name=self.db_repo_name),
|
||||
'private': True
|
||||
'private': private_flag
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,6 +275,20 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
|
||||
c.state_progressing = pull_request.is_state_changing()
|
||||
|
||||
_new_state = {
|
||||
'created': PullRequest.STATE_CREATED,
|
||||
}.get(self.request.GET.get('force_state'))
|
||||
if c.is_super_admin and _new_state:
|
||||
with pull_request.set_state(PullRequest.STATE_UPDATING, final_state=_new_state):
|
||||
h.flash(
|
||||
_('Pull Request state was force changed to `{}`').format(_new_state),
|
||||
category='success')
|
||||
Session().commit()
|
||||
|
||||
raise HTTPFound(h.route_path(
|
||||
'pullrequest_show', repo_name=self.db_repo_name,
|
||||
pull_request_id=pull_request_id))
|
||||
|
||||
version = self.request.GET.get('version')
|
||||
from_version = self.request.GET.get('from_version') or version
|
||||
merge_checks = self.request.GET.get('merge_checks')
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ from rhodecode.lib.auth import (
|
|||
LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
|
||||
from rhodecode.model.forms import IssueTrackerPatternsForm
|
||||
from rhodecode.model.meta import Session
|
||||
from rhodecode.model.settings import IssueTrackerSettingsModel, SettingsModel
|
||||
from rhodecode.model.settings import SettingsModel
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ class RepoSettingsIssueTrackersView(RepoAppView):
|
|||
c.active = 'issuetracker'
|
||||
c.data = 'data'
|
||||
|
||||
c.settings_model = IssueTrackerSettingsModel(repo=self.db_repo)
|
||||
c.settings_model = self.db_repo_patterns
|
||||
c.global_patterns = c.settings_model.get_global_settings()
|
||||
c.repo_patterns = c.settings_model.get_repo_settings()
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ class RepoSettingsIssueTrackersView(RepoAppView):
|
|||
def repo_issuetracker_delete(self):
|
||||
_ = self.request.translate
|
||||
uid = self.request.POST.get('uid')
|
||||
repo_settings = IssueTrackerSettingsModel(repo=self.db_repo_name)
|
||||
repo_settings = self.db_repo_patterns
|
||||
try:
|
||||
repo_settings.delete_entries(uid)
|
||||
except Exception:
|
||||
|
|
@ -113,7 +113,7 @@ class RepoSettingsIssueTrackersView(RepoAppView):
|
|||
def repo_issuetracker_update(self):
|
||||
_ = self.request.translate
|
||||
# Save inheritance
|
||||
repo_settings = IssueTrackerSettingsModel(repo=self.db_repo_name)
|
||||
repo_settings = self.db_repo_patterns
|
||||
inherited = (
|
||||
self.request.POST.get('inherit_global_issuetracker') == "inherited")
|
||||
repo_settings.inherit_global_settings = inherited
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
# LogLevel info
|
||||
# # allows custom host names, prevents 400 errors on checkout
|
||||
# HttpProtocolOptions Unsafe
|
||||
# # Most likely this will be: /home/user/.rccontrol/enterprise-1/mod_dav_svn.conf
|
||||
# Include /path/to/generated/mod_dav_svn.conf
|
||||
# </VirtualHost>
|
||||
#
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ class RhodeCodeAuthPluginBase(object):
|
|||
|
||||
def __init__(self, plugin_id):
|
||||
self._plugin_id = plugin_id
|
||||
self._settings = {}
|
||||
|
||||
def __str__(self):
|
||||
return self.get_id()
|
||||
|
|
@ -226,17 +227,26 @@ class RhodeCodeAuthPluginBase(object):
|
|||
"""
|
||||
return AuthnPluginSettingsSchemaBase()
|
||||
|
||||
def get_settings(self):
|
||||
"""
|
||||
Returns the plugin settings as dictionary.
|
||||
"""
|
||||
def _propagate_settings(self, raw_settings):
|
||||
settings = {}
|
||||
raw_settings = SettingsModel().get_all_settings()
|
||||
for node in self.get_settings_schema():
|
||||
settings[node.name] = self.get_setting_by_name(
|
||||
node.name, plugin_cached_settings=raw_settings)
|
||||
return settings
|
||||
|
||||
def get_settings(self, use_cache=True):
|
||||
"""
|
||||
Returns the plugin settings as dictionary.
|
||||
"""
|
||||
if self._settings != {} and use_cache:
|
||||
return self._settings
|
||||
|
||||
raw_settings = SettingsModel().get_all_settings()
|
||||
settings = self._propagate_settings(raw_settings)
|
||||
|
||||
self._settings = settings
|
||||
return self._settings
|
||||
|
||||
def get_setting_by_name(self, name, default=None, plugin_cached_settings=None):
|
||||
"""
|
||||
Returns a plugin setting by name.
|
||||
|
|
@ -594,19 +604,19 @@ class AuthLdapBase(object):
|
|||
if not full_resolve:
|
||||
return '{}:{}'.format(host, port)
|
||||
|
||||
log.debug('LDAP: Resolving IP for LDAP host %s', host)
|
||||
log.debug('LDAP: Resolving IP for LDAP host `%s`', host)
|
||||
try:
|
||||
ip = socket.gethostbyname(host)
|
||||
log.debug('Got LDAP server %s ip %s', host, ip)
|
||||
log.debug('LDAP: Got LDAP host `%s` ip %s', host, ip)
|
||||
except Exception:
|
||||
raise LdapConnectionError(
|
||||
'Failed to resolve host: `{}`'.format(host))
|
||||
raise LdapConnectionError('Failed to resolve host: `{}`'.format(host))
|
||||
|
||||
log.debug('LDAP: Checking if IP %s is accessible', ip)
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.connect((ip, int(port)))
|
||||
s.shutdown(socket.SHUT_RD)
|
||||
log.debug('LDAP: connection to %s successful', ip)
|
||||
except Exception:
|
||||
raise LdapConnectionError(
|
||||
'Failed to connect to host: `{}:{}`'.format(host, port))
|
||||
|
|
@ -667,7 +677,7 @@ def loadplugin(plugin_id):
|
|||
|
||||
def get_authn_registry(registry=None):
|
||||
registry = registry or get_current_registry()
|
||||
authn_registry = registry.getUtility(IAuthnPluginRegistry)
|
||||
authn_registry = registry.queryUtility(IAuthnPluginRegistry)
|
||||
return authn_registry
|
||||
|
||||
|
||||
|
|
@ -690,6 +700,7 @@ def authenticate(username, password, environ=None, auth_type=None,
|
|||
headers_only = environ and not (username and password)
|
||||
|
||||
authn_registry = get_authn_registry(registry)
|
||||
|
||||
plugins_to_check = authn_registry.get_plugins_for_authentication()
|
||||
log.debug('Starting ordered authentication chain using %s plugins',
|
||||
[x.name for x in plugins_to_check])
|
||||
|
|
|
|||
|
|
@ -145,16 +145,16 @@ class AuthLdap(AuthLdapBase):
|
|||
log.debug('Trying simple_bind with password and given login DN: %r',
|
||||
self.LDAP_BIND_DN)
|
||||
ldap_conn.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS)
|
||||
|
||||
log.debug('simple_bind successful')
|
||||
return ldap_conn
|
||||
|
||||
def fetch_attrs_from_simple_bind(self, server, dn, username, password):
|
||||
try:
|
||||
log.debug('Trying simple bind with %r', dn)
|
||||
server.simple_bind_s(dn, safe_str(password))
|
||||
user = server.search_ext_s(
|
||||
_dn, attrs = server.search_ext_s(
|
||||
dn, ldap.SCOPE_BASE, '(objectClass=*)', )[0]
|
||||
_, attrs = user
|
||||
|
||||
return attrs
|
||||
|
||||
except ldap.INVALID_CREDENTIALS:
|
||||
|
|
@ -206,7 +206,7 @@ class AuthLdap(AuthLdapBase):
|
|||
break
|
||||
else:
|
||||
raise LdapPasswordError(
|
||||
'Failed to authenticate user `{}`'
|
||||
'Failed to authenticate user `{}` '
|
||||
'with given password'.format(username))
|
||||
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
|
|
@ -249,7 +249,7 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
|
|||
colander.Int(),
|
||||
default=389,
|
||||
description=_('Custom port that the LDAP server is listening on. '
|
||||
'Default value is: 389, use 689 for LDAPS(SSL)'),
|
||||
'Default value is: 389, use 689 for LDAPS (SSL)'),
|
||||
preparer=strip_whitespace,
|
||||
title=_('Port'),
|
||||
validator=colander.Range(min=0, max=65536),
|
||||
|
|
@ -272,7 +272,7 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
|
|||
'uid=root,cn=users,dc=mydomain,dc=com, or admin@mydomain.com'),
|
||||
missing='',
|
||||
preparer=strip_whitespace,
|
||||
title=_('Account'),
|
||||
title=_('Bind account'),
|
||||
widget='string')
|
||||
dn_pass = colander.SchemaNode(
|
||||
colander.String(),
|
||||
|
|
@ -280,7 +280,7 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
|
|||
description=_('Password to authenticate for given user DN.'),
|
||||
missing='',
|
||||
preparer=strip_whitespace,
|
||||
title=_('Password'),
|
||||
title=_('Bind account password'),
|
||||
widget='password')
|
||||
tls_kind = colander.SchemaNode(
|
||||
colander.String(),
|
||||
|
|
@ -318,7 +318,7 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
|
|||
colander.String(),
|
||||
default='',
|
||||
description=_('Base DN to search. Dynamic bind is supported. Add `$login` marker '
|
||||
'in it to be replaced with current user credentials \n'
|
||||
'in it to be replaced with current user username \n'
|
||||
'(e.g., dc=mydomain,dc=com, or ou=Users,dc=mydomain,dc=com)'),
|
||||
missing='',
|
||||
preparer=strip_whitespace,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class AuthenticationPluginRegistry(object):
|
|||
|
||||
def __init__(self, settings):
|
||||
self._plugins = {}
|
||||
self._plugins_for_auth = None
|
||||
self._fallback_plugin = settings.get(self.fallback_plugin_key, None)
|
||||
|
||||
def add_authn_plugin(self, config, plugin):
|
||||
|
|
@ -63,6 +64,10 @@ class AuthenticationPluginRegistry(object):
|
|||
if plugin.uid == plugin_uid:
|
||||
return plugin
|
||||
|
||||
def invalidate_plugins_for_auth(self):
|
||||
log.debug('Invalidating cached plugins for authentication')
|
||||
self._plugins_for_auth = None
|
||||
|
||||
def get_plugins_for_authentication(self):
|
||||
"""
|
||||
Returns a list of plugins which should be consulted when authenticating
|
||||
|
|
@ -70,6 +75,9 @@ class AuthenticationPluginRegistry(object):
|
|||
Additionally it includes the fallback plugin from the INI file, if
|
||||
`rhodecode.auth_plugin_fallback` is set to a plugin ID.
|
||||
"""
|
||||
if self._plugins_for_auth is not None:
|
||||
return self._plugins_for_auth
|
||||
|
||||
plugins = []
|
||||
|
||||
# Add all enabled and active plugins to the list. We iterate over the
|
||||
|
|
@ -80,6 +88,9 @@ class AuthenticationPluginRegistry(object):
|
|||
plugin = self.get_plugin(plugin_id)
|
||||
if plugin is not None and plugin.is_active(
|
||||
plugin_cached_settings=raw_settings):
|
||||
|
||||
# inject settings into plugin, we can re-use the DB fetched settings here
|
||||
plugin._settings = plugin._propagate_settings(raw_settings)
|
||||
plugins.append(plugin)
|
||||
|
||||
# Add the fallback plugin from ini file.
|
||||
|
|
@ -89,6 +100,8 @@ class AuthenticationPluginRegistry(object):
|
|||
self._fallback_plugin)
|
||||
plugin = self.get_plugin(self._fallback_plugin)
|
||||
if plugin is not None and plugin not in plugins:
|
||||
plugin._settings = plugin._propagate_settings(raw_settings)
|
||||
plugins.append(plugin)
|
||||
|
||||
return plugins
|
||||
self._plugins_for_auth = plugins
|
||||
return self._plugins_for_auth
|
||||
|
|
|
|||
|
|
@ -99,11 +99,12 @@ class AuthnPluginViewBase(BaseAppView):
|
|||
for name, value in valid_data.items():
|
||||
self.plugin.create_or_update_setting(name, value)
|
||||
Session().commit()
|
||||
SettingsModel().invalidate_settings_cache()
|
||||
|
||||
# Display success message and redirect.
|
||||
h.flash(_('Auth settings updated successfully.'), category='success')
|
||||
redirect_to = self.request.resource_path(
|
||||
self.context, route_name='auth_home')
|
||||
redirect_to = self.request.resource_path(self.context, route_name='auth_home')
|
||||
|
||||
return HTTPFound(redirect_to)
|
||||
|
||||
|
||||
|
|
@ -159,7 +160,7 @@ class AuthSettingsView(BaseAppView):
|
|||
'auth_plugins', plugins)
|
||||
Session().add(setting)
|
||||
Session().commit()
|
||||
|
||||
SettingsModel().invalidate_settings_cache()
|
||||
h.flash(_('Auth settings updated successfully.'), category='success')
|
||||
except formencode.Invalid as errors:
|
||||
e = errors.error_dict or {}
|
||||
|
|
@ -174,6 +175,6 @@ class AuthSettingsView(BaseAppView):
|
|||
h.flash(_('Error occurred during update of auth settings.'),
|
||||
category='error')
|
||||
|
||||
redirect_to = self.request.resource_path(
|
||||
self.context, route_name='auth_home')
|
||||
redirect_to = self.request.resource_path(self.context, route_name='auth_home')
|
||||
|
||||
return HTTPFound(redirect_to)
|
||||
|
|
|
|||
|
|
@ -95,3 +95,5 @@ def inspect_getargspec():
|
|||
return inspect.ArgSpec(args, varargs, varkw, func.func_defaults)
|
||||
|
||||
inspect.getargspec = custom_getargspec
|
||||
|
||||
return inspect
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -151,20 +151,22 @@ def _store_log(action_name, action_data, user_id, username, user_data,
|
|||
|
||||
|
||||
def store_web(*args, **kwargs):
|
||||
if 'action_data' not in kwargs:
|
||||
kwargs['action_data'] = {}
|
||||
kwargs['action_data'].update({
|
||||
'source': SOURCE_WEB
|
||||
})
|
||||
action_data = {}
|
||||
org_action_data = kwargs.pop('action_data', {})
|
||||
action_data.update(org_action_data)
|
||||
action_data['source'] = SOURCE_WEB
|
||||
kwargs['action_data'] = action_data
|
||||
|
||||
return store(*args, **kwargs)
|
||||
|
||||
|
||||
def store_api(*args, **kwargs):
|
||||
if 'action_data' not in kwargs:
|
||||
kwargs['action_data'] = {}
|
||||
kwargs['action_data'].update({
|
||||
'source': SOURCE_API
|
||||
})
|
||||
action_data = {}
|
||||
org_action_data = kwargs.pop('action_data', {})
|
||||
action_data.update(org_action_data)
|
||||
action_data['source'] = SOURCE_API
|
||||
kwargs['action_data'] = action_data
|
||||
|
||||
return store(*args, **kwargs)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ authentication and permission libraries
|
|||
|
||||
import os
|
||||
import time
|
||||
import inspect
|
||||
import collections
|
||||
import fnmatch
|
||||
import hashlib
|
||||
|
|
@ -2013,6 +2012,7 @@ class PermsFunction(object):
|
|||
self.user_group_name = None
|
||||
|
||||
def __bool__(self):
|
||||
import inspect
|
||||
frame = inspect.currentframe()
|
||||
stack_trace = traceback.format_stack(frame)
|
||||
log.error('Checking bool value on a class instance of perm '
|
||||
|
|
|
|||
|
|
@ -211,8 +211,9 @@ def vcs_operation_context(
|
|||
class BasicAuth(AuthBasicAuthenticator):
|
||||
|
||||
def __init__(self, realm, authfunc, registry, auth_http_code=None,
|
||||
initial_call_detection=False, acl_repo_name=None):
|
||||
initial_call_detection=False, acl_repo_name=None, rc_realm=''):
|
||||
self.realm = realm
|
||||
self.rc_realm = rc_realm
|
||||
self.initial_call = initial_call_detection
|
||||
self.authfunc = authfunc
|
||||
self.registry = registry
|
||||
|
|
@ -227,7 +228,7 @@ class BasicAuth(AuthBasicAuthenticator):
|
|||
return HTTPForbidden
|
||||
|
||||
def get_rc_realm(self):
|
||||
return safe_str(self.registry.rhodecode_settings.get('rhodecode_realm'))
|
||||
return safe_str(self.rc_realm)
|
||||
|
||||
def build_authentication(self):
|
||||
head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
|
||||
|
|
@ -288,7 +289,7 @@ def attach_context_attributes(context, request, user_id=None):
|
|||
"""
|
||||
config = request.registry.settings
|
||||
|
||||
rc_config = SettingsModel().get_all_settings(cache=True)
|
||||
rc_config = SettingsModel().get_all_settings(cache=True, from_request=False)
|
||||
context.rc_config = rc_config
|
||||
context.rhodecode_version = rhodecode.__version__
|
||||
context.rhodecode_edition = config.get('rhodecode.edition')
|
||||
|
|
|
|||
|
|
@ -66,11 +66,12 @@ markdown_tags = [
|
|||
markdown_attrs = {
|
||||
"*": ["class", "style", "align"],
|
||||
"img": ["src", "alt", "title"],
|
||||
"a": ["href", "alt", "title", "name"],
|
||||
"a": ["href", "alt", "title", "name", "data-hovercard-alt", "data-hovercard-url"],
|
||||
"abbr": ["title"],
|
||||
"acronym": ["title"],
|
||||
"pre": ["lang"],
|
||||
"input": ["type", "disabled", "checked"]
|
||||
"input": ["type", "disabled", "checked"],
|
||||
"strong": ["title", "data-hovercard-alt", "data-hovercard-url"],
|
||||
}
|
||||
|
||||
standard_styles = [
|
||||
|
|
|
|||
|
|
@ -421,9 +421,20 @@ class DbManage(object):
|
|||
|
||||
:param skip_existing:
|
||||
"""
|
||||
defaults = [
|
||||
('auth_plugins',
|
||||
'egg:rhodecode-enterprise-ce#token,egg:rhodecode-enterprise-ce#rhodecode',
|
||||
'list'),
|
||||
|
||||
for k, v, t in [('auth_plugins', 'egg:rhodecode-enterprise-ce#rhodecode', 'list'),
|
||||
('auth_rhodecode_enabled', 'True', 'bool')]:
|
||||
('auth_authtoken_enabled',
|
||||
'True',
|
||||
'bool'),
|
||||
|
||||
('auth_rhodecode_enabled',
|
||||
'True',
|
||||
'bool'),
|
||||
]
|
||||
for k, v, t in defaults:
|
||||
if (skip_existing and
|
||||
SettingsModel().get_setting_by_name(k) is not None):
|
||||
log.debug('Skipping option %s', k)
|
||||
|
|
@ -568,19 +579,32 @@ class DbManage(object):
|
|||
('title', '', 'unicode'),
|
||||
('pre_code', '', 'unicode'),
|
||||
('post_code', '', 'unicode'),
|
||||
|
||||
# Visual
|
||||
('show_public_icon', True, 'bool'),
|
||||
('show_private_icon', True, 'bool'),
|
||||
('stylify_metatags', False, 'bool'),
|
||||
('dashboard_items', 100, 'int'),
|
||||
('admin_grid_items', 25, 'int'),
|
||||
|
||||
('markup_renderer', 'markdown', 'unicode'),
|
||||
|
||||
('show_version', True, 'bool'),
|
||||
('use_gravatar', False, 'bool'),
|
||||
('gravatar_url', User.DEFAULT_GRAVATAR_URL, 'unicode'),
|
||||
('clone_uri_tmpl', Repository.DEFAULT_CLONE_URI, 'unicode'),
|
||||
('support_url', '', 'unicode'),
|
||||
('update_url', RhodeCodeSetting.DEFAULT_UPDATE_URL, 'unicode'),
|
||||
('show_revision_number', True, 'bool'),
|
||||
('show_sha_length', 12, 'int'),
|
||||
|
||||
('use_gravatar', False, 'bool'),
|
||||
('gravatar_url', User.DEFAULT_GRAVATAR_URL, 'unicode'),
|
||||
|
||||
('clone_uri_tmpl', Repository.DEFAULT_CLONE_URI, 'unicode'),
|
||||
('clone_uri_ssh_tmpl', Repository.DEFAULT_CLONE_URI_SSH, 'unicode'),
|
||||
('support_url', '', 'unicode'),
|
||||
('update_url', RhodeCodeSetting.DEFAULT_UPDATE_URL, 'unicode'),
|
||||
|
||||
# VCS Settings
|
||||
('pr_merge_enabled', True, 'bool'),
|
||||
('use_outdated_comments', True, 'bool'),
|
||||
('diff_cache', True, 'bool'),
|
||||
]
|
||||
|
||||
for key, val, type_ in settings:
|
||||
|
|
|
|||
|
|
@ -598,9 +598,10 @@ class _Message(object):
|
|||
* ``category``: the category specified when the message was created.
|
||||
"""
|
||||
|
||||
def __init__(self, category, message):
|
||||
def __init__(self, category, message, sub_data=None):
|
||||
self.category = category
|
||||
self.message = message
|
||||
self.sub_data = sub_data or {}
|
||||
|
||||
def __str__(self):
|
||||
return self.message
|
||||
|
|
@ -663,7 +664,17 @@ class Flash(object):
|
|||
# of strings.
|
||||
for cat in self.categories:
|
||||
for msg in session.pop_flash(queue=cat):
|
||||
messages.append(_Message(cat, msg))
|
||||
sub_data = {}
|
||||
if hasattr(msg, 'rsplit'):
|
||||
flash_data = msg.rsplit('|DELIM|', 1)
|
||||
org_message = flash_data[0]
|
||||
if len(flash_data) > 1:
|
||||
sub_data = json.loads(flash_data[1])
|
||||
else:
|
||||
org_message = msg
|
||||
|
||||
messages.append(_Message(cat, org_message, sub_data=sub_data))
|
||||
|
||||
# Map messages from the default queue to the 'notice' category.
|
||||
for msg in session.pop_flash():
|
||||
messages.append(_Message('notice', msg))
|
||||
|
|
@ -673,25 +684,16 @@ class Flash(object):
|
|||
|
||||
def json_alerts(self, session=None, request=None):
|
||||
payloads = []
|
||||
messages = flash.pop_messages(session=session, request=request)
|
||||
if messages:
|
||||
for message in messages:
|
||||
subdata = {}
|
||||
if hasattr(message.message, 'rsplit'):
|
||||
flash_data = message.message.rsplit('|DELIM|', 1)
|
||||
org_message = flash_data[0]
|
||||
if len(flash_data) > 1:
|
||||
subdata = json.loads(flash_data[1])
|
||||
else:
|
||||
org_message = message.message
|
||||
payloads.append({
|
||||
'message': {
|
||||
'message': u'{}'.format(org_message),
|
||||
'level': message.category,
|
||||
'force': True,
|
||||
'subdata': subdata
|
||||
}
|
||||
})
|
||||
messages = flash.pop_messages(session=session, request=request) or []
|
||||
for message in messages:
|
||||
payloads.append({
|
||||
'message': {
|
||||
'message': u'{}'.format(message.message),
|
||||
'level': message.category,
|
||||
'force': True,
|
||||
'subdata': message.sub_data
|
||||
}
|
||||
})
|
||||
return json.dumps(payloads)
|
||||
|
||||
def __call__(self, message, category=None, ignore_duplicate=True,
|
||||
|
|
@ -1514,6 +1516,9 @@ def get_active_pattern_entries(repo_name):
|
|||
return active_entries
|
||||
|
||||
|
||||
pr_pattern_re = re.compile(r'(?:(?:^!)|(?: !))(\d+)')
|
||||
|
||||
|
||||
def process_patterns(text_string, repo_name, link_format='html', active_entries=None):
|
||||
|
||||
allowed_formats = ['html', 'rst', 'markdown',
|
||||
|
|
@ -1522,7 +1527,10 @@ def process_patterns(text_string, repo_name, link_format='html', active_entries=
|
|||
raise ValueError('Link format can be only one of:{} got {}'.format(
|
||||
allowed_formats, link_format))
|
||||
|
||||
active_entries = active_entries or get_active_pattern_entries(repo_name)
|
||||
if active_entries is None:
|
||||
log.debug('Fetch active patterns for repo: %s', repo_name)
|
||||
active_entries = get_active_pattern_entries(repo_name)
|
||||
|
||||
issues_data = []
|
||||
new_text = text_string
|
||||
|
||||
|
|
@ -1537,11 +1545,14 @@ def process_patterns(text_string, repo_name, link_format='html', active_entries=
|
|||
log.debug('issue tracker entry: uid: `%s` PAT:%s URL:%s PREFIX:%s',
|
||||
uid, entry['pat'], entry['url'], entry['pref'])
|
||||
|
||||
try:
|
||||
pattern = re.compile(r'%s' % entry['pat'])
|
||||
except re.error:
|
||||
log.exception('issue tracker pattern: `%s` failed to compile', entry['pat'])
|
||||
continue
|
||||
if entry.get('pat_compiled'):
|
||||
pattern = entry['pat_compiled']
|
||||
else:
|
||||
try:
|
||||
pattern = re.compile(r'%s' % entry['pat'])
|
||||
except re.error:
|
||||
log.exception('issue tracker pattern: `%s` failed to compile', entry['pat'])
|
||||
continue
|
||||
|
||||
data_func = partial(
|
||||
_process_url_func, repo_name=repo_name, entry=entry, uid=uid,
|
||||
|
|
@ -1569,7 +1580,7 @@ def process_patterns(text_string, repo_name, link_format='html', active_entries=
|
|||
pr_url_func = partial(
|
||||
_process_url_func, repo_name=repo_name, entry=pr_entry, uid=None,
|
||||
link_format=link_format+'+hovercard')
|
||||
new_text = re.compile(r'(?:(?:^!)|(?: !))(\d+)').sub(pr_url_func, new_text)
|
||||
new_text = pr_pattern_re.sub(pr_url_func, new_text)
|
||||
log.debug('processed !pr pattern')
|
||||
|
||||
return new_text, issues_data
|
||||
|
|
@ -1580,6 +1591,7 @@ def urlify_commit_message(commit_text, repository=None, active_pattern_entries=N
|
|||
Parses given text message and makes proper links.
|
||||
issues are linked to given issue-server, and rest is a commit link
|
||||
"""
|
||||
|
||||
def escaper(_text):
|
||||
return _text.replace('<', '<').replace('>', '>')
|
||||
|
||||
|
|
@ -1636,7 +1648,7 @@ def renderer_from_filename(filename, exclude=None):
|
|||
|
||||
|
||||
def render(source, renderer='rst', mentions=False, relative_urls=None,
|
||||
repo_name=None):
|
||||
repo_name=None, active_pattern_entries=None):
|
||||
|
||||
def maybe_convert_relative_links(html_source):
|
||||
if relative_urls:
|
||||
|
|
@ -1651,7 +1663,8 @@ def render(source, renderer='rst', mentions=False, relative_urls=None,
|
|||
if repo_name:
|
||||
# process patterns on comments if we pass in repo name
|
||||
source, issues = process_patterns(
|
||||
source, repo_name, link_format='rst')
|
||||
source, repo_name, link_format='rst',
|
||||
active_entries=active_pattern_entries)
|
||||
|
||||
return literal(
|
||||
'<div class="rst-block">%s</div>' %
|
||||
|
|
@ -1662,7 +1675,8 @@ def render(source, renderer='rst', mentions=False, relative_urls=None,
|
|||
if repo_name:
|
||||
# process patterns on comments if we pass in repo name
|
||||
source, issues = process_patterns(
|
||||
source, repo_name, link_format='markdown')
|
||||
source, repo_name, link_format='markdown',
|
||||
active_entries=active_pattern_entries)
|
||||
|
||||
return literal(
|
||||
'<div class="markdown-block">%s</div>' %
|
||||
|
|
|
|||
|
|
@ -47,6 +47,14 @@ log = logging.getLogger(__name__)
|
|||
# default renderer used to generate automated comments
|
||||
DEFAULT_COMMENTS_RENDERER = 'rst'
|
||||
|
||||
try:
|
||||
from lxml.html import fromstring
|
||||
from lxml.html import tostring
|
||||
except ImportError:
|
||||
log.exception('Failed to import lxml')
|
||||
fromstring = None
|
||||
tostring = None
|
||||
|
||||
|
||||
class CustomHTMLTranslator(writers.html4css1.HTMLTranslator):
|
||||
"""
|
||||
|
|
@ -81,11 +89,7 @@ def relative_links(html_source, server_paths):
|
|||
if not html_source:
|
||||
return html_source
|
||||
|
||||
try:
|
||||
from lxml.html import fromstring
|
||||
from lxml.html import tostring
|
||||
except ImportError:
|
||||
log.exception('Failed to import lxml')
|
||||
if not fromstring and tostring:
|
||||
return html_source
|
||||
|
||||
try:
|
||||
|
|
@ -210,6 +214,8 @@ class MarkupRenderer(object):
|
|||
URL_PAT = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'
|
||||
r'|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)')
|
||||
|
||||
MENTION_PAT = re.compile(MENTIONS_REGEX)
|
||||
|
||||
extensions = ['markdown.extensions.codehilite', 'markdown.extensions.extra',
|
||||
'markdown.extensions.def_list', 'markdown.extensions.sane_lists']
|
||||
|
||||
|
|
@ -347,6 +353,26 @@ class MarkupRenderer(object):
|
|||
|
||||
return cls.URL_PAT.sub(url_func, text)
|
||||
|
||||
@classmethod
|
||||
def convert_mentions(cls, text, mode):
|
||||
mention_pat = cls.MENTION_PAT
|
||||
|
||||
def wrapp(match_obj):
|
||||
uname = match_obj.groups()[0]
|
||||
hovercard_url = "pyroutes.url('hovercard_username', {'username': '%s'});" % uname
|
||||
|
||||
if mode == 'markdown':
|
||||
tmpl = '<strong class="tooltip-hovercard" data-hovercard-alt="{uname}" data-hovercard-url="{hovercard_url}">@{uname}</strong>'
|
||||
elif mode == 'rst':
|
||||
tmpl = ' **@{uname}** '
|
||||
else:
|
||||
raise ValueError('mode must be rst or markdown')
|
||||
|
||||
return tmpl.format(**{'uname': uname,
|
||||
'hovercard_url': hovercard_url})
|
||||
|
||||
return mention_pat.sub(wrapp, text).strip()
|
||||
|
||||
@classmethod
|
||||
def plain(cls, source, universal_newline=True, leading_newline=True):
|
||||
source = safe_unicode(source)
|
||||
|
|
@ -378,12 +404,7 @@ class MarkupRenderer(object):
|
|||
cls.extensions, cls.output_format)
|
||||
|
||||
if mentions:
|
||||
mention_pat = re.compile(MENTIONS_REGEX)
|
||||
|
||||
def wrapp(match_obj):
|
||||
uname = match_obj.groups()[0]
|
||||
return ' **@%(uname)s** ' % {'uname': uname}
|
||||
mention_hl = mention_pat.sub(wrapp, source).strip()
|
||||
mention_hl = cls.convert_mentions(source, mode='markdown')
|
||||
# we extracted mentions render with this using Mentions false
|
||||
return cls.markdown(mention_hl, safe=safe, flavored=flavored,
|
||||
mentions=False)
|
||||
|
|
@ -409,12 +430,7 @@ class MarkupRenderer(object):
|
|||
@classmethod
|
||||
def rst(cls, source, safe=True, mentions=False, clean_html=False):
|
||||
if mentions:
|
||||
mention_pat = re.compile(MENTIONS_REGEX)
|
||||
|
||||
def wrapp(match_obj):
|
||||
uname = match_obj.groups()[0]
|
||||
return ' **@%(uname)s** ' % {'uname': uname}
|
||||
mention_hl = mention_pat.sub(wrapp, source).strip()
|
||||
mention_hl = cls.convert_mentions(source, mode='rst')
|
||||
# we extracted mentions render with this using Mentions false
|
||||
return cls.rst(mention_hl, safe=safe, mentions=False)
|
||||
|
||||
|
|
@ -443,7 +459,7 @@ class MarkupRenderer(object):
|
|||
except Exception:
|
||||
log.exception('Error when rendering RST')
|
||||
if safe:
|
||||
log.debug('Fallbacking to render in plain mode')
|
||||
log.debug('Fallback to render in plain mode')
|
||||
return cls.plain(source)
|
||||
else:
|
||||
raise
|
||||
|
|
|
|||
|
|
@ -133,15 +133,16 @@ class SimpleVCS(object):
|
|||
self.config = config
|
||||
# re-populated by specialized middleware
|
||||
self.repo_vcs_config = base.Config()
|
||||
self.rhodecode_settings = SettingsModel().get_all_settings(cache=True)
|
||||
|
||||
registry.rhodecode_settings = self.rhodecode_settings
|
||||
rc_settings = SettingsModel().get_all_settings(cache=True, from_request=False)
|
||||
realm = rc_settings.get('rhodecode_realm') or 'RhodeCode AUTH'
|
||||
|
||||
# authenticate this VCS request using authfunc
|
||||
auth_ret_code_detection = \
|
||||
str2bool(self.config.get('auth_ret_code_detection', False))
|
||||
self.authenticate = BasicAuth(
|
||||
'', authenticate, registry, config.get('auth_ret_code'),
|
||||
auth_ret_code_detection)
|
||||
auth_ret_code_detection, rc_realm=realm)
|
||||
self.ip_addr = '0.0.0.0'
|
||||
|
||||
@LazyProperty
|
||||
|
|
|
|||
|
|
@ -32,10 +32,14 @@ def BeakerSessionFactoryConfig(**options):
|
|||
|
||||
def session_callback(request, response):
|
||||
exception = getattr(request, 'exception', None)
|
||||
if (exception is None or self._cookie_on_exception) and self.accessed():
|
||||
file_response = getattr(request, '_file_response', None)
|
||||
|
||||
if file_response is None \
|
||||
and (exception is None or self._cookie_on_exception) \
|
||||
and self.accessed():
|
||||
self.persist()
|
||||
headers = self.__dict__['_headers']
|
||||
if headers['set_cookie'] and headers['cookie_out']:
|
||||
if headers.get('set_cookie') and headers.get('cookie_out'):
|
||||
response.headerlist.append(('Set-Cookie', headers['cookie_out']))
|
||||
request.add_response_callback(session_callback)
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,15 @@ class HGUpdateCaches(MaintenanceTask):
|
|||
return res
|
||||
|
||||
|
||||
class HGRebuildFnCaches(MaintenanceTask):
|
||||
human_name = 'HG rebuild fn caches'
|
||||
|
||||
def run(self):
|
||||
instance = self.db_repo.scm_instance()
|
||||
res = instance.hg_rebuild_fn_cache()
|
||||
return res
|
||||
|
||||
|
||||
class SVNVerify(MaintenanceTask):
|
||||
human_name = 'SVN Verify repo'
|
||||
|
||||
|
|
@ -162,7 +171,7 @@ class RepoMaintenance(object):
|
|||
Performs maintenance of repository based on it's type
|
||||
"""
|
||||
tasks = {
|
||||
'hg': [HGVerify, HGUpdateCaches],
|
||||
'hg': [HGVerify, HGUpdateCaches, HGRebuildFnCaches],
|
||||
'git': [GitFSCK, GitGC, GitRepack],
|
||||
'svn': [SVNVerify],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -432,8 +432,11 @@ class GitCommit(base.BaseCommit):
|
|||
"""
|
||||
if not self.parents:
|
||||
return list(self._get_file_nodes())
|
||||
return AddedFileNodesGenerator(
|
||||
[n for n in self._get_paths_for_status('added')], self)
|
||||
return AddedFileNodesGenerator(self.added_paths, self)
|
||||
|
||||
@LazyProperty
|
||||
def added_paths(self):
|
||||
return [n for n in self._get_paths_for_status('added')]
|
||||
|
||||
@LazyProperty
|
||||
def changed(self):
|
||||
|
|
@ -442,8 +445,11 @@ class GitCommit(base.BaseCommit):
|
|||
"""
|
||||
if not self.parents:
|
||||
return []
|
||||
return ChangedFileNodesGenerator(
|
||||
[n for n in self._get_paths_for_status('modified')], self)
|
||||
return ChangedFileNodesGenerator(self.changed_paths, self)
|
||||
|
||||
@LazyProperty
|
||||
def changed_paths(self):
|
||||
return [n for n in self._get_paths_for_status('modified')]
|
||||
|
||||
@LazyProperty
|
||||
def removed(self):
|
||||
|
|
@ -452,8 +458,11 @@ class GitCommit(base.BaseCommit):
|
|||
"""
|
||||
if not self.parents:
|
||||
return []
|
||||
return RemovedFileNodesGenerator(
|
||||
[n for n in self._get_paths_for_status('deleted')], self)
|
||||
return RemovedFileNodesGenerator(self.removed_paths, self)
|
||||
|
||||
@LazyProperty
|
||||
def removed_paths(self):
|
||||
return [n for n in self._get_paths_for_status('deleted')]
|
||||
|
||||
def _get_submodule_url(self, submodule_path):
|
||||
git_modules_path = '.gitmodules'
|
||||
|
|
@ -472,7 +481,7 @@ class GitCommit(base.BaseCommit):
|
|||
for line in _content.splitlines():
|
||||
yield line
|
||||
|
||||
parser = configparser.ConfigParser()
|
||||
parser = configparser.RawConfigParser()
|
||||
parser.read_file(iter_content(submodules_node.content))
|
||||
|
||||
for section in parser.sections():
|
||||
|
|
|
|||
|
|
@ -372,18 +372,30 @@ class MercurialCommit(base.BaseCommit):
|
|||
"""
|
||||
Returns list of added ``FileNode`` objects.
|
||||
"""
|
||||
return AddedFileNodesGenerator([n for n in self.status[1]], self)
|
||||
return AddedFileNodesGenerator(self.added_paths, self)
|
||||
|
||||
@LazyProperty
|
||||
def added_paths(self):
|
||||
return [n for n in self.status[1]]
|
||||
|
||||
@property
|
||||
def changed(self):
|
||||
"""
|
||||
Returns list of modified ``FileNode`` objects.
|
||||
"""
|
||||
return ChangedFileNodesGenerator([n for n in self.status[0]], self)
|
||||
return ChangedFileNodesGenerator(self.changed_paths, self)
|
||||
|
||||
@LazyProperty
|
||||
def changed_paths(self):
|
||||
return [n for n in self.status[0]]
|
||||
|
||||
@property
|
||||
def removed(self):
|
||||
"""
|
||||
Returns list of removed ``FileNode`` objects.
|
||||
"""
|
||||
return RemovedFileNodesGenerator([n for n in self.status[2]], self)
|
||||
return RemovedFileNodesGenerator(self.removed_paths, self)
|
||||
|
||||
@LazyProperty
|
||||
def removed_paths(self):
|
||||
return [n for n in self.status[2]]
|
||||
|
|
|
|||
|
|
@ -290,6 +290,12 @@ class MercurialRepository(BaseRepository):
|
|||
self._remote.invalidate_vcs_cache()
|
||||
return update_cache
|
||||
|
||||
def hg_rebuild_fn_cache(self):
|
||||
update_cache = self._remote.hg_rebuild_fn_cache()
|
||||
|
||||
self._remote.invalidate_vcs_cache()
|
||||
return update_cache
|
||||
|
||||
def get_common_ancestor(self, commit_id1, commit_id2, repo2):
|
||||
if commit_id1 == commit_id2:
|
||||
return commit_id1
|
||||
|
|
|
|||
|
|
@ -218,18 +218,27 @@ class SubversionCommit(base.BaseCommit):
|
|||
|
||||
@property
|
||||
def added(self):
|
||||
return nodes.AddedFileNodesGenerator(
|
||||
self._changes_cache['added'], self)
|
||||
return nodes.AddedFileNodesGenerator(self.added_paths, self)
|
||||
|
||||
@LazyProperty
|
||||
def added_paths(self):
|
||||
return [n for n in self._changes_cache['added']]
|
||||
|
||||
@property
|
||||
def changed(self):
|
||||
return nodes.ChangedFileNodesGenerator(
|
||||
self._changes_cache['changed'], self)
|
||||
return nodes.ChangedFileNodesGenerator(self.changed_paths, self)
|
||||
|
||||
@LazyProperty
|
||||
def changed_paths(self):
|
||||
return [n for n in self._changes_cache['changed']]
|
||||
|
||||
@property
|
||||
def removed(self):
|
||||
return nodes.RemovedFileNodesGenerator(
|
||||
self._changes_cache['removed'], self)
|
||||
return nodes.RemovedFileNodesGenerator(self.removed_paths, self)
|
||||
|
||||
@LazyProperty
|
||||
def removed_paths(self):
|
||||
return [n for n in self._changes_cache['removed']]
|
||||
|
||||
|
||||
def _date_from_svn_properties(properties):
|
||||
|
|
|
|||
|
|
@ -18,6 +18,19 @@
|
|||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
DEFAULTS = {
|
||||
'encodings_map': {'.gz': 'gzip',
|
||||
'.Z': 'compress',
|
||||
'.bz2': 'bzip2',
|
||||
'.xz': 'xz'},
|
||||
'suffix_map': {'.svgz': '.svg.gz',
|
||||
'.tgz': '.tar.gz',
|
||||
'.taz': '.tar.gz',
|
||||
'.tz': '.tar.gz',
|
||||
'.tbz2': '.tar.bz2',
|
||||
'.txz': '.tar.xz'},
|
||||
}
|
||||
|
||||
TYPES_MAP = [
|
||||
{'.jpg': 'image/jpg',
|
||||
'.mid': 'audio/midi',
|
||||
|
|
@ -1203,4 +1216,6 @@ def get_mimetypes_db(extra_types=None):
|
|||
types_map[1].update(extra_types)
|
||||
db = mimetypes.MimeTypes()
|
||||
db.types_map = types_map
|
||||
db.encodings_map.update(DEFAULTS['encodings_map'])
|
||||
db.suffix_map.update(DEFAULTS['suffix_map'])
|
||||
return db
|
||||
|
|
|
|||
|
|
@ -1024,6 +1024,17 @@ class User(Base, BaseModel):
|
|||
qry = qry.filter(User.active == true())
|
||||
return qry.all()
|
||||
|
||||
@classmethod
|
||||
def get_all_user_ids(cls, only_active=True):
|
||||
"""
|
||||
Returns all users IDs
|
||||
"""
|
||||
qry = Session().query(User.user_id)
|
||||
|
||||
if only_active:
|
||||
qry = qry.filter(User.active == true())
|
||||
return [x.user_id for x in qry]
|
||||
|
||||
@classmethod
|
||||
def get_default_user(cls, cache=False, refresh=False):
|
||||
user = User.get_by_username(User.DEFAULT_USER, cache=cache)
|
||||
|
|
@ -3890,8 +3901,8 @@ class _SetState(object):
|
|||
self._current_state = None
|
||||
|
||||
def __enter__(self):
|
||||
log.debug('StateLock: entering set state context, setting state to: `%s`',
|
||||
self._pr_state)
|
||||
log.debug('StateLock: entering set state context of pr %s, setting state to: `%s`',
|
||||
self._pr, self._pr_state)
|
||||
self.set_pr_state(self._pr_state)
|
||||
return self
|
||||
|
||||
|
|
@ -3901,8 +3912,9 @@ class _SetState(object):
|
|||
return None
|
||||
|
||||
self.set_pr_state(self._org_state)
|
||||
log.debug('StateLock: exiting set state context, setting state to: `%s`',
|
||||
self._org_state)
|
||||
log.debug('StateLock: exiting set state context of pr %s, setting state to: `%s`',
|
||||
self._pr, self._org_state)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
return self._current_state
|
||||
|
|
@ -4285,6 +4297,7 @@ class PullRequest(Base, _PullRequestBase):
|
|||
def __json__(self):
|
||||
return {
|
||||
'revisions': self.revisions,
|
||||
'versions': self.versions_count
|
||||
}
|
||||
|
||||
def calculated_review_status(self):
|
||||
|
|
@ -4307,6 +4320,14 @@ class PullRequest(Base, _PullRequestBase):
|
|||
vcs_obj = self.target_repo.scm_instance()
|
||||
return vcs_obj.get_shadow_instance(shadow_repository_path)
|
||||
|
||||
@property
|
||||
def versions_count(self):
|
||||
"""
|
||||
return number of versions this PR have, e.g a PR that once been
|
||||
updated will have 2 versions
|
||||
"""
|
||||
return self.versions.count() + 1
|
||||
|
||||
|
||||
class PullRequestVersion(Base, _PullRequestBase):
|
||||
__tablename__ = 'pull_request_versions'
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@
|
|||
"""
|
||||
permissions model for RhodeCode
|
||||
"""
|
||||
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
|
|
@ -557,6 +556,27 @@ class PermissionModel(BaseModel):
|
|||
self.sa.rollback()
|
||||
raise
|
||||
|
||||
def get_users_with_repo_write(self, db_repo):
|
||||
write_plus = ['repository.write', 'repository.admin']
|
||||
default_user_id = User.get_default_user().user_id
|
||||
user_write_permissions = collections.OrderedDict()
|
||||
|
||||
# write+ and DEFAULT user for inheritance
|
||||
for perm in db_repo.permissions():
|
||||
if perm.permission in write_plus or perm.user_id == default_user_id:
|
||||
user_write_permissions[perm.user_id] = perm
|
||||
return user_write_permissions
|
||||
|
||||
def get_user_groups_with_repo_write(self, db_repo):
|
||||
write_plus = ['repository.write', 'repository.admin']
|
||||
user_group_write_permissions = collections.OrderedDict()
|
||||
|
||||
# write+ and DEFAULT user for inheritance
|
||||
for p in db_repo.permission_user_groups():
|
||||
if p.permission in write_plus:
|
||||
user_group_write_permissions[p.users_group_id] = p
|
||||
return user_group_write_permissions
|
||||
|
||||
def trigger_permission_flush(self, affected_user_ids):
|
||||
events.trigger(events.UserPermissionsChange(affected_user_ids))
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ pull request model for RhodeCode
|
|||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
import datetime
|
||||
import urllib
|
||||
import collections
|
||||
|
|
@ -632,6 +634,7 @@ class PullRequestModel(BaseModel):
|
|||
repo_id = pull_request.target_repo.repo_id
|
||||
use_rebase = self._use_rebase_for_merging(pull_request)
|
||||
close_branch = self._close_branch_before_merging(pull_request)
|
||||
user_name = self._user_name_for_merging(pull_request, user)
|
||||
|
||||
target_ref = self._refresh_reference(
|
||||
pull_request.target_ref_parts, target_vcs)
|
||||
|
|
@ -647,7 +650,6 @@ class PullRequestModel(BaseModel):
|
|||
target_vcs.config.set(
|
||||
'rhodecode', 'RC_SCM_DATA', json.dumps(extras))
|
||||
|
||||
user_name = user.short_contact
|
||||
merge_state = target_vcs.merge(
|
||||
repo_id, workspace_id, target_ref, source_vcs,
|
||||
pull_request.source_ref_parts,
|
||||
|
|
@ -1664,6 +1666,16 @@ class PullRequestModel(BaseModel):
|
|||
|
||||
return False
|
||||
|
||||
def _user_name_for_merging(self, pull_request, user):
|
||||
env_user_name_attr = os.environ.get('RC_MERGE_USER_NAME_ATTR', '')
|
||||
if env_user_name_attr and hasattr(user, env_user_name_attr):
|
||||
user_name_attr = env_user_name_attr
|
||||
else:
|
||||
user_name_attr = 'short_contact'
|
||||
|
||||
user_name = getattr(user, user_name_attr)
|
||||
return user_name
|
||||
|
||||
def _close_branch_before_merging(self, pull_request):
|
||||
repo_type = pull_request.target_repo.repo_type
|
||||
if repo_type == 'hg':
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ from rhodecode.lib.user_log_filter import user_log_filter
|
|||
from rhodecode.lib.utils import make_db_config
|
||||
from rhodecode.lib.utils2 import (
|
||||
safe_str, safe_unicode, remove_prefix, obfuscate_url_pw,
|
||||
get_current_rhodecode_user, safe_int, datetime_to_time,
|
||||
action_logger_generic)
|
||||
get_current_rhodecode_user, safe_int, action_logger_generic)
|
||||
from rhodecode.lib.vcs.backends import get_backend
|
||||
from rhodecode.model import BaseModel
|
||||
from rhodecode.model.db import (
|
||||
|
|
@ -199,9 +198,11 @@ class RepoModel(BaseModel):
|
|||
|
||||
def get_repos_as_dict(self, repo_list=None, admin=False,
|
||||
super_user_actions=False, short_name=None):
|
||||
|
||||
_render = get_current_request().get_partial_renderer(
|
||||
'rhodecode:templates/data_table/_dt_elements.mako')
|
||||
c = _render.get_call_context()
|
||||
h = _render.get_helpers()
|
||||
|
||||
def quick_menu(repo_name):
|
||||
return _render('quick_menu', repo_name)
|
||||
|
|
@ -258,7 +259,7 @@ class RepoModel(BaseModel):
|
|||
"name": repo_lnk(repo.repo_name, repo.repo_type, repo.repo_state,
|
||||
repo.private, repo.archived, repo.fork),
|
||||
|
||||
"desc": desc(repo.description),
|
||||
"desc": desc(h.escape(repo.description)),
|
||||
|
||||
"last_change": last_change(repo.updated_on),
|
||||
|
||||
|
|
@ -619,13 +620,26 @@ class RepoModel(BaseModel):
|
|||
changes = {
|
||||
'added': [],
|
||||
'updated': [],
|
||||
'deleted': []
|
||||
'deleted': [],
|
||||
'default_user_changed': None
|
||||
}
|
||||
|
||||
repo = self._get_repo(repo)
|
||||
|
||||
# update permissions
|
||||
for member_id, perm, member_type in perm_updates:
|
||||
member_id = int(member_id)
|
||||
if member_type == 'user':
|
||||
member_name = User.get(member_id).username
|
||||
if member_name == User.DEFAULT_USER:
|
||||
# NOTE(dan): detect if we changed permissions for default user
|
||||
perm_obj = self.sa.query(UserRepoToPerm) \
|
||||
.filter(UserRepoToPerm.user_id == member_id) \
|
||||
.filter(UserRepoToPerm.repository == repo) \
|
||||
.scalar()
|
||||
if perm_obj and perm_obj.permission.permission_name != perm:
|
||||
changes['default_user_changed'] = True
|
||||
|
||||
# this updates also current one if found
|
||||
self.grant_user_permission(
|
||||
repo=repo, user=member_id, perm=perm)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ from rhodecode.model.db import (_hash_key, func, or_, in_filter_generator,
|
|||
UserGroup, Repository)
|
||||
from rhodecode.model.settings import VcsSettingsModel, SettingsModel
|
||||
from rhodecode.lib.caching_query import FromCache
|
||||
from rhodecode.lib.utils2 import action_logger_generic, datetime_to_time
|
||||
from rhodecode.lib.utils2 import action_logger_generic
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -353,7 +353,8 @@ class RepoGroupModel(BaseModel):
|
|||
changes = {
|
||||
'added': [],
|
||||
'updated': [],
|
||||
'deleted': []
|
||||
'deleted': [],
|
||||
'default_user_changed': None
|
||||
}
|
||||
|
||||
def _set_perm_user(obj, user, perm):
|
||||
|
|
@ -430,6 +431,15 @@ class RepoGroupModel(BaseModel):
|
|||
member_id = int(member_id)
|
||||
if member_type == 'user':
|
||||
member_name = User.get(member_id).username
|
||||
if isinstance(obj, RepoGroup) and obj == repo_group and member_name == User.DEFAULT_USER:
|
||||
# NOTE(dan): detect if we changed permissions for default user
|
||||
perm_obj = self.sa.query(UserRepoGroupToPerm) \
|
||||
.filter(UserRepoGroupToPerm.user_id == member_id) \
|
||||
.filter(UserRepoGroupToPerm.group == repo_group) \
|
||||
.scalar()
|
||||
if perm_obj and perm_obj.permission.permission_name != perm:
|
||||
changes['default_user_changed'] = True
|
||||
|
||||
# this updates also current one if found
|
||||
_set_perm_user(obj, user=member_id, perm=perm)
|
||||
elif member_type == 'user_group':
|
||||
|
|
@ -698,8 +708,6 @@ class RepoGroupModel(BaseModel):
|
|||
for repo_group in repo_groups:
|
||||
repo_group.update_commit_cache()
|
||||
|
||||
|
||||
|
||||
def get_repo_groups_as_dict(self, repo_group_list=None, admin=False,
|
||||
super_user_actions=False):
|
||||
|
||||
|
|
@ -753,7 +761,7 @@ class RepoGroupModel(BaseModel):
|
|||
"last_changeset": "",
|
||||
"last_changeset_raw": "",
|
||||
|
||||
"desc": desc(group.group_description, group.personal),
|
||||
"desc": desc(h.escape(group.group_description), group.personal),
|
||||
"top_level_repos": 0,
|
||||
"owner": user_profile(group.User.username)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@
|
|||
import os
|
||||
import hashlib
|
||||
import logging
|
||||
import re
|
||||
from collections import namedtuple
|
||||
from functools import wraps
|
||||
import bleach
|
||||
from pyramid.threadlocal import get_current_request, get_current_registry
|
||||
|
||||
from rhodecode.lib import rc_cache
|
||||
from rhodecode.lib.utils2 import (
|
||||
|
|
@ -210,7 +212,23 @@ class SettingsModel(BaseModel):
|
|||
invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE
|
||||
CacheKey.set_invalidate(invalidation_namespace)
|
||||
|
||||
def get_all_settings(self, cache=False):
|
||||
def get_all_settings(self, cache=False, from_request=True):
|
||||
from rhodecode.authentication.base import get_authn_registry
|
||||
|
||||
# defines if we use GLOBAL, or PER_REPO
|
||||
repo = self._get_repo(self.repo) if self.repo else None
|
||||
key = "settings_repo.{}".format(repo.repo_id) if repo else "settings_app"
|
||||
|
||||
# initially try the requests context, this is the fastest
|
||||
# we only fetch global config
|
||||
if from_request:
|
||||
request = get_current_request()
|
||||
|
||||
if request and not repo and hasattr(request, 'call_context') and hasattr(request.call_context, 'rc_config'):
|
||||
rc_config = request.call_context.rc_config
|
||||
if rc_config:
|
||||
return rc_config
|
||||
|
||||
region = rc_cache.get_or_create_region('sql_cache_short')
|
||||
invalidation_namespace = CacheKey.SETTINGS_INVALIDATION_NAMESPACE
|
||||
|
||||
|
|
@ -226,9 +244,6 @@ class SettingsModel(BaseModel):
|
|||
}
|
||||
return settings
|
||||
|
||||
repo = self._get_repo(self.repo) if self.repo else None
|
||||
key = "settings_repo.{}".format(repo.repo_id) if repo else "settings_app"
|
||||
|
||||
inv_context_manager = rc_cache.InvalidationContext(
|
||||
uid='cache_settings', invalidation_namespace=invalidation_namespace)
|
||||
with inv_context_manager as invalidation_context:
|
||||
|
|
@ -240,6 +255,11 @@ class SettingsModel(BaseModel):
|
|||
# are anyway very short lived and it's a safest way.
|
||||
region = rc_cache.get_or_create_region('sql_cache_short')
|
||||
region.invalidate()
|
||||
registry = get_current_registry()
|
||||
if registry:
|
||||
authn_registry = get_authn_registry(registry)
|
||||
if authn_registry:
|
||||
authn_registry.invalidate_plugins_for_auth()
|
||||
|
||||
result = _get_all_settings('rhodecode_settings', key)
|
||||
log.debug('Fetching app settings for key: %s took: %.4fs', key,
|
||||
|
|
@ -360,9 +380,15 @@ class IssueTrackerSettingsModel(object):
|
|||
for uid in issuetracker_entries:
|
||||
url_data = qs.get(self._get_keyname('url', uid, 'rhodecode_'))
|
||||
|
||||
pat = qs.get(self._get_keyname('pat', uid, 'rhodecode_'))
|
||||
try:
|
||||
pat_compiled = re.compile(r'%s' % pat)
|
||||
except re.error:
|
||||
pat_compiled = None
|
||||
|
||||
issuetracker_entries[uid] = AttributeDict({
|
||||
'pat': qs.get(
|
||||
self._get_keyname('pat', uid, 'rhodecode_')),
|
||||
'pat': pat,
|
||||
'pat_compiled': pat_compiled,
|
||||
'url': url_cleaner(
|
||||
qs.get(self._get_keyname('url', uid, 'rhodecode_')) or ''),
|
||||
'pref': bleach.clean(
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ log = logging.getLogger(__name__)
|
|||
|
||||
class SshKeyModel(BaseModel):
|
||||
cls = UserSshKeys
|
||||
DEFAULT_PRIVATE_KEY_FORMAT = 'pkcs8'
|
||||
|
||||
def parse_key(self, key_data):
|
||||
"""
|
||||
|
|
@ -66,16 +67,23 @@ class SshKeyModel(BaseModel):
|
|||
log.error("Key Parse error: %s", err)
|
||||
raise
|
||||
|
||||
def generate_keypair(self, comment=None):
|
||||
def generate_keypair(self, comment=None, private_format=DEFAULT_PRIVATE_KEY_FORMAT):
|
||||
|
||||
key = rsa.generate_private_key(
|
||||
backend=crypto_default_backend(),
|
||||
public_exponent=65537,
|
||||
key_size=2048
|
||||
)
|
||||
if private_format == self.DEFAULT_PRIVATE_KEY_FORMAT:
|
||||
private_format = crypto_serialization.PrivateFormat.PKCS8
|
||||
else:
|
||||
# legacy format that can be used by older systems, use if pkcs8 have
|
||||
# problems
|
||||
private_format = crypto_serialization.PrivateFormat.TraditionalOpenSSL
|
||||
|
||||
private_key = key.private_bytes(
|
||||
crypto_serialization.Encoding.PEM,
|
||||
crypto_serialization.PrivateFormat.PKCS8,
|
||||
private_format,
|
||||
crypto_serialization.NoEncryption())
|
||||
public_key = key.public_key().public_bytes(
|
||||
crypto_serialization.Encoding.OpenSSH,
|
||||
|
|
|
|||
|
|
@ -134,14 +134,11 @@ div.markdown-block h2 {
|
|||
div.markdown-block h1 {
|
||||
font-size: 32px;
|
||||
margin: 15px 0 15px 0 !important;
|
||||
padding-bottom: 5px !important;
|
||||
}
|
||||
|
||||
div.markdown-block h2 {
|
||||
font-size: 24px !important;
|
||||
margin: 34px 0 10px 0 !important;
|
||||
padding-top: 15px !important;
|
||||
padding-bottom: 8px !important;
|
||||
}
|
||||
|
||||
div.markdown-block h3 {
|
||||
|
|
@ -174,6 +171,21 @@ div.markdown-block hr {
|
|||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
div.markdown-block blockquote {
|
||||
color: #424242 !important;
|
||||
padding: 8px 21px;
|
||||
margin: 12px 0;
|
||||
border-left: 4px solid @grey6;
|
||||
}
|
||||
|
||||
div.markdown-block blockquote p {
|
||||
color: #424242 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
div.markdown-block ol,
|
||||
div.markdown-block ul,
|
||||
div.markdown-block p,
|
||||
|
|
@ -181,13 +193,11 @@ div.markdown-block blockquote,
|
|||
div.markdown-block dl,
|
||||
div.markdown-block li,
|
||||
div.markdown-block table {
|
||||
margin: 3px 0px 13px 0px !important;
|
||||
color: #424242 !important;
|
||||
font-size: 13px !important;
|
||||
font-family: @text-regular;
|
||||
font-weight: normal !important;
|
||||
overflow: visible !important;
|
||||
line-height: 140% !important;
|
||||
}
|
||||
|
||||
div.markdown-block pre {
|
||||
|
|
@ -245,14 +255,6 @@ div.markdown-block ol li {
|
|||
list-style: decimal !important;
|
||||
}
|
||||
|
||||
/*
|
||||
div.markdown-block a,
|
||||
div.markdown-block a:visited {
|
||||
color: #4183C4 !important;
|
||||
background-color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
*/
|
||||
|
||||
div.markdown-block #message {
|
||||
.border-radius(@border-radius);
|
||||
|
|
|
|||
|
|
@ -87,6 +87,10 @@ body {
|
|||
border-left: @border-thickness solid @border-default-color;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input + .action-link, .action-link.first{
|
||||
border-left: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@
|
|||
.readme-title {
|
||||
border: 1px solid @grey6;
|
||||
padding: 10px 5px;
|
||||
font-weight: 600;
|
||||
margin-top: 30px;
|
||||
margin-bottom: -1px;
|
||||
|
||||
a {
|
||||
font-weight: 600;
|
||||
font-size: 13px
|
||||
}
|
||||
}
|
||||
|
||||
div.readme_box {
|
||||
|
|
@ -34,14 +38,11 @@ div.readme_box h2 {
|
|||
div.readme_box h1 {
|
||||
font-size: 32px;
|
||||
margin: 15px 0 15px 0 !important;
|
||||
padding-bottom: 5px !important;
|
||||
}
|
||||
|
||||
div.readme_box h2 {
|
||||
font-size: 24px !important;
|
||||
margin: 34px 0 10px 0 !important;
|
||||
padding-top: 15px !important;
|
||||
padding-bottom: 8px !important;
|
||||
}
|
||||
|
||||
div.readme_box h3 {
|
||||
|
|
@ -74,6 +75,20 @@ div.readme_box hr {
|
|||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
div.readme_box blockquote {
|
||||
color: #424242 !important;
|
||||
padding: 8px 21px;
|
||||
margin: 12px 0;
|
||||
border-left: 4px solid @grey6;
|
||||
}
|
||||
|
||||
div.readme_box blockquote p {
|
||||
color: #424242 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
div.readme_box ol,
|
||||
div.readme_box ul,
|
||||
div.readme_box p,
|
||||
|
|
@ -81,13 +96,11 @@ div.readme_box blockquote,
|
|||
div.readme_box dl,
|
||||
div.readme_box li,
|
||||
div.readme_box table {
|
||||
margin: 3px 0px 13px 0px !important;
|
||||
color: #424242 !important;
|
||||
font-size: 13px !important;
|
||||
font-family: @text-regular;
|
||||
font-weight: normal !important;
|
||||
overflow: visible !important;
|
||||
line-height: 140% !important;
|
||||
}
|
||||
|
||||
div.readme_box pre {
|
||||
|
|
|
|||
|
|
@ -373,6 +373,17 @@ table#repo_list_table {
|
|||
min-width: 600px;
|
||||
}
|
||||
|
||||
#no_grid_data {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#grid_data_loading {
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
padding: 80px 20px;
|
||||
}
|
||||
|
||||
// Keyboard mappings
|
||||
table.keyboard-mappings {
|
||||
th {
|
||||
|
|
@ -538,5 +549,12 @@ table.compare_view_commits {
|
|||
img{
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&.td-expire {
|
||||
width: 200px;
|
||||
}
|
||||
&.td-gist-type {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ address {
|
|||
}
|
||||
|
||||
.help-block-inline {
|
||||
margin: 0;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
// help block text
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Follow',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': 'Lifetime',
|
||||
'Loading ...': 'Loading ...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'No matching files',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'No results',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Follow',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': 'Lebensdauer',
|
||||
'Loading ...': 'Loading ...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'No matching files',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'No results',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Follow',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': 'Lifetime',
|
||||
'Loading ...': 'Loading ...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'No matching files',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'No results',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Follow',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': 'De por vida',
|
||||
'Loading ...': 'Loading ...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'No matching files',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'No results',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Follow',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': 'Durée de vie',
|
||||
'Loading ...': 'Loading ...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'No matching files',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'No results',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} mois',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Segui',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': 'a vita',
|
||||
'Loading ...': 'Caricamento ...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'Nessuna corrispondenza tra i file',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'Nessun risultato',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': '選択したステータス ({0}) を元にコメントが自動的に設定されます...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'フォロー',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': '有効期間',
|
||||
'Loading ...': '読み込み中...',
|
||||
'Loading failed': '読み込み失敗',
|
||||
'Loading more results...': '結果を読み込み中...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'まだブックマークがありません。',
|
||||
'No branches available yet.': 'まだブランチがありません。',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'マッチするファイルはありません',
|
||||
'No pull requests available yet.': 'まだプルリクエストがありません。',
|
||||
'No repositories available yet.': 'まだリポジトリがありません。',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'まだリポジトリグループがありません。',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': '結果がありません',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'まだタグがありません。',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} 分',
|
||||
'{0} month': '{0} ヶ月',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} 件の結果があります。矢印キーの上下で選択できます。',
|
||||
'{0} sec': '{0} 秒',
|
||||
|
|
|
|||
|
|
@ -5,28 +5,38 @@ _gettext('Adding new reviewers is forbidden.');
|
|||
_gettext('All Authors');
|
||||
_gettext('All individual reviewers must vote.');
|
||||
_gettext('All reviewers must vote.');
|
||||
_gettext('Are you sure to close this pull request without merging?');
|
||||
_gettext('At least {0} reviewer must vote.');
|
||||
_gettext('At least {0} reviewers must vote.');
|
||||
_gettext('Author is not allowed to be a reviewer.');
|
||||
_gettext('Changed files');
|
||||
_gettext('Close');
|
||||
_gettext('Collapse all files');
|
||||
_gettext('Collapse {0} commit');
|
||||
_gettext('Collapse {0} commits');
|
||||
_gettext('Comment text will be set automatically based on currently selected status ({0}) ...');
|
||||
_gettext('Commit Authors are not allowed to be a reviewer.');
|
||||
_gettext('Context file: ');
|
||||
_gettext('Delete this comment?');
|
||||
_gettext('Diff to Commit ');
|
||||
_gettext('Expand all files');
|
||||
_gettext('Expand {0} commit');
|
||||
_gettext('Expand {0} commits');
|
||||
_gettext('Fetching repository state failed. Error code: {0} {1}. Try <a href="{2}">refreshing</a> this page.');
|
||||
_gettext('Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.');
|
||||
_gettext('Follow');
|
||||
_gettext('Force updating...');
|
||||
_gettext('Hide full context diff');
|
||||
_gettext('Hide whitespace changes');
|
||||
_gettext('Invite reviewers to this discussion');
|
||||
_gettext('Leave a comment on line {0}.');
|
||||
_gettext('Leave a comment, or click resolve button to resolve TODO comment #{0}');
|
||||
_gettext('Leave a resolution comment, or click resolve button to resolve TODO comment #{0}');
|
||||
_gettext('Lifetime');
|
||||
_gettext('Loading ...');
|
||||
_gettext('Loading failed');
|
||||
_gettext('Loading more results...');
|
||||
_gettext('Loading...');
|
||||
_gettext('No bookmarks available yet.');
|
||||
_gettext('No branches available yet.');
|
||||
_gettext('No forks available yet.');
|
||||
|
|
@ -35,7 +45,9 @@ _gettext('No matches found');
|
|||
_gettext('No matching files');
|
||||
_gettext('No pull requests available yet.');
|
||||
_gettext('No repositories available yet.');
|
||||
_gettext('No repositories present.');
|
||||
_gettext('No repository groups available yet.');
|
||||
_gettext('No repository groups present.');
|
||||
_gettext('No results');
|
||||
_gettext('No ssh keys available yet.');
|
||||
_gettext('No tags available yet.');
|
||||
|
|
@ -119,9 +131,11 @@ _gettext('{0} hours');
|
|||
_gettext('{0} min');
|
||||
_gettext('{0} month');
|
||||
_gettext('{0} months');
|
||||
_gettext('{0} of {1} repositories');
|
||||
_gettext('{0} of {1} repository groups');
|
||||
_gettext('{0} out of {1} ssh keys');
|
||||
_gettext('{0} out of {1} users');
|
||||
_gettext('{0} repositories');
|
||||
_gettext('{0} repository groups');
|
||||
_gettext('{0} results are available, use up and down arrow keys to navigate.');
|
||||
_gettext('{0} sec');
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Zamknij',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Obserwuj',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': 'Czas życia',
|
||||
'Loading ...': 'Ładuję...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'Nie ma plików pasujących',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'No results',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Seguir',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': 'Tempo de Vida',
|
||||
'Loading ...': 'Carregando...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'Nenhum arquivo encontrado',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'No results',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Наблюдать',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': 'Срок',
|
||||
'Loading ...': 'Загрузка...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'Нет совпадений',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'No results',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -11,28 +11,38 @@ var _TM = {
|
|||
'All Authors': 'All Authors',
|
||||
'All individual reviewers must vote.': 'All individual reviewers must vote.',
|
||||
'All reviewers must vote.': 'All reviewers must vote.',
|
||||
'Are you sure to close this pull request without merging?': 'Are you sure to close this pull request without merging?',
|
||||
'At least {0} reviewer must vote.': 'At least {0} reviewer must vote.',
|
||||
'At least {0} reviewers must vote.': 'At least {0} reviewers must vote.',
|
||||
'Author is not allowed to be a reviewer.': 'Author is not allowed to be a reviewer.',
|
||||
'Changed files': 'Changed files',
|
||||
'Close': 'Close',
|
||||
'Collapse all files': 'Collapse all files',
|
||||
'Collapse {0} commit': 'Collapse {0} commit',
|
||||
'Collapse {0} commits': 'Collapse {0} commits',
|
||||
'Comment text will be set automatically based on currently selected status ({0}) ...': 'Comment text will be set automatically based on currently selected status ({0}) ...',
|
||||
'Commit Authors are not allowed to be a reviewer.': 'Commit Authors are not allowed to be a reviewer.',
|
||||
'Context file: ': 'Context file: ',
|
||||
'Delete this comment?': 'Delete this comment?',
|
||||
'Diff to Commit ': 'Diff to Commit ',
|
||||
'Expand all files': 'Expand all files',
|
||||
'Expand {0} commit': 'Expand {0} commit',
|
||||
'Expand {0} commits': 'Expand {0} commits',
|
||||
'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.',
|
||||
'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.': 'Fetching repository state failed. Error code: {0} {1}. Try refreshing this page.',
|
||||
'Follow': 'Follow',
|
||||
'Force updating...': 'Force updating...',
|
||||
'Hide full context diff': 'Hide full context diff',
|
||||
'Hide whitespace changes': 'Hide whitespace changes',
|
||||
'Invite reviewers to this discussion': 'Invite reviewers to this discussion',
|
||||
'Leave a comment on line {0}.': 'Leave a comment on line {0}.',
|
||||
'Leave a comment, or click resolve button to resolve TODO comment #{0}': 'Leave a comment, or click resolve button to resolve TODO comment #{0}',
|
||||
'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}',
|
||||
'Lifetime': '终身',
|
||||
'Loading ...': 'Loading ...',
|
||||
'Loading failed': 'Loading failed',
|
||||
'Loading more results...': 'Loading more results...',
|
||||
'Loading...': 'Loading...',
|
||||
'No bookmarks available yet.': 'No bookmarks available yet.',
|
||||
'No branches available yet.': 'No branches available yet.',
|
||||
'No forks available yet.': 'No forks available yet.',
|
||||
|
|
@ -41,7 +51,9 @@ var _TM = {
|
|||
'No matching files': 'No matching files',
|
||||
'No pull requests available yet.': 'No pull requests available yet.',
|
||||
'No repositories available yet.': 'No repositories available yet.',
|
||||
'No repositories present.': 'No repositories present.',
|
||||
'No repository groups available yet.': 'No repository groups available yet.',
|
||||
'No repository groups present.': 'No repository groups present.',
|
||||
'No results': 'No results',
|
||||
'No ssh keys available yet.': 'No ssh keys available yet.',
|
||||
'No tags available yet.': 'No tags available yet.',
|
||||
|
|
@ -125,9 +137,11 @@ var _TM = {
|
|||
'{0} min': '{0} min',
|
||||
'{0} month': '{0} month',
|
||||
'{0} months': '{0} months',
|
||||
'{0} of {1} repositories': '{0} of {1} repositories',
|
||||
'{0} of {1} repository groups': '{0} of {1} repository groups',
|
||||
'{0} out of {1} ssh keys': '{0} out of {1} ssh keys',
|
||||
'{0} out of {1} users': '{0} out of {1} users',
|
||||
'{0} repositories': '{0} repositories',
|
||||
'{0} repository groups': '{0} repository groups',
|
||||
'{0} results are available, use up and down arrow keys to navigate.': '{0} results are available, use up and down arrow keys to navigate.',
|
||||
'{0} sec': '{0} sec',
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ function registerRCRoutes() {
|
|||
pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
|
||||
pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
|
||||
pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
|
||||
pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
|
||||
pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
|
||||
pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
|
||||
pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
|
||||
|
|
|
|||
|
|
@ -299,6 +299,10 @@ var tooltipActivate = function () {
|
|||
var altHovercard =$origin.data('hovercardAlt');
|
||||
|
||||
if (hovercardUrl !== undefined && hovercardUrl !== "") {
|
||||
if (hovercardUrl.substr(0,12) === 'pyroutes.url'){
|
||||
hovercardUrl = eval(hovercardUrl)
|
||||
}
|
||||
|
||||
var loaded = loadHoverCard(hovercardUrl, altHovercard, function (data) {
|
||||
instance.content(data);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ $(document).ready(function() {
|
|||
{ data: {"_": "author",
|
||||
"sort": "author_raw"}, title: "${_("Author")}", width: "250px", className: "td-user" },
|
||||
{ data: {"_": "type",
|
||||
"sort": "type"}, title: "${_("Type")}", width: "70px", className: "td-tags" },
|
||||
"sort": "type"}, title: "${_("Type")}", width: "100px", className: "td-gist-type" },
|
||||
{ data: {"_": "access_id",
|
||||
"sort": "access_id"}, title: "${_("Name")}", width:"150px", className: "td-componentname" },
|
||||
{ data: {"_": "description",
|
||||
|
|
@ -110,7 +110,7 @@ $(document).ready(function() {
|
|||
{ data: {"_": "created_on",
|
||||
"sort": "created_on_raw"}, title: "${_("Created on")}", className: "td-time" },
|
||||
{ data: {"_": "expires",
|
||||
"sort": "expires"}, title: "${_("Expires")}", className: "td-exp" }
|
||||
"sort": "expires"}, title: "${_("Expires")}", width: "200px", className: "td-expire" }
|
||||
],
|
||||
language: {
|
||||
paginate: DEFAULT_GRID_PAGINATION,
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@
|
|||
<div class="input">
|
||||
${h.text('description', class_='medium', placeholder=_('Description'))}
|
||||
${h.hidden('lifetime')}
|
||||
${h.select('role', '', c.role_options)}
|
||||
${h.select('role', request.GET.get('token_role', ''), c.role_options)}
|
||||
|
||||
% if c.allow_scoped_tokens:
|
||||
${h.hidden('scope_repo_id')}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
% if c.extern_type != 'rhodecode':
|
||||
<p>${_('Your user account details are managed by an external source. Details cannot be managed here.')}
|
||||
<br/>${_('Source type')}: <strong>${c.extern_type}</strong>
|
||||
<br/>${_('For VCS access please generate')}
|
||||
<a href="${h.route_path('my_account_auth_tokens', _query={'token_role':'token_role_vcs'})}">Authentication Token</a> or <a href="${h.route_path('my_account_ssh_keys_generate')}">SSH Key</a>.
|
||||
<br/>${_('Source type')}: <strong>${c.extern_type}</strong>
|
||||
</p>
|
||||
% else:
|
||||
${c.form.render() | n}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,17 @@
|
|||
</div>
|
||||
|
||||
<div class="panel-body fields">
|
||||
%if c.extern_type != 'rhodecode':
|
||||
<% readonly = "readonly" %>
|
||||
<% disabled = " disabled" %>
|
||||
<div class="alert-warning" style="margin:0px 0px 20px 0px; padding: 10px">
|
||||
<strong>${_('This user was created from external source (%s). Editing some of the settings is limited.' % c.extern_type)}</strong>
|
||||
</div>
|
||||
<div style="margin:-10px 0px 20px 0px;">
|
||||
${_('For VCS access please generate')}
|
||||
<a href="${h.route_path('my_account_auth_tokens', _query={'token_role':'token_role_vcs'})}">Authentication Token</a> or <a href="${h.route_path('my_account_ssh_keys_generate')}">SSH Key</a>.
|
||||
</div>
|
||||
%endif
|
||||
<div class="field">
|
||||
<div class="label">
|
||||
${_('Photo')}:
|
||||
|
|
|
|||
|
|
@ -11,13 +11,19 @@
|
|||
|
||||
%if c.extern_type != 'rhodecode':
|
||||
<% readonly = "readonly" %>
|
||||
<% disabled = "disabled" %>
|
||||
<% disabled = " disabled" %>
|
||||
<div class="alert-warning" style="margin:0px 0px 20px 0px; padding: 10px">
|
||||
<strong>${_('This user was created from external source (%s). Editing some of the settings is limited.' % c.extern_type)}</strong>
|
||||
</div>
|
||||
<div style="margin:-10px 0px 20px 0px;">
|
||||
${_('For VCS access please generate')}
|
||||
<a href="${h.route_path('my_account_auth_tokens', _query={'token_role':'token_role_vcs'})}">Authentication Token</a> or <a href="${h.route_path('my_account_ssh_keys_generate')}">SSH Key</a>.
|
||||
</div>
|
||||
%endif
|
||||
|
||||
%if c.extern_type != 'rhodecode':
|
||||
<div class="infoform">
|
||||
<div class="fields">
|
||||
<p>${_('Your user account details are managed by an external source. Details cannot be managed here.')}
|
||||
<br/>${_('Source type')}: <strong>${c.extern_type}</strong>
|
||||
</p>
|
||||
|
||||
<div class="field">
|
||||
<div class="label">
|
||||
<label for="username">${_('Username')}:</label>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,13 @@
|
|||
<div class="textarea editor">
|
||||
${h.textarea('group_description',cols=23,rows=5,class_="medium")}
|
||||
<% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
|
||||
<span class="help-block">${_('Plain text format with support of {metatags}').format(metatags=metatags_url)|n}</span>
|
||||
<span class="help-block">
|
||||
% if c.visual.stylify_metatags:
|
||||
${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n}
|
||||
% else:
|
||||
${_('Plain text format.')}
|
||||
% endif
|
||||
</span>
|
||||
<span id="meta-tags-desc" style="display: none">
|
||||
<%namespace name="dt" file="/data_table/_dt_elements.mako"/>
|
||||
${dt.metatags_help()}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
<div class="sidebar">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li class="${h.is_active('settings', c.active)}"><a href="${h.route_path('edit_repo_group', repo_group_name=c.repo_group.group_name)}">${_('Settings')}</a></li>
|
||||
<li class="${h.is_active('permissions', c.active)}"><a href="${h.route_path('edit_repo_group_perms', repo_group_name=c.repo_group.group_name)}">${_('Permissions')}</a></li>
|
||||
<li class="${h.is_active('permissions', c.active)}"><a href="${h.route_path('edit_repo_group_perms', repo_group_name=c.repo_group.group_name)}">${_('Access Permissions')}</a></li>
|
||||
<li class="${h.is_active('advanced', c.active)}"><a href="${h.route_path('edit_repo_group_advanced', repo_group_name=c.repo_group.group_name)}">${_('Advanced')}</a></li>
|
||||
<li class="${h.is_active('integrations', c.active)}"><a href="${h.route_path('repo_group_integrations_home', repo_group_name=c.repo_group.group_name)}">${_('Integrations')}</a></li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,12 @@
|
|||
${base.gravatar(_user.email, 16, user=_user, tooltip=True)}
|
||||
<span class="user">
|
||||
% if _user.username == h.DEFAULT_USER:
|
||||
${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
|
||||
${h.DEFAULT_USER}
|
||||
% if _user.active:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span>
|
||||
% else:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span>
|
||||
% endif
|
||||
% else:
|
||||
${h.link_to_user(_user.username)}
|
||||
%if getattr(_user, 'duplicate_perm', None):
|
||||
|
|
@ -104,7 +109,12 @@
|
|||
${base.gravatar(_user.email, 16, user=_user, tooltip=True)}
|
||||
<span class="user">
|
||||
% if _user.username == h.DEFAULT_USER:
|
||||
${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
|
||||
${h.DEFAULT_USER}
|
||||
% if _user.active:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span>
|
||||
% else:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span>
|
||||
% endif
|
||||
% else:
|
||||
${h.link_to_user(_user.username)}
|
||||
%if getattr(_user, 'duplicate_perm', None):
|
||||
|
|
|
|||
|
|
@ -59,7 +59,13 @@
|
|||
${c.form.render_error(request, c.form['repo_group_description'])|n}
|
||||
|
||||
<% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
|
||||
<span class="help-block">${_('Plain text format with support of {metatags}').format(metatags=metatags_url)|n}</span>
|
||||
<span class="help-block">
|
||||
% if c.visual.stylify_metatags:
|
||||
${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n}
|
||||
% else:
|
||||
${_('Plain text format.')}
|
||||
% endif
|
||||
</span>
|
||||
<span id="meta-tags-desc" style="display: none">
|
||||
<%namespace name="dt" file="/data_table/_dt_elements.mako"/>
|
||||
${dt.metatags_help()}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,14 @@ ${h.secure_form(h.route_path('repo_create'), request=request)}
|
|||
<div class="textarea editor">
|
||||
${h.textarea('repo_description',cols=23,rows=5,class_="medium")}
|
||||
<% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
|
||||
<span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span>
|
||||
<span class="help-block">
|
||||
% if c.visual.stylify_metatags:
|
||||
${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n}
|
||||
% else:
|
||||
${_('Plain text format.')}
|
||||
% endif
|
||||
${_('Add a README file for longer descriptions')}
|
||||
</span>
|
||||
<span id="meta-tags-desc" style="display: none">
|
||||
<%namespace name="dt" file="/data_table/_dt_elements.mako"/>
|
||||
${dt.metatags_help()}
|
||||
|
|
|
|||
|
|
@ -23,43 +23,48 @@
|
|||
<div class="panel-heading">
|
||||
<h3 class="panel-title">${_('Inherited Issue Tracker Patterns')}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="rctable issuetracker readonly">
|
||||
<tr>
|
||||
<th>${_('Description')}</th>
|
||||
<th>${_('Pattern')}</th>
|
||||
<th>${_('Url')}</th>
|
||||
<th>${_('Prefix')}</th>
|
||||
<th ></th>
|
||||
</tr>
|
||||
%for uid, entry in c.global_patterns.items():
|
||||
<tr id="${uid}">
|
||||
<td class="td-description issuetracker_desc">
|
||||
<span class="entry">
|
||||
${entry.desc}
|
||||
</span>
|
||||
</td>
|
||||
<td class="td-regex issuetracker_pat">
|
||||
<span class="entry">
|
||||
${entry.pat}
|
||||
</span>
|
||||
</td>
|
||||
<td class="td-url issuetracker_url">
|
||||
<span class="entry">
|
||||
${entry.url}
|
||||
</span>
|
||||
</td>
|
||||
<td class="td-prefix issuetracker_pref">
|
||||
<span class="entry">
|
||||
${entry.pref}
|
||||
</span>
|
||||
</td>
|
||||
<td class="td-action">
|
||||
</td>
|
||||
</tr>
|
||||
%endfor
|
||||
|
||||
</table>
|
||||
<div class="panel-body">
|
||||
<table class="rctable issuetracker readonly">
|
||||
<tr>
|
||||
<th>${_('Description')}</th>
|
||||
<th>${_('Pattern')}</th>
|
||||
<th>${_('Url')}</th>
|
||||
<th>${_('Prefix')}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
% for uid, entry in c.global_patterns.items():
|
||||
<tr id="${uid}">
|
||||
<td class="td-description issuetracker_desc">
|
||||
<span class="entry">
|
||||
${entry.desc}
|
||||
</span>
|
||||
</td>
|
||||
<td class="td-regex issuetracker_pat">
|
||||
<span class="entry">
|
||||
${entry.pat}
|
||||
</span>
|
||||
</td>
|
||||
<td class="td-url issuetracker_url">
|
||||
<span class="entry">
|
||||
${entry.url}
|
||||
</span>
|
||||
</td>
|
||||
<td class="td-prefix issuetracker_pref">
|
||||
<span class="entry">
|
||||
${entry.pref}
|
||||
</span>
|
||||
</td>
|
||||
<td class="td-action">
|
||||
</td>
|
||||
</tr>
|
||||
% endfor
|
||||
|
||||
</table>
|
||||
<div class="buttons">
|
||||
<button type="submit" class="btn btn-primary save-inheritance" id="save">${_('Save')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -77,7 +82,6 @@
|
|||
)}
|
||||
<div class="buttons">
|
||||
<button type="submit" class="btn btn-primary save-inheritance" id="save">${_('Save')}</button>
|
||||
<button type="reset" class="btn reset-inheritance">${_('Reset')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -58,7 +58,11 @@
|
|||
<td class="private_repo_msg">
|
||||
${base.gravatar(h.DEFAULT_USER_EMAIL, 16)}
|
||||
${h.DEFAULT_USER} - ${_('only users/user groups explicitly added here will have access')}</td>
|
||||
<td></td>
|
||||
<td class="td-action">
|
||||
<span class="tooltip btn btn-link btn-default" onclick="setPrivateRepo(false); return false" title="${_('Private repositories are only visible to people explicitly added as collaborators. Default permissions wont apply')}">
|
||||
${_('un-set private mode')}
|
||||
</span>
|
||||
</td>
|
||||
<td class="quick_repo_menu">
|
||||
% if c.rhodecode_user.is_admin:
|
||||
<i class="icon-more"></i>
|
||||
|
|
@ -83,7 +87,12 @@
|
|||
${base.gravatar(_user.email, 16, user=_user, tooltip=True)}
|
||||
<span class="user">
|
||||
% if _user.username == h.DEFAULT_USER:
|
||||
${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
|
||||
${h.DEFAULT_USER}
|
||||
% if _user.active:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span>
|
||||
% else:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span>
|
||||
% endif
|
||||
% else:
|
||||
${h.link_to_user(_user.username)}
|
||||
%if getattr(_user, 'duplicate_perm', None):
|
||||
|
|
@ -106,7 +115,7 @@
|
|||
${_('Remove')}
|
||||
</span>
|
||||
%elif _user.username == h.DEFAULT_USER:
|
||||
<span class="tooltip btn btn-link btn-default" onclick="enablePrivateRepo(); return false" title="${_('Private repositories are only visible to people explicitly added as collaborators.')}">
|
||||
<span class="tooltip btn btn-link btn-default" onclick="setPrivateRepo(true); return false" title="${_('Private repositories are only visible to people explicitly added as collaborators. Default permissions wont apply')}">
|
||||
${_('set private mode')}
|
||||
</span>
|
||||
%endif
|
||||
|
|
@ -204,9 +213,10 @@
|
|||
});
|
||||
quick_repo_menu();
|
||||
|
||||
var enablePrivateRepo = function () {
|
||||
var setPrivateRepo = function (private) {
|
||||
var postData = {
|
||||
'csrf_token': CSRF_TOKEN
|
||||
'csrf_token': CSRF_TOKEN,
|
||||
'private': private
|
||||
};
|
||||
|
||||
var success = function(o) {
|
||||
|
|
|
|||
|
|
@ -174,7 +174,14 @@
|
|||
${c.form.render_error(request, c.form['repo_description'])|n}
|
||||
|
||||
<% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
|
||||
<span class="help-block">${_('Plain text format with support of {metatags}. Add a README file for longer descriptions').format(metatags=metatags_url)|n}</span>
|
||||
<span class="help-block">
|
||||
% if c.visual.stylify_metatags:
|
||||
${_('Plain text format with {metatags} support.').format(metatags=metatags_url)|n}
|
||||
% else:
|
||||
${_('Plain text format.')}
|
||||
% endif
|
||||
${_('Add a README file for longer descriptions')}
|
||||
</span>
|
||||
<span id="meta-tags-desc" style="display: none">
|
||||
<%namespace name="dt" file="/data_table/_dt_elements.mako"/>
|
||||
${dt.metatags_help()}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
<div id="update_notice" style="display: none; margin: -40px 0px 20px 0px">
|
||||
<div id="update_notice" style="display: none; margin: 0px 0px 30px 0px">
|
||||
<div>${_('Checking for updates...')}</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@
|
|||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3>
|
||||
<h3 class="panel-title">
|
||||
<i class="icon-user-group" title="${_('User group')}"></i>
|
||||
${h.link_to_group(c.user_group.users_group_name)}
|
||||
- ${_('Advanced')}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
${base.dt_info_panel(elems)}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@
|
|||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">${_('User Group Permissions')}</h3>
|
||||
<h3 class="panel-title">
|
||||
<i class="icon-user-group" title="${_('User group')}"></i>
|
||||
${h.link_to_group(c.user_group.users_group_name)}
|
||||
- ${_('Access Permissions')}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
${h.secure_form(h.route_path('edit_user_group_perms_update', user_group_id=c.user_group.users_group_id), request=request)}
|
||||
|
|
@ -63,7 +67,12 @@
|
|||
${base.gravatar(_user.email, 16, user=_user, tooltip=True)}
|
||||
<span class="user">
|
||||
% if _user.username == h.DEFAULT_USER:
|
||||
${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
|
||||
${h.DEFAULT_USER}
|
||||
% if _user.active:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span>
|
||||
% else:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span>
|
||||
% endif
|
||||
% else:
|
||||
${h.link_to_user(_user.username)}
|
||||
%if getattr(_user, 'duplicate_perm', None):
|
||||
|
|
@ -106,7 +115,12 @@
|
|||
${base.gravatar(_user.email, 16, user=_user, tooltip=True)}
|
||||
<span class="user">
|
||||
% if _user.username == h.DEFAULT_USER:
|
||||
${h.DEFAULT_USER} <span class="user-perm-help-text"> - ${_('permission for all other users')}</span>
|
||||
${h.DEFAULT_USER}
|
||||
% if _user.active:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span>
|
||||
% else:
|
||||
<span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span>
|
||||
% endif
|
||||
% else:
|
||||
${h.link_to_user(_user.username)}
|
||||
%if getattr(_user, 'duplicate_perm', None):
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue