release: Merge default into stable for release preparation
This commit is contained in:
commit
89d54f218a
334 changed files with 21428 additions and 5130 deletions
|
|
@ -1,5 +1,5 @@
|
|||
[bumpversion]
|
||||
current_version = 4.16.2
|
||||
current_version = 4.17.0
|
||||
message = release: Bump version {current_version} to {new_version}
|
||||
|
||||
[bumpversion:file:rhodecode/VERSION]
|
||||
|
|
|
|||
13
.release.cfg
13
.release.cfg
|
|
@ -5,26 +5,21 @@ done = false
|
|||
done = true
|
||||
|
||||
[task:rc_tools_pinned]
|
||||
done = true
|
||||
|
||||
[task:fixes_on_stable]
|
||||
done = true
|
||||
|
||||
[task:pip2nix_generated]
|
||||
done = true
|
||||
|
||||
[task:changelog_updated]
|
||||
done = true
|
||||
|
||||
[task:generate_api_docs]
|
||||
done = true
|
||||
|
||||
[release]
|
||||
state = prepared
|
||||
version = 4.16.2
|
||||
|
||||
[task:updated_translation]
|
||||
|
||||
[release]
|
||||
state = in_progress
|
||||
version = 4.17.0
|
||||
|
||||
[task:generate_js_routes]
|
||||
|
||||
[task:updated_trial_license]
|
||||
|
|
|
|||
9
Makefile
9
Makefile
|
|
@ -53,3 +53,12 @@ web-build:
|
|||
|
||||
generate-pkgs:
|
||||
nix-shell pkgs/shell-generate.nix --command "pip2nix generate --licenses"
|
||||
|
||||
generate-js-pkgs:
|
||||
rm -rf node_modules && \
|
||||
nix-shell pkgs/shell-generate.nix --command "node2nix --input package.json -o pkgs/node-packages.nix -e pkgs/node-env.nix -c pkgs/node-default.nix -d --flatten --nodejs-8" && \
|
||||
sed -i -e 's/http:\/\//https:\/\//g' pkgs/node-packages.nix
|
||||
|
||||
generate-license-meta:
|
||||
nix-build pkgs/license-generate.nix -o result-license && \
|
||||
cat result-license/licenses.json | python -m json.tool > rhodecode/config/licenses.json
|
||||
|
|
@ -133,6 +133,11 @@ rhodecode.api.url = /_admin/api
|
|||
## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
|
||||
#rhodecode.encrypted_values.strict = false
|
||||
|
||||
## Pick algorithm for encryption. Either fernet (more secure) or aes (default)
|
||||
## fernet is safer, and we strongly recommend switching to it.
|
||||
## Due to backward compatibility aes is used as default.
|
||||
#rhodecode.encrypted_values.algorithm = fernet
|
||||
|
||||
## return gzipped responses from RhodeCode (static files/application)
|
||||
gzip_responses = false
|
||||
|
||||
|
|
@ -374,6 +379,10 @@ rc_cache.cache_repo_longterm.max_size = 10000
|
|||
beaker.session.type = file
|
||||
beaker.session.data_dir = %(here)s/data/sessions
|
||||
|
||||
## redis sessions
|
||||
#beaker.session.type = ext:redis
|
||||
#beaker.session.url = redis://127.0.0.1:6379/2
|
||||
|
||||
## db based session, fast, and allows easy management over logged in users
|
||||
#beaker.session.type = ext:database
|
||||
#beaker.session.table_name = db_session
|
||||
|
|
|
|||
|
|
@ -30,10 +30,12 @@ loglevel = 'debug'
|
|||
# SECURITY
|
||||
|
||||
# The maximum size of HTTP request line in bytes.
|
||||
limit_request_line = 4094
|
||||
# 0 for unlimited
|
||||
limit_request_line = 0
|
||||
|
||||
# Limit the number of HTTP headers fields in a request.
|
||||
limit_request_fields = 1024
|
||||
# By default this value is 100 and can’t be larger than 32768.
|
||||
limit_request_fields = 10240
|
||||
|
||||
# Limit the allowed size of an HTTP request header field.
|
||||
# Value is a positive number or 0.
|
||||
|
|
|
|||
|
|
@ -108,6 +108,11 @@ use = egg:rhodecode-enterprise-ce
|
|||
## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
|
||||
#rhodecode.encrypted_values.strict = false
|
||||
|
||||
## Pick algorithm for encryption. Either fernet (more secure) or aes (default)
|
||||
## fernet is safer, and we strongly recommend switching to it.
|
||||
## Due to backward compatibility aes is used as default.
|
||||
#rhodecode.encrypted_values.algorithm = fernet
|
||||
|
||||
## return gzipped responses from RhodeCode (static files/application)
|
||||
gzip_responses = false
|
||||
|
||||
|
|
@ -349,6 +354,10 @@ rc_cache.cache_repo_longterm.max_size = 10000
|
|||
beaker.session.type = file
|
||||
beaker.session.data_dir = %(here)s/data/sessions
|
||||
|
||||
## redis sessions
|
||||
#beaker.session.type = ext:redis
|
||||
#beaker.session.url = redis://127.0.0.1:6379/2
|
||||
|
||||
## db based session, fast, and allows easy management over logged in users
|
||||
#beaker.session.type = ext:database
|
||||
#beaker.session.table_name = db_session
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ let
|
|||
# check required files
|
||||
STATIC_CHECK="/robots.txt /502.html
|
||||
/js/scripts.js /js/rhodecode-components.js
|
||||
/css/style.css /css/style-polymer.css"
|
||||
/css/style.css /css/style-polymer.css /css/style-ipython.css"
|
||||
|
||||
for file in $STATIC_CHECK;
|
||||
do
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
.. _repo-admin-set:
|
||||
.. _permissions-info-add-group-ref:
|
||||
|
||||
Repository Administration
|
||||
|
|
@ -18,9 +19,10 @@ settings for your needs:
|
|||
|
||||
.. toctree::
|
||||
|
||||
repo-perm-steps
|
||||
repo-extra-fields
|
||||
repo-hooks
|
||||
repo-issue-tracker
|
||||
repo-vcs
|
||||
|
||||
repo_admin/repo-perm-steps
|
||||
repo_admin/repo-extra-fields
|
||||
repo_admin/repo-hooks
|
||||
repo_admin/repo-issue-tracker
|
||||
repo_admin/repo-vcs
|
||||
repo_admin/restore-deleted-repositories
|
||||
repo_admin/repo-admin-tasks
|
||||
24
docs/admin/repo_admin/repo-admin-tasks.rst
Normal file
24
docs/admin/repo_admin/repo-admin-tasks.rst
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
.. _repo-admin-tasks:
|
||||
|
||||
Common Admin Tasks for Repositories
|
||||
-----------------------------------
|
||||
|
||||
|
||||
Manually Force Delete Repository
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In case of attached forks or pull-requests repositories should be archived.
|
||||
Here is how to force delete a repository and remove all dependent objects
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# starts the ishell interactive prompt
|
||||
$ rccontrol ishell enterprise-1
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
In [4]: from rhodecode.model.repo import RepoModel
|
||||
In [3]: repo = Repository.get_by_repo_name('test_repos/repo_with_prs')
|
||||
In [5]: RepoModel().delete(repo, forks='detach', pull_requests='delete')
|
||||
In [6]: Session().commit()
|
||||
|
|
@ -29,7 +29,7 @@ To configure extra fields per repository, use the following steps:
|
|||
beside the |repo| to which you wish to add extra fields.
|
||||
2. On the |repo| settings page, select the :guilabel:`Extra fields` tab.
|
||||
|
||||
.. image:: ../images/extra-repo-fields.png
|
||||
.. image:: ../../images/extra-repo-fields.png
|
||||
|
||||
The most important is the `New field key` variable which under the value will
|
||||
be stored. It needs to be unique for each repository. The label and description
|
||||
|
|
@ -16,19 +16,17 @@ The following are the most common system administration tasks.
|
|||
|
||||
.. toctree::
|
||||
|
||||
config-files-overview
|
||||
vcs-server
|
||||
svn-http
|
||||
svn-path-permissions
|
||||
gunicorn-ssl-support
|
||||
apache-config
|
||||
nginx-config
|
||||
backup-restore
|
||||
tuning-rhodecode
|
||||
indexing
|
||||
reset-information
|
||||
enable-debug
|
||||
admin-tricks
|
||||
cleanup-cmds
|
||||
restore-deleted-repositories
|
||||
|
||||
system_admin/config-files-overview
|
||||
system_admin/vcs-server
|
||||
system_admin/svn-http
|
||||
system_admin/svn-path-permissions
|
||||
system_admin/gunicorn-ssl-support
|
||||
system_admin/apache-config
|
||||
system_admin/nginx-config
|
||||
system_admin/backup-restore
|
||||
system_admin/tuning-rhodecode
|
||||
system_admin/indexing
|
||||
system_admin/reset-information
|
||||
system_admin/enable-debug
|
||||
system_admin/admin-tricks
|
||||
system_admin/cleanup-cmds
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ you can add a message to be displayed using the following steps:
|
|||
3. Select :guilabel:`Save`, and you will see the message once your page
|
||||
refreshes.
|
||||
|
||||
.. image:: ../images/server-wide-announcement.png
|
||||
.. image:: ../../images/server-wide-announcement.png
|
||||
:alt: Server Wide Announcement
|
||||
|
||||
.. _md-rst:
|
||||
|
|
@ -207,7 +207,7 @@ do this, use the following steps.
|
|||
Instance "enterprise-2" successfully stopped.
|
||||
Instance "enterprise-2" successfully started.
|
||||
|
||||
.. image:: ../images/language.png
|
||||
.. image:: ../../images/language.png
|
||||
|
||||
.. _set-repo-pub:
|
||||
|
||||
|
|
@ -239,3 +239,26 @@ following URL: ``{instance-URL}/_admin/ping``.
|
|||
|
||||
.. _Markdown: http://daringfireball.net/projects/markdown/
|
||||
.. _reStructured Text: http://docutils.sourceforge.net/docs/index.html
|
||||
|
||||
|
||||
Unarchiving a repository
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Archive operation for the repository is similar as delete. Archive keeps the data for future references
|
||||
but makes the repository read-only. After archiving the repository it shouldn't be modified in any way.
|
||||
This is why repository settings are disabled for an archived repository.
|
||||
|
||||
If there's a need for unarchiving a repository for some reasons, the interactive
|
||||
ishell interface should be used.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Open iShell from the terminal
|
||||
$ rccontrol ishell enterprise-1/community-1
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Set repository as un-archived
|
||||
In [1]: repo = Repository.get_by_repo_name('SOME_REPO_NAME')
|
||||
In [2]: repo.archived = False
|
||||
In [3]: Session().add(repo);Session().commit()
|
||||
|
|
@ -8,7 +8,7 @@ the information in the following sections.
|
|||
|
||||
.. toctree::
|
||||
|
||||
apache-conf-example
|
||||
apache-diffie-hellman
|
||||
apache-subdirectory
|
||||
apache-wsgi-coding
|
||||
apache/apache-conf-example
|
||||
apache/apache-diffie-hellman
|
||||
apache/apache-subdirectory
|
||||
apache/apache-wsgi-coding
|
||||
|
|
@ -66,14 +66,18 @@ Below config if for an Apache Reverse Proxy configuration.
|
|||
# Directive to properly generate url (clone url) for RhodeCode
|
||||
ProxyPreserveHost On
|
||||
|
||||
# It allows request bodies to be sent to the backend using chunked transfer encoding.
|
||||
SetEnv proxy-sendchunked 1
|
||||
|
||||
# Increase headers size for large Mercurial headers sent with many branches
|
||||
LimitRequestLine 16380
|
||||
|
||||
# Url to running RhodeCode instance. This is shown as `- URL:` when
|
||||
# running rccontrol status.
|
||||
|
||||
ProxyPass / http://127.0.0.1:10002/ timeout=7200 Keepalive=On
|
||||
ProxyPassReverse / http://127.0.0.1:10002/
|
||||
|
||||
# Increase headers for large Mercurial headers
|
||||
LimitRequestLine 16380
|
||||
|
||||
# strict http prevents from https -> http downgrade
|
||||
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ the information in the following sections.
|
|||
|
||||
.. toctree::
|
||||
|
||||
nginx-config-example
|
||||
nginx-diffie-hellman
|
||||
nginx-proxy-conf
|
||||
nginx-url-prefix
|
||||
nginx/nginx-config-example
|
||||
nginx/nginx-diffie-hellman
|
||||
nginx/nginx-proxy-conf
|
||||
nginx/nginx-url-prefix
|
||||
21
docs/admin/system_admin/tuning-rhodecode.rst
Normal file
21
docs/admin/system_admin/tuning-rhodecode.rst
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
.. _rhodecode-tuning-ref:
|
||||
|
||||
Tuning |RCE|
|
||||
============
|
||||
|
||||
To customize your |RCE| |version| installation for maximum performance you
|
||||
may find some of the following methods useful.
|
||||
|
||||
.. toctree::
|
||||
|
||||
tuning/tuning-gunicorn
|
||||
tuning/tuning-vcs-memory-cache
|
||||
tuning/tuning-user-sessions-performance
|
||||
tuning/tuning-increase-db-performance
|
||||
tuning/tuning-scale-horizontally-cluster
|
||||
tuning/tuning-mount-cache-memory
|
||||
tuning/tuning-change-encoding
|
||||
tuning/tuning-change-large-file-dir
|
||||
tuning/tuning-change-lfs-dir
|
||||
tuning/tuning-hg-auth-loop
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ To do this, use the following steps:
|
|||
## restarted, could prevent memory leaks
|
||||
max_requests = 1000
|
||||
max_requests_jitter = 30
|
||||
## amount of time a worker can spend with handling a request before it
|
||||
## amount of time a worker can spend with handling a request tuning-change-lfs-dir.before it
|
||||
## gets killed and restarted. Set to 6hrs
|
||||
timeout = 21600
|
||||
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
.. _rhodecode-tuning-ref:
|
||||
|
||||
Tuning |RCE|
|
||||
============
|
||||
|
||||
To customize your |RCE| |version| installation for maximum performance you
|
||||
may find some of the following methods useful.
|
||||
|
||||
.. toctree::
|
||||
|
||||
tuning-gunicorn
|
||||
tuning-vcs-memory-cache
|
||||
tuning-user-sessions-performance
|
||||
tuning-increase-db-performance
|
||||
tuning-scale-horizontally-cluster
|
||||
tuning-mount-cache-memory
|
||||
tuning-change-encoding
|
||||
tuning-change-large-file-dir
|
||||
tuning-change-lfs-dir
|
||||
tuning-hg-auth-loop
|
||||
|
||||
|
|
@ -13,11 +13,12 @@ permissions applied to it; |perm|.
|
|||
|
||||
.. toctree::
|
||||
|
||||
public-access
|
||||
default-user-perms
|
||||
adding-anonymous-user
|
||||
adding-new-user
|
||||
setting-default-permissions
|
||||
setting-usergroup-permissions
|
||||
user_admin/public-access
|
||||
user_admin/default-user-perms
|
||||
user_admin/adding-anonymous-user
|
||||
user_admin/adding-new-user
|
||||
user_admin/setting-default-permissions
|
||||
user_admin/setting-usergroup-permissions
|
||||
user_admin/user-admin-tasks
|
||||
|
||||
.. |perm| replace:: **None**, **Read**, **Write**, or **Admin**
|
||||
.. |perm| replace:: **None**, **Read**, **Write**, or **Admin**
|
||||
|
|
|
|||
24
docs/admin/user_admin/user-admin-tasks.rst
Normal file
24
docs/admin/user_admin/user-admin-tasks.rst
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
.. _user-admin-tasks:
|
||||
|
||||
Common Admin Tasks for Users
|
||||
----------------------------
|
||||
|
||||
|
||||
Manually Set Personal Repository Group
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Here is how to set a repository group as personal for a user using ishell.
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# starts the ishell interactive prompt
|
||||
$ rccontrol ishell enterprise-1
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
In [1]: repo_group = RepoGroup.get_by_group_name('some_group_name')
|
||||
In [2]: user = User.get_by_username('some_user')
|
||||
In [3]: repo_group.user = user
|
||||
In [4]: repo_group.personal = True
|
||||
In [5]: Session().add(repo_group);Session().commit()
|
||||
|
|
@ -204,6 +204,7 @@ are not required in args.
|
|||
methods/pull-request-methods
|
||||
methods/repo-methods
|
||||
methods/repo-group-methods
|
||||
methods/search-methods
|
||||
methods/server-methods
|
||||
methods/user-methods
|
||||
methods/user-group-methods
|
||||
|
|
|
|||
|
|
@ -462,6 +462,7 @@ get_repo_file
|
|||
:param cache: Use internal caches for fetching files. If disabled fetching
|
||||
files is slower but more memory efficient
|
||||
:type cache: Optional(bool)
|
||||
|
||||
Example output:
|
||||
|
||||
.. code-block:: bash
|
||||
|
|
@ -499,53 +500,51 @@ get_repo_nodes
|
|||
.. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=<Optional:'all'>, details=<Optional:'basic'>, max_file_bytes=<Optional:None>)
|
||||
|
||||
Returns a list of nodes and children in a flat list for a given
|
||||
path at given revision.
|
||||
path at given revision.
|
||||
|
||||
It's possible to specify ret_type to show only `files` or `dirs`.
|
||||
It's possible to specify ret_type to show only `files` or `dirs`.
|
||||
|
||||
This command can only be run using an |authtoken| with admin rights,
|
||||
or users with at least read rights to |repos|.
|
||||
This command can only be run using an |authtoken| with admin rights,
|
||||
or users with at least read rights to |repos|.
|
||||
|
||||
:param apiuser: This is filled automatically from the |authtoken|.
|
||||
:type apiuser: AuthUser
|
||||
:param repoid: The repository name or repository ID.
|
||||
:type repoid: str or int
|
||||
:param revision: The revision for which listing should be done.
|
||||
:type revision: str
|
||||
:param root_path: The path from which to start displaying.
|
||||
:type root_path: str
|
||||
:param ret_type: Set the return type. Valid options are
|
||||
``all`` (default), ``files`` and ``dirs``.
|
||||
:type ret_type: Optional(str)
|
||||
:param details: Returns extended information about nodes, such as
|
||||
md5, binary, and or content.
|
||||
The valid options are ``basic`` and ``full``.
|
||||
:type details: Optional(str)
|
||||
:param max_file_bytes: Only return file content under this file size bytes
|
||||
:type details: Optional(int)
|
||||
:param apiuser: This is filled automatically from the |authtoken|.
|
||||
:type apiuser: AuthUser
|
||||
:param repoid: The repository name or repository ID.
|
||||
:type repoid: str or int
|
||||
:param revision: The revision for which listing should be done.
|
||||
:type revision: str
|
||||
:param root_path: The path from which to start displaying.
|
||||
:type root_path: str
|
||||
:param ret_type: Set the return type. Valid options are
|
||||
``all`` (default), ``files`` and ``dirs``.
|
||||
:type ret_type: Optional(str)
|
||||
:param details: Returns extended information about nodes, such as
|
||||
md5, binary, and or content.
|
||||
The valid options are ``basic`` and ``full``.
|
||||
:type details: Optional(str)
|
||||
:param max_file_bytes: Only return file content under this file size bytes
|
||||
:type details: Optional(int)
|
||||
|
||||
Example output:
|
||||
Example output:
|
||||
|
||||
.. code-block:: bash
|
||||
.. code-block:: bash
|
||||
|
||||
id : <id_given_in_input>
|
||||
result: [
|
||||
{
|
||||
"binary": false,
|
||||
"content": "File line
|
||||
Line2
|
||||
",
|
||||
"extension": "md",
|
||||
"lines": 2,
|
||||
"md5": "059fa5d29b19c0657e384749480f6422",
|
||||
"mimetype": "text/x-minidsrc",
|
||||
"name": "file.md",
|
||||
"size": 580,
|
||||
"type": "file"
|
||||
},
|
||||
...
|
||||
]
|
||||
error: null
|
||||
id : <id_given_in_input>
|
||||
result: [
|
||||
{
|
||||
"binary": false,
|
||||
"content": "File line",
|
||||
"extension": "md",
|
||||
"lines": 2,
|
||||
"md5": "059fa5d29b19c0657e384749480f6422",
|
||||
"mimetype": "text/x-minidsrc",
|
||||
"name": "file.md",
|
||||
"size": 580,
|
||||
"type": "file"
|
||||
},
|
||||
...
|
||||
]
|
||||
error: null
|
||||
|
||||
|
||||
get_repo_refs
|
||||
|
|
|
|||
35
docs/api/methods/search-methods.rst
Normal file
35
docs/api/methods/search-methods.rst
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
.. _search-methods-ref:
|
||||
|
||||
search methods
|
||||
==============
|
||||
|
||||
search
|
||||
------
|
||||
|
||||
.. py:function:: search(apiuser, search_query, search_type, page_limit=<Optional:10>, page=<Optional:1>, search_sort=<Optional:'newfirst'>, repo_name=<Optional:None>, repo_group_name=<Optional:None>)
|
||||
|
||||
Fetch Full Text Search results using API.
|
||||
|
||||
:param apiuser: This is filled automatically from the |authtoken|.
|
||||
:type apiuser: AuthUser
|
||||
:param search_query: Search query.
|
||||
:type search_query: str
|
||||
:param search_type: Search type. The following are valid options:
|
||||
* commit
|
||||
* content
|
||||
* path
|
||||
:type search_type: str
|
||||
:param page_limit: Page item limit, from 1 to 500. Default 10 items.
|
||||
:type page_limit: Optional(int)
|
||||
:param page: Page number. Default first page.
|
||||
:type page: Optional(int)
|
||||
:param search_sort: Search sort order. Default newfirst. The following are valid options:
|
||||
* newfirst
|
||||
* oldfirst
|
||||
:type search_sort: Optional(str)
|
||||
:param repo_name: Filter by one repo. Default is all.
|
||||
:type repo_name: Optional(str)
|
||||
:param repo_group_name: Filter by one repo group. Default is all.
|
||||
:type repo_group_name: Optional(str)
|
||||
|
||||
|
||||
|
|
@ -32,9 +32,9 @@ The most important this id needs to be unique for each user.
|
|||
|
||||
In [1]: saml2user = {
|
||||
...: # OneLogin, uses externalID available to read from in the UI
|
||||
...: 123: {'id: '48253211'},
|
||||
...: 123: {'id': '48253211'},
|
||||
...: # for Google/DuoSecurity email is also an option for unique ID
|
||||
...: 124: {'id: 'email@domain.com'},
|
||||
...: 124: {'id': 'email@domain.com'},
|
||||
...: }
|
||||
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ Enter in the ishell prompt
|
|||
...: new_external_identity.external_id = external_id
|
||||
...: new_external_identity.external_username = '{}-saml-{}'.format(user.username, user.user_id)
|
||||
...: new_external_identity.provider_name = provider
|
||||
...: new_external_identity.local_user_id = user_id
|
||||
...: new_external_identity.local_user_id = user.user_id
|
||||
...: new_external_identity.access_token = ''
|
||||
...: new_external_identity.token_secret = ''
|
||||
...: new_external_identity.alt_token = ''
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ and commit files and |repos| while managing their security permissions.
|
|||
nix/default-env
|
||||
admin/system-admin
|
||||
admin/user-admin
|
||||
admin/setting-repo-perms
|
||||
admin/repo-admin
|
||||
admin/security-tips
|
||||
auth/auth
|
||||
issue-trackers/issue-trackers
|
||||
|
|
@ -62,6 +62,13 @@ and commit files and |repos| while managing their security permissions.
|
|||
code-review/code-review
|
||||
integrations/integrations
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: User Documentation
|
||||
|
||||
usage/basic-usage
|
||||
tutorials/tutorials
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Developer Documentation
|
||||
|
|
@ -71,13 +78,6 @@ and commit files and |repos| while managing their security permissions.
|
|||
extensions/extensions-hooks
|
||||
contributing/contributing
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: User Documentation
|
||||
|
||||
usage/basic-usage
|
||||
tutorials/tutorials
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: About
|
||||
|
|
|
|||
85
docs/release-notes/release-notes-4.17.0.rst
Normal file
85
docs/release-notes/release-notes-4.17.0.rst
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
|RCE| 4.17.0 |RNS|
|
||||
------------------
|
||||
|
||||
Release Date
|
||||
^^^^^^^^^^^^
|
||||
|
||||
- 2019-07-04
|
||||
|
||||
|
||||
New Features
|
||||
^^^^^^^^^^^^
|
||||
|
||||
- New artifacts feature.
|
||||
Ability to store binary artifacts for repository with ACL
|
||||
- UI/UX refresh for most of the pages. This includes multiple fixes and improvements.
|
||||
- Diffs: store wide-diff mode in user sessions to store user preference for diff display.
|
||||
- Mercurial: added support for Mercurial 4.9
|
||||
- API: Added search API methods
|
||||
- Files: adding/editing allows previews for generated content.
|
||||
- Files: allowed multi file upload using UI.
|
||||
- Repository Groups: last change is now smartly calculated based on latest change
|
||||
from all it's children repositories.
|
||||
- Archives: it's now currently possible to download partial directories from files view.
|
||||
- SVN: allowed executing pre-commit code with rcextensions, also added example to
|
||||
validate SVN file size and paths on pre-commit level.
|
||||
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
- Exception store: add filter for display and deletion.
|
||||
- Files: loading history doesn't display hidden and obsolete commits anymore.
|
||||
- Repositories: bring back missing watch action in summary view.
|
||||
- Admin: user groups is now using pure DB filtering to speed up display
|
||||
for large number of groups.
|
||||
- Mercurial: enabled full evolve+topic extensions when evolve is enabled.
|
||||
- Dependencies: bumped evolve to 8.5.1
|
||||
- Dependencies: bumped pyramid to 1.10.4
|
||||
- Dependencies: bumped psutil to 5.5.1
|
||||
- Dependencies: bumped pygments to 2.4.2
|
||||
- Dependencies: bumped pyramid to 1.10.4
|
||||
- Dependencies: bumped psycopg2 to 2.8.3
|
||||
- Dependencies [security]: updated colander to 1.7.0
|
||||
|
||||
|
||||
Security
|
||||
^^^^^^^^
|
||||
|
||||
- SSH: replaced pycrypto with cryptography to generate SSH keys as pycrypto isn't
|
||||
considered safe anymore.
|
||||
|
||||
|
||||
Performance
|
||||
^^^^^^^^^^^
|
||||
|
||||
- Config: updated header limits on gunicorn to prevent errors on large Mercurial repositories.
|
||||
- User sessions: added option to cleanup redis based sessions in user session interface.
|
||||
- Authentication: reduced usage of raw auth calls inside templates to speed up rendering.
|
||||
- Sessions: don't touch session for API calls. Before each API call created new session
|
||||
object which wasn't required.
|
||||
|
||||
|
||||
Fixes
|
||||
^^^^^
|
||||
|
||||
- hHooks: fixed more unicode problems with new pull-request link generator.
|
||||
- Mercurial: fix ssh-server support for mercurial custom options.
|
||||
- Pull requests: updated metadata information for failed merges with multiple heads.
|
||||
- Pull requests: calculate ancestor in the same way as creation mode.
|
||||
Fixed problem with updates generating wrong diffs in case of merges.
|
||||
- Pull requests: fixed a bug in removal of multiple reviewers at once.
|
||||
- Summary: fix timeout issues loading summary page without styling.
|
||||
- SSH: fix invocation of custom hgrc.
|
||||
- SSH: call custom hooks via SSH backend
|
||||
- Markup: fix styling for check-lists.
|
||||
- Archives: allows downloading refs that have slashes and special refs. e.g f/feat1 branch names.
|
||||
- Files: ensure we generate archives with consistent hashing (except for .tar.gz which uses temp files names in header)
|
||||
- Files: fixed rendering of readme files under non-ascii paths.
|
||||
|
||||
|
||||
Upgrade notes
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
- In this release we introduced new UI across the application.
|
||||
In case of problems with the display on your systems please send us info to support@rhodecode.com.
|
||||
|
||||
|
|
@ -9,6 +9,7 @@ Release Notes
|
|||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
release-notes-4.17.0.rst
|
||||
release-notes-4.16.2.rst
|
||||
release-notes-4.16.1.rst
|
||||
release-notes-4.16.0.rst
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
"<%= dirs.js.node_modules %>/moment/min/moment.min.js",
|
||||
"<%= dirs.js.node_modules %>/clipboard/dist/clipboard.min.js",
|
||||
"<%= dirs.js.node_modules %>/favico.js/favico-0.3.10.min.js",
|
||||
"<%= dirs.js.node_modules %>/dropzone/dist/dropzone.js",
|
||||
"<%= dirs.js.node_modules %>/sticky-sidebar/dist/sticky-sidebar.min.js",
|
||||
"<%= dirs.js.node_modules %>/sticky-sidebar/dist/jquery.sticky-sidebar.min.js",
|
||||
"<%= dirs.js.node_modules %>/waypoints/lib/noframework.waypoints.min.js",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"files": {
|
||||
"<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
|
||||
"<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
|
||||
"<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less",
|
||||
"<%= dirs.css.dest %>/style-ipython.css": "<%= dirs.css.src %>/ipython.less"
|
||||
}
|
||||
},
|
||||
"production": {
|
||||
|
|
@ -118,7 +120,8 @@
|
|||
},
|
||||
"files": {
|
||||
"<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
|
||||
"<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
|
||||
"<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less",
|
||||
"<%= dirs.css.dest %>/style-ipython.css": "<%= dirs.css.src %>/ipython.less"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
"clipboard": "^2.0.1",
|
||||
"exports-loader": "^0.6.4",
|
||||
"favico.js": "^0.3.10",
|
||||
"dropzone": "^5.5.0",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-cli": "^1.3.1",
|
||||
"grunt-contrib-concat": "^0.5.1",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[pip2nix]
|
||||
requirements = ., -r ./requirements.txt
|
||||
requirements = ., -r ./requirements.txt, -r ./requirements_pinned.txt
|
||||
output = ./pkgs/python-packages.nix
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -35,6 +35,18 @@ self: super: {
|
|||
];
|
||||
});
|
||||
|
||||
"cffi" = super."cffi".override (attrs: {
|
||||
buildInputs = [
|
||||
pkgs.libffi
|
||||
];
|
||||
});
|
||||
|
||||
"cryptography" = super."cryptography".override (attrs: {
|
||||
buildInputs = [
|
||||
pkgs.openssl
|
||||
];
|
||||
});
|
||||
|
||||
"gevent" = super."gevent".override (attrs: {
|
||||
propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
|
||||
# NOTE: (marcink) odd requirements from gevent aren't set properly,
|
||||
|
|
@ -152,12 +164,6 @@ self: super: {
|
|||
};
|
||||
});
|
||||
|
||||
"pytest-runner" = super."pytest-runner".override (attrs: {
|
||||
propagatedBuildInputs = [
|
||||
self."setuptools-scm"
|
||||
];
|
||||
});
|
||||
|
||||
"python-ldap" = super."python-ldap".override (attrs: {
|
||||
propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
|
||||
pkgs.openldap
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
self: super: {
|
||||
"alembic" = super.buildPythonPackage {
|
||||
name = "alembic-1.0.5";
|
||||
name = "alembic-1.0.10";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."sqlalchemy"
|
||||
|
|
@ -14,8 +14,8 @@ self: super: {
|
|||
self."python-dateutil"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/1c/65/b8e4f5b2f345bb13b5e0a3fddd892b0b3f0e8ad4880e954fdc6a50d00d84/alembic-1.0.5.tar.gz";
|
||||
sha256 = "0rpjqp2iq6p49x1nli18ivak1izz547nnjxi110mzrgc1v7dxzz9";
|
||||
url = "https://files.pythonhosted.org/packages/6e/8b/fa3bd058cccd5e9177fea4efa26bfb769228fdd3178436ad5e05830ef6ef/alembic-1.0.10.tar.gz";
|
||||
sha256 = "1dwl0264r6ri2jyrjr68am04x538ab26xwy4crqjnnhm4alwm3c2";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -51,6 +51,17 @@ self: super: {
|
|||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
};
|
||||
};
|
||||
"asn1crypto" = super.buildPythonPackage {
|
||||
name = "asn1crypto-0.24.0";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/fc/f1/8db7daa71f414ddabfa056c4ef792e1461ff655c2ae2928a2b675bfed6b4/asn1crypto-0.24.0.tar.gz";
|
||||
sha256 = "0jaf8rf9dx1lf23xfv2cdd5h52f1qr3w8k63985bc35g3d220p4x";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
};
|
||||
};
|
||||
"atomicwrites" = super.buildPythonPackage {
|
||||
name = "atomicwrites-1.2.1";
|
||||
doCheck = false;
|
||||
|
|
@ -77,8 +88,8 @@ self: super: {
|
|||
name = "authomatic-0.1.0.post1";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801";
|
||||
sha256 = "1cgk0a86sbsjbri06gf5z5l4npwkjdxw6fdnwl4vvfmxs2sx9yxw";
|
||||
url = "https://code.rhodecode.com/upstream/authomatic/artifacts/download/0-4fe9c041-a567-4f84-be4c-7efa2a606d3c.tar.gz?md5=f6bdc3c769688212db68233e8d2b0383";
|
||||
sha256 = "0pc716mva0ym6xd8jwzjbjp8dqxy9069wwwv2aqwb8lyhl4757ab";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -146,15 +157,15 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"bleach" = super.buildPythonPackage {
|
||||
name = "bleach-3.0.2";
|
||||
name = "bleach-3.1.0";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."six"
|
||||
self."webencodings"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/ae/31/680afc7d44040004296a2d8f0584983c2f2386448cd9d0964197e6c1160e/bleach-3.0.2.tar.gz";
|
||||
sha256 = "06474zg7f73hv8h1xw2wcsmvn2ygj73zxgxxqg8zcx8ap1srdls8";
|
||||
url = "https://files.pythonhosted.org/packages/78/5a/0df03e8735cd9c75167528299c738702437589b9c71a849489d00ffa82e8/bleach-3.1.0.tar.gz";
|
||||
sha256 = "1yhrgrhkln8bd6gn3imj69g1h4xqah9gaz9q26crqr6gmmvpzprz";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.asl20 ];
|
||||
|
|
@ -187,6 +198,20 @@ self: super: {
|
|||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
};
|
||||
};
|
||||
"cffi" = super.buildPythonPackage {
|
||||
name = "cffi-1.12.2";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."pycparser"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/64/7c/27367b38e6cc3e1f49f193deb761fe75cda9f95da37b67b422e62281fcac/cffi-1.12.2.tar.gz";
|
||||
sha256 = "19qfks2djya8vix95bmg3xzipjb8w9b8mbj4j5k2hqkc8j58f4z1";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
};
|
||||
};
|
||||
"chameleon" = super.buildPythonPackage {
|
||||
name = "chameleon-2.24";
|
||||
doCheck = false;
|
||||
|
|
@ -230,7 +255,7 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"colander" = super.buildPythonPackage {
|
||||
name = "colander-1.5.1";
|
||||
name = "colander-1.7.0";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."translationstring"
|
||||
|
|
@ -238,8 +263,8 @@ self: super: {
|
|||
self."enum34"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/ec/d1/fcca811a0a692c69d27e36b4d11a73acb98b4bab48323442642b6fd4386d/colander-1.5.1.tar.gz";
|
||||
sha256 = "18ah4cwwxnpm6qxi6x9ipy51dal4spd343h44s5wd01cnhgrwsyq";
|
||||
url = "https://files.pythonhosted.org/packages/db/e4/74ab06f54211917b41865cafc987ce511e35503de48da9bfe9358a1bdc3e/colander-1.7.0.tar.gz";
|
||||
sha256 = "1wl1bqab307lbbcjx81i28s3yl6dlm4rf15fxawkjb6j48x1cn6p";
|
||||
};
|
||||
meta = {
|
||||
license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
|
||||
|
|
@ -252,19 +277,19 @@ self: super: {
|
|||
self."six"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://code.rhodecode.com/upstream/configobj/archive/a11ff0a0bd4fbda9e3a91267e720f88329efb4a6.tar.gz?md5=9916c524ea11a6c418217af6b28d4b3c";
|
||||
sha256 = "1hhcxirwvg58grlfr177b3awhbq8hlx1l3lh69ifl1ki7lfd1s1x";
|
||||
url = "https://code.rhodecode.com/upstream/configobj/artifacts/download/0-012de99a-b1e1-4f64-a5c0-07a98a41b324.tar.gz?md5=6a513f51fe04b2c18cf84c1395a7c626";
|
||||
sha256 = "0kqfrdfr14mw8yd8qwq14dv2xghpkjmd3yjsy8dfcbvpcc17xnxp";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
};
|
||||
};
|
||||
"configparser" = super.buildPythonPackage {
|
||||
name = "configparser-3.7.1";
|
||||
name = "configparser-3.7.4";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/b6/a6/eceea7c5a5dbcf56815bed411c38cabd8a879386be10717b160e7362b5a2/configparser-3.7.1.tar.gz";
|
||||
sha256 = "0cnz213il9lhgda6x70fw7mfqr8da43s3wm343lwzhqx94mgmmav";
|
||||
url = "https://files.pythonhosted.org/packages/e2/1c/83fd53748d8245cb9a3399f705c251d3fc0ce7df04450aac1cfc49dd6a0f/configparser-3.7.4.tar.gz";
|
||||
sha256 = "0xac32886ihs2xg7w1gppcq2sgin5qsm8lqwijs5xifq9w0x0q6s";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -285,16 +310,34 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"coverage" = super.buildPythonPackage {
|
||||
name = "coverage-4.5.1";
|
||||
name = "coverage-4.5.3";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/35/fe/e7df7289d717426093c68d156e0fd9117c8f4872b6588e8a8928a0f68424/coverage-4.5.1.tar.gz";
|
||||
sha256 = "1wbrzpxka3xd4nmmkc6q0ir343d91kymwsm8pbmwa0d2a7q4ir2n";
|
||||
url = "https://files.pythonhosted.org/packages/82/70/2280b5b29a0352519bb95ab0ef1ea942d40466ca71c53a2085bdeff7b0eb/coverage-4.5.3.tar.gz";
|
||||
sha256 = "02f6m073qdispn96rc616hg0rnmw1pgqzw3bgxwiwza4zf9hirlx";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.asl20 ];
|
||||
};
|
||||
};
|
||||
"cryptography" = super.buildPythonPackage {
|
||||
name = "cryptography-2.6.1";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."asn1crypto"
|
||||
self."six"
|
||||
self."cffi"
|
||||
self."enum34"
|
||||
self."ipaddress"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/07/ca/bc827c5e55918ad223d59d299fff92f3563476c3b00d0a9157d9c0217449/cryptography-2.6.1.tar.gz";
|
||||
sha256 = "19iwz5avym5zl6jrrrkym1rdaa9h61j20ph4cswsqgv8xg5j3j16";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal { fullName = "BSD or Apache License, Version 2.0"; } pkgs.lib.licenses.asl20 ];
|
||||
};
|
||||
};
|
||||
"cssselect" = super.buildPythonPackage {
|
||||
name = "cssselect-1.0.3";
|
||||
doCheck = false;
|
||||
|
|
@ -337,11 +380,11 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"defusedxml" = super.buildPythonPackage {
|
||||
name = "defusedxml-0.5.0";
|
||||
name = "defusedxml-0.6.0";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/74/ba/4ba4e89e21b5a2e267d80736ea674609a0a33cc4435a6d748ef04f1f9374/defusedxml-0.5.0.tar.gz";
|
||||
sha256 = "1x54n0h8hl92vvwyymx883fbqpqjwn2mc8fb383bcg3z9zwz5mr4";
|
||||
url = "https://files.pythonhosted.org/packages/a4/5f/f8aa58ca0cf01cbcee728abc9d88bfeb74e95e6cb4334cfd5bed5673ea77/defusedxml-0.6.0.tar.gz";
|
||||
sha256 = "1xbp8fivl3wlbyg2jrvs4lalaqv1xp9a9f29p75wdx2s2d6h717n";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.psfl ];
|
||||
|
|
@ -399,11 +442,11 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"ecdsa" = super.buildPythonPackage {
|
||||
name = "ecdsa-0.13";
|
||||
name = "ecdsa-0.13.2";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/f9/e5/99ebb176e47f150ac115ffeda5fedb6a3dbb3c00c74a59fd84ddf12f5857/ecdsa-0.13.tar.gz";
|
||||
sha256 = "1yj31j0asmrx4an9xvsaj2icdmzy6pw0glfpqrrkrphwdpi1xkv4";
|
||||
url = "https://files.pythonhosted.org/packages/51/76/139bf6e9b7b6684d5891212cdbd9e0739f2bfc03f380a1a6ffa700f392ac/ecdsa-0.13.2.tar.gz";
|
||||
sha256 = "116qaq7bh4lcynzi613960jhsnn19v0kmsqwahiwjfj14gx4y0sw";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -491,8 +534,8 @@ self: super: {
|
|||
self."configparser"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313";
|
||||
sha256 = "0bihrdp8ahsys437kxdhk52gz6kib8rxjv71i93wkw7594fcaxll";
|
||||
url = "https://code.rhodecode.com/upstream/entrypoints/artifacts/download/0-8e9ee9e4-c4db-409c-b07e-81568fd1832d.tar.gz?md5=3a027b8ff1d257b91fe257de6c43357d";
|
||||
sha256 = "0qih72n2myclanplqipqxpgpj9d2yhff1pz5d02zq1cfqyd173w5";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -623,11 +666,11 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"hupper" = super.buildPythonPackage {
|
||||
name = "hupper-1.4.2";
|
||||
name = "hupper-1.6.1";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/f1/75/1915dc7650b4867fa3049256e24ca8eddb5989998fcec788cf52b9812dfc/hupper-1.4.2.tar.gz";
|
||||
sha256 = "16vb9fkiaakdpcp6pn56h3w0dwvm67bxq2k2dv4i382qhqwphdzb";
|
||||
url = "https://files.pythonhosted.org/packages/85/d9/e005d357b11249c5d70ddf5b7adab2e4c0da4e8b0531ff146917a04fe6c0/hupper-1.6.1.tar.gz";
|
||||
sha256 = "0d3cvkc8ssgwk54wvhbifj56ry97qi10pfzwfk8vwzzcikbfp3zy";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -671,15 +714,15 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"ipdb" = super.buildPythonPackage {
|
||||
name = "ipdb-0.11";
|
||||
name = "ipdb-0.12";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."setuptools"
|
||||
self."ipython"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/80/fe/4564de08f174f3846364b3add8426d14cebee228f741c27e702b2877e85b/ipdb-0.11.tar.gz";
|
||||
sha256 = "02m0l8wrhhd3z7dg3czn5ys1g5pxib516hpshdzp7rxzsxgcd0bh";
|
||||
url = "https://files.pythonhosted.org/packages/6d/43/c3c2e866a8803e196d6209595020a4a6db1a3c5d07c01455669497ae23d0/ipdb-0.12.tar.gz";
|
||||
sha256 = "1khr2n7xfy8hg65kj1bsrjq9g7656pp0ybfa8abpbzpdawji3qnw";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
|
|
@ -802,14 +845,14 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"jupyter-core" = super.buildPythonPackage {
|
||||
name = "jupyter-core-4.4.0";
|
||||
name = "jupyter-core-4.5.0";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."traitlets"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz";
|
||||
sha256 = "1dy083rarba8prn9f9srxq3c7n7vyql02ycrqq306c40lr57aw5s";
|
||||
url = "https://files.pythonhosted.org/packages/4a/de/ff4ca734656d17ebe0450807b59d728f45277e2e7f4b82bc9aae6cb82961/jupyter_core-4.5.0.tar.gz";
|
||||
sha256 = "1xr4pbghwk5hayn5wwnhb7z95380r45p79gf5if5pi1akwg7qvic";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
|
|
@ -1008,14 +1051,14 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"paste" = super.buildPythonPackage {
|
||||
name = "paste-3.0.5";
|
||||
name = "paste-3.0.8";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."six"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/d4/41/91bde422400786b1b06357c1e6e3a5379f54dc3002aeb337cb767233304e/Paste-3.0.5.tar.gz";
|
||||
sha256 = "1a6i8fh1fg8r4x800fvy9r82m15clwjim6yf2g9r4dff0y40dchv";
|
||||
url = "https://files.pythonhosted.org/packages/66/65/e3acf1663438483c1f6ced0b6c6f3b90da9f0faacb0a6e2aa0f3f9f4b235/Paste-3.0.8.tar.gz";
|
||||
sha256 = "05w1sh6ky4d7pmdb8nv82n13w22jcn3qsagg5ih3hjmbws9kkwf4";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -1033,7 +1076,7 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"pastescript" = super.buildPythonPackage {
|
||||
name = "pastescript-3.0.0";
|
||||
name = "pastescript-3.1.0";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."paste"
|
||||
|
|
@ -1041,23 +1084,23 @@ self: super: {
|
|||
self."six"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/08/2a/3797377a884ab9a064ad4d564ed612e54d26d7997caa8229c9c9df4eac31/PasteScript-3.0.0.tar.gz";
|
||||
sha256 = "1hvmyz1sbn7ws1syw567ph7km9fi0wi75r3vlyzx6sk0z26xkm6r";
|
||||
url = "https://files.pythonhosted.org/packages/9e/1d/14db1c283eb21a5d36b6ba1114c13b709629711e64acab653d9994fe346f/PasteScript-3.1.0.tar.gz";
|
||||
sha256 = "02qcxjjr32ks7a6d4f533wl34ysc7yhwlrfcyqwqbzr52250v4fs";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
};
|
||||
};
|
||||
"pathlib2" = super.buildPythonPackage {
|
||||
name = "pathlib2-2.3.3";
|
||||
name = "pathlib2-2.3.4";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."six"
|
||||
self."scandir"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/bf/d7/a2568f4596b75d2c6e2b4094a7e64f620decc7887f69a1f2811931ea15b9/pathlib2-2.3.3.tar.gz";
|
||||
sha256 = "0hpp92vqqgcd8h92msm9slv161b1q160igjwnkf2ag6cx0c96695";
|
||||
url = "https://files.pythonhosted.org/packages/b5/f4/9c7cc726ece2498b6c8b62d3262aa43f59039b953fe23c9964ac5e18d40b/pathlib2-2.3.4.tar.gz";
|
||||
sha256 = "1y0f9rkm1924zrc5dn4bwxlhgdkbml82lkcc28l5rgmr7d918q24";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -1075,14 +1118,14 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"pexpect" = super.buildPythonPackage {
|
||||
name = "pexpect-4.6.0";
|
||||
name = "pexpect-4.7.0";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."ptyprocess"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/89/43/07d07654ee3e25235d8cea4164cdee0ec39d1fda8e9203156ebe403ffda4/pexpect-4.6.0.tar.gz";
|
||||
sha256 = "1fla85g47iaxxpjhp9vkxdnv4pgc7rplfy6ja491smrrk0jqi3ia";
|
||||
url = "https://files.pythonhosted.org/packages/1c/b1/362a0d4235496cb42c33d1d8732b5e2c607b0129ad5fdd76f5a583b9fcb3/pexpect-4.7.0.tar.gz";
|
||||
sha256 = "1sv2rri15zwhds85a4kamwh9pj49qcxv7m4miyr4jfpfwv81yb4y";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
|
||||
|
|
@ -1117,63 +1160,63 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"plaster-pastedeploy" = super.buildPythonPackage {
|
||||
name = "plaster-pastedeploy-0.6";
|
||||
name = "plaster-pastedeploy-0.7";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."pastedeploy"
|
||||
self."plaster"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/3f/e7/6a6833158d2038ec40085433308a1e164fd1dac595513f6dd556d5669bb8/plaster_pastedeploy-0.6.tar.gz";
|
||||
sha256 = "1bkggk18f4z2bmsmxyxabvf62znvjwbivzh880419r3ap0616cf2";
|
||||
url = "https://files.pythonhosted.org/packages/99/69/2d3bc33091249266a1bd3cf24499e40ab31d54dffb4a7d76fe647950b98c/plaster_pastedeploy-0.7.tar.gz";
|
||||
sha256 = "1zg7gcsvc1kzay1ry5p699rg2qavfsxqwl17mqxzr0gzw6j9679r";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
};
|
||||
};
|
||||
"pluggy" = super.buildPythonPackage {
|
||||
name = "pluggy-0.8.1";
|
||||
name = "pluggy-0.11.0";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/38/e1/83b10c17688af7b2998fa5342fec58ecbd2a5a7499f31e606ae6640b71ac/pluggy-0.8.1.tar.gz";
|
||||
sha256 = "05l6g42p9ilmabw0hlbiyxy6gyzjri41m5l11a8dzgvi77q35p4d";
|
||||
url = "https://files.pythonhosted.org/packages/0d/a1/862ab336e8128fde20981d2c1aa8506693412daf5083b1911d539412676b/pluggy-0.11.0.tar.gz";
|
||||
sha256 = "10511a54dvafw1jrk75mrhml53c7b7w4yaw7241696lc2hfvr895";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
};
|
||||
};
|
||||
"prompt-toolkit" = super.buildPythonPackage {
|
||||
name = "prompt-toolkit-1.0.15";
|
||||
name = "prompt-toolkit-1.0.16";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."six"
|
||||
self."wcwidth"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/8a/ad/cf6b128866e78ad6d7f1dc5b7f99885fb813393d9860778b2984582e81b5/prompt_toolkit-1.0.15.tar.gz";
|
||||
sha256 = "05v9h5nydljwpj5nm8n804ms0glajwfy1zagrzqrg91wk3qqi1c5";
|
||||
url = "https://files.pythonhosted.org/packages/f1/03/bb36771dc9fa7553ac4bdc639a9ecdf6fda0ff4176faf940d97e3c16e41d/prompt_toolkit-1.0.16.tar.gz";
|
||||
sha256 = "1d65hm6nf0cbq0q0121m60zzy4s1fpg9fn761s1yxf08dridvkn1";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
};
|
||||
};
|
||||
"psutil" = super.buildPythonPackage {
|
||||
name = "psutil-5.4.8";
|
||||
name = "psutil-5.5.1";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/e3/58/0eae6e4466e5abf779d7e2b71fac7fba5f59e00ea36ddb3ed690419ccb0f/psutil-5.4.8.tar.gz";
|
||||
sha256 = "1hyna338sml2cl1mfb2gs89np18z27mvyhmq4ifh22x07n7mq9kf";
|
||||
url = "https://files.pythonhosted.org/packages/c7/01/7c30b247cdc5ba29623faa5c8cf1f1bbf7e041783c340414b0ed7e067c64/psutil-5.5.1.tar.gz";
|
||||
sha256 = "045qaqvn6k90bj5bcy259yrwcd2afgznaav3sfhphy9b8ambzkkj";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
};
|
||||
};
|
||||
"psycopg2" = super.buildPythonPackage {
|
||||
name = "psycopg2-2.7.5";
|
||||
name = "psycopg2-2.8.3";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/b2/c1/7bf6c464e903ffc4f3f5907c389e5a4199666bf57f6cd6bf46c17912a1f9/psycopg2-2.7.5.tar.gz";
|
||||
sha256 = "17klx964gw8z0znl0raz3by8vdc7cq5gxj4pdcrfcina84nrdkzc";
|
||||
url = "https://files.pythonhosted.org/packages/5c/1c/6997288da181277a0c29bc39a5f9143ff20b8c99f2a7d059cfb55163e165/psycopg2-2.8.3.tar.gz";
|
||||
sha256 = "0ms4kx0p5n281l89awccix4d05ybmdngnjjpi9jbzd0rhf1nwyl9";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.zpl21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
|
||||
|
|
@ -1239,14 +1282,25 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"pyasn1-modules" = super.buildPythonPackage {
|
||||
name = "pyasn1-modules-0.2.4";
|
||||
name = "pyasn1-modules-0.2.5";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."pyasn1"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/bd/a5/ef7bf693e8a8f015386c9167483199f54f8a8ec01d1c737e05524f16e792/pyasn1-modules-0.2.4.tar.gz";
|
||||
sha256 = "0z3w5dqrrvdplg9ma45j8n23xvyrj9ki8mg4ibqbn7l4qpl90855";
|
||||
url = "https://files.pythonhosted.org/packages/ec/0b/69620cb04a016e4a1e8e352e8a42717862129b574b3479adb2358a1f12f7/pyasn1-modules-0.2.5.tar.gz";
|
||||
sha256 = "15nvfx0vnl8akdlv3k6s0n80vqvryj82bm040jdsn7wmyxl1ywpg";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
};
|
||||
};
|
||||
"pycparser" = super.buildPythonPackage {
|
||||
name = "pycparser-2.19";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/68/9e/49196946aee219aead1290e00d1e7fdeab8567783e83e1b9ab5585e6206a/pycparser-2.19.tar.gz";
|
||||
sha256 = "1cr5dcj9628lkz1qlwq3fv97c25363qppkmcayqvd05dpy573259";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
|
|
@ -1274,23 +1328,12 @@ self: super: {
|
|||
license = [ pkgs.lib.licenses.mit { fullName = "LGPL/MIT"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
|
||||
};
|
||||
};
|
||||
"pyflakes" = super.buildPythonPackage {
|
||||
name = "pyflakes-0.8.1";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/75/22/a90ec0252f4f87f3ffb6336504de71fe16a49d69c4538dae2f12b9360a38/pyflakes-0.8.1.tar.gz";
|
||||
sha256 = "0sbpq6pqm1i9wqi41mlfrsc5rk92jv4mskvlyxmnhlbdnc80ma1z";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
};
|
||||
};
|
||||
"pygments" = super.buildPythonPackage {
|
||||
name = "pygments-2.3.1";
|
||||
name = "pygments-2.4.2";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/64/69/413708eaf3a64a6abb8972644e0f20891a55e621c6759e2c3f3891e05d63/Pygments-2.3.1.tar.gz";
|
||||
sha256 = "0ji87g09jph8jqcvclgb02qvxasdnr9pzvk90rl66d90yqcxmyjz";
|
||||
url = "https://files.pythonhosted.org/packages/7e/ae/26808275fc76bf2832deb10d3a3ed3107bc4de01b85dcccbe525f2cd6d1e/Pygments-2.4.2.tar.gz";
|
||||
sha256 = "15v2sqm5g12bqa0c7wikfh9ck2nl97ayizy1hpqhmws5gqalq748";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
|
|
@ -1330,7 +1373,7 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"pyramid" = super.buildPythonPackage {
|
||||
name = "pyramid-1.10.1";
|
||||
name = "pyramid-1.10.4";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."hupper"
|
||||
|
|
@ -1345,28 +1388,13 @@ self: super: {
|
|||
self."repoze.lru"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/0a/3e/22e3ac9be1b70a01139adba8906ee4b8f628bb469fea3c52f6c97b73063c/pyramid-1.10.1.tar.gz";
|
||||
sha256 = "1h5105nfh6rsrfjiyw20aavyibj36la3hajy6vh1fa77xb4y3hrp";
|
||||
url = "https://files.pythonhosted.org/packages/c2/43/1ae701c9c6bb3a434358e678a5e72c96e8aa55cf4cb1d2fa2041b5dd38b7/pyramid-1.10.4.tar.gz";
|
||||
sha256 = "0rkxs1ajycg2zh1c94xlmls56mx5m161sn8112skj0amza6cn36q";
|
||||
};
|
||||
meta = {
|
||||
license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
|
||||
};
|
||||
};
|
||||
"pyramid-beaker" = super.buildPythonPackage {
|
||||
name = "pyramid-beaker-0.8";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."pyramid"
|
||||
self."beaker"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/d9/6e/b85426e00fd3d57f4545f74e1c3828552d8700f13ededeef9233f7bca8be/pyramid_beaker-0.8.tar.gz";
|
||||
sha256 = "0hflx3qkcdml1mwpq53sz46s7jickpfn0zy0ns2c7j445j66bp3p";
|
||||
};
|
||||
meta = {
|
||||
license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
|
||||
};
|
||||
};
|
||||
"pyramid-debugtoolbar" = super.buildPythonPackage {
|
||||
name = "pyramid-debugtoolbar-4.5";
|
||||
doCheck = false;
|
||||
|
|
@ -1538,14 +1566,14 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"python-dateutil" = super.buildPythonPackage {
|
||||
name = "python-dateutil-2.7.5";
|
||||
name = "python-dateutil-2.8.0";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."six"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/0e/01/68747933e8d12263d41ce08119620d9a7e5eb72c876a3442257f74490da0/python-dateutil-2.7.5.tar.gz";
|
||||
sha256 = "00ngwcdw36w5b37b51mdwn3qxid9zdf3kpffv2q6n9kl05y2iyc8";
|
||||
url = "https://files.pythonhosted.org/packages/ad/99/5b2e99737edeb28c71bcbec5b5dda19d0d9ef3ca3e92e3e925e7c0bb364c/python-dateutil-2.8.0.tar.gz";
|
||||
sha256 = "17nsfhy4xdz1khrfxa61vd7pmvd5z0wa3zb6v4gb4kfnykv0b668";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.asl20 { fullName = "Dual License"; } ];
|
||||
|
|
@ -1690,7 +1718,7 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"rhodecode-enterprise-ce" = super.buildPythonPackage {
|
||||
name = "rhodecode-enterprise-ce-4.16.2";
|
||||
name = "rhodecode-enterprise-ce-4.17.0";
|
||||
buildInputs = [
|
||||
self."pytest"
|
||||
self."py"
|
||||
|
|
@ -1709,36 +1737,29 @@ self: super: {
|
|||
];
|
||||
doCheck = true;
|
||||
propagatedBuildInputs = [
|
||||
self."setuptools-scm"
|
||||
self."amqp"
|
||||
self."authomatic"
|
||||
self."atomicwrites"
|
||||
self."attrs"
|
||||
self."babel"
|
||||
self."beaker"
|
||||
self."bleach"
|
||||
self."celery"
|
||||
self."chameleon"
|
||||
self."channelstream"
|
||||
self."click"
|
||||
self."colander"
|
||||
self."configobj"
|
||||
self."cssselect"
|
||||
self."cryptography"
|
||||
self."decorator"
|
||||
self."deform"
|
||||
self."docutils"
|
||||
self."dogpile.cache"
|
||||
self."dogpile.core"
|
||||
self."ecdsa"
|
||||
self."formencode"
|
||||
self."future"
|
||||
self."futures"
|
||||
self."gnureadline"
|
||||
self."infrae.cache"
|
||||
self."iso8601"
|
||||
self."itsdangerous"
|
||||
self."jinja2"
|
||||
self."billiard"
|
||||
self."kombu"
|
||||
self."lxml"
|
||||
self."mako"
|
||||
|
|
@ -1747,21 +1768,18 @@ self: super: {
|
|||
self."msgpack-python"
|
||||
self."pyotp"
|
||||
self."packaging"
|
||||
self."pathlib2"
|
||||
self."paste"
|
||||
self."pastedeploy"
|
||||
self."pastescript"
|
||||
self."pathlib2"
|
||||
self."peppercorn"
|
||||
self."psutil"
|
||||
self."py-bcrypt"
|
||||
self."pycrypto"
|
||||
self."pycurl"
|
||||
self."pyflakes"
|
||||
self."pycrypto"
|
||||
self."pygments"
|
||||
self."pyparsing"
|
||||
self."pyramid-beaker"
|
||||
self."pyramid-debugtoolbar"
|
||||
self."pyramid-jinja2"
|
||||
self."pyramid-mako"
|
||||
self."pyramid"
|
||||
self."pyramid-mailer"
|
||||
|
|
@ -1784,7 +1802,6 @@ self: super: {
|
|||
self."sshpubkeys"
|
||||
self."subprocess32"
|
||||
self."supervisor"
|
||||
self."tempita"
|
||||
self."translationstring"
|
||||
self."urllib3"
|
||||
self."urlobject"
|
||||
|
|
@ -1813,7 +1830,6 @@ self: super: {
|
|||
self."greenlet"
|
||||
self."gunicorn"
|
||||
self."waitress"
|
||||
self."setproctitle"
|
||||
self."ipdb"
|
||||
self."ipython"
|
||||
self."rhodecode-tools"
|
||||
|
|
@ -1855,8 +1871,8 @@ self: super: {
|
|||
self."elasticsearch1-dsl"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v1.2.1.tar.gz?md5=25bc2f7de1da318e547236d3fb463d28";
|
||||
sha256 = "1k8l3s4mvshza1zay6dfxprq54fyb5dc85dqdva9wa3f466y0adk";
|
||||
url = "https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-10ac93f4-bb7d-4b97-baea-68110743dd5a.tar.gz?md5=962dc77c06aceee62282b98d33149661";
|
||||
sha256 = "1vfhgf46inbx7jvlfx4fdzh3vz7lh37r291gzb5hx447pfm3qllg";
|
||||
};
|
||||
meta = {
|
||||
license = [ { fullName = "Apache 2.0 and Proprietary"; } ];
|
||||
|
|
@ -1878,11 +1894,11 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"scandir" = super.buildPythonPackage {
|
||||
name = "scandir-1.9.0";
|
||||
name = "scandir-1.10.0";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/16/2a/557af1181e6b4e30254d5a6163b18f5053791ca66e251e77ab08887e8fe3/scandir-1.9.0.tar.gz";
|
||||
sha256 = "0r3hvf1a9jm1rkqgx40gxkmccknkaiqjavs8lccgq9s8khh5x5s4";
|
||||
url = "https://files.pythonhosted.org/packages/df/f5/9c052db7bd54d0cbf1bc0bb6554362bba1012d03e5888950a4f5c5dadc4e/scandir-1.10.0.tar.gz";
|
||||
sha256 = "1bkqwmf056pkchf05ywbnf659wqlp6lljcdb0y88wr9f0vv32ijd";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ];
|
||||
|
|
@ -1900,22 +1916,11 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"setuptools" = super.buildPythonPackage {
|
||||
name = "setuptools-40.8.0";
|
||||
name = "setuptools-41.0.1";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/c2/f7/c7b501b783e5a74cf1768bc174ee4fb0a8a6ee5af6afa92274ff964703e0/setuptools-40.8.0.zip";
|
||||
sha256 = "0k9hifpgahnw2a26w3cr346iy733k6d3nwh3f7g9m13y6f8fqkkf";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
};
|
||||
};
|
||||
"setuptools-scm" = super.buildPythonPackage {
|
||||
name = "setuptools-scm-2.1.0";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/e5/62/f9e1ac314464eb5945c97542acb6bf6f3381dfa5d7a658de7730c36f31a1/setuptools_scm-2.1.0.tar.gz";
|
||||
sha256 = "0yb364cgk15sfw3x8ln4ssh98z1dj6n8iiz4r2rw1cfsxhgi8rx7";
|
||||
url = "https://files.pythonhosted.org/packages/1d/64/a18a487b4391a05b9c7f938b94a16d80305bf0369c6b0b9509e86165e1d3/setuptools-41.0.1.zip";
|
||||
sha256 = "04sns22y2hhsrwfy1mha2lgslvpjsjsz8xws7h2rh5a7ylkd28m2";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -1966,40 +1971,40 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"sshpubkeys" = super.buildPythonPackage {
|
||||
name = "sshpubkeys-2.2.0";
|
||||
name = "sshpubkeys-3.1.0";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."pycrypto"
|
||||
self."cryptography"
|
||||
self."ecdsa"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/27/da/337fabeb3dca6b62039a93ceaa636f25065e0ae92b575b1235342076cf0a/sshpubkeys-2.2.0.tar.gz";
|
||||
sha256 = "0r4kpwzmg96a2x56pllik7dmc3fnqk189v3sfgsi07q2ryrhr6xm";
|
||||
url = "https://files.pythonhosted.org/packages/00/23/f7508a12007c96861c3da811992f14283d79c819d71a217b3e12d5196649/sshpubkeys-3.1.0.tar.gz";
|
||||
sha256 = "105g2li04nm1hb15a2y6hm9m9k7fbrkd5l3gy12w3kgcmsf3k25k";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
};
|
||||
};
|
||||
"subprocess32" = super.buildPythonPackage {
|
||||
name = "subprocess32-3.5.3";
|
||||
name = "subprocess32-3.5.4";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/be/2b/beeba583e9877e64db10b52a96915afc0feabf7144dcbf2a0d0ea68bf73d/subprocess32-3.5.3.tar.gz";
|
||||
sha256 = "1hr5fan8i719hmlmz73hf8rhq74014w07d8ryg7krvvf6692kj3b";
|
||||
url = "https://files.pythonhosted.org/packages/32/c8/564be4d12629b912ea431f1a50eb8b3b9d00f1a0b1ceff17f266be190007/subprocess32-3.5.4.tar.gz";
|
||||
sha256 = "17f7mvwx2271s1wrl0qac3wjqqnrqag866zs3qc8v5wp0k43fagb";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.psfl ];
|
||||
};
|
||||
};
|
||||
"supervisor" = super.buildPythonPackage {
|
||||
name = "supervisor-3.3.5";
|
||||
name = "supervisor-4.0.3";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."meld3"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/ba/65/92575a8757ed576beaee59251f64a3287bde82bdc03964b89df9e1d29e1b/supervisor-3.3.5.tar.gz";
|
||||
sha256 = "1w3ahridzbc6rxfpbyx8lij6pjlcgf2ymzyg53llkjqxalp6sk8v";
|
||||
url = "https://files.pythonhosted.org/packages/97/48/f38bf70bd9282d1a18d591616557cc1a77a1c627d57dff66ead65c891dc8/supervisor-4.0.3.tar.gz";
|
||||
sha256 = "17hla7mx6w5m5jzkkjxgqa8wpswqmfhbhf49f692hw78fg0ans7p";
|
||||
};
|
||||
meta = {
|
||||
license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
|
||||
|
|
@ -2128,22 +2133,22 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"vine" = super.buildPythonPackage {
|
||||
name = "vine-1.2.0";
|
||||
name = "vine-1.3.0";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/46/1a/c94317efa98040c5d50fe3cf9080cafb0372ff5afb0283dc018c751c6746/vine-1.2.0.tar.gz";
|
||||
sha256 = "0xjz2sjbr5jrpjk411b7alkghdskhphgsqqrbi7abqfh2pli6j7f";
|
||||
url = "https://files.pythonhosted.org/packages/1c/e1/79fb8046e607dd6c2ad05c9b8ebac9d0bd31d086a08f02699e96fc5b3046/vine-1.3.0.tar.gz";
|
||||
sha256 = "11ydsbhl1vabndc2r979dv61s6j2b0giq6dgvryifvq1m7bycghk";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.bsdOriginal ];
|
||||
};
|
||||
};
|
||||
"waitress" = super.buildPythonPackage {
|
||||
name = "waitress-1.1.0";
|
||||
name = "waitress-1.3.0";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/3c/68/1c10dd5c556872ceebe88483b0436140048d39de83a84a06a8baa8136f4f/waitress-1.1.0.tar.gz";
|
||||
sha256 = "1a85gyji0kajc3p0s1pwwfm06w4wfxjkvvl4rnrz3h164kbd6g6k";
|
||||
url = "https://files.pythonhosted.org/packages/43/50/9890471320d5ad22761ae46661cf745f487b1c8c4ec49352b99e1078b970/waitress-1.3.0.tar.gz";
|
||||
sha256 = "09j5dzbbcxib7vdskhx39s1qsydlr4n2p2png71d7mjnr9pnwajf";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.zpl21 ];
|
||||
|
|
@ -2218,18 +2223,18 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"webob" = super.buildPythonPackage {
|
||||
name = "webob-1.8.4";
|
||||
name = "webob-1.8.5";
|
||||
doCheck = false;
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/e4/6c/99e322c3d4cc11d9060a67a9bf2f7c9c581f40988c11fffe89bb8c36bc5e/WebOb-1.8.4.tar.gz";
|
||||
sha256 = "16cfg5y4n6sihz59vsmns2yqbfm0gfsn3l5xgz2g0pdhilaib0x4";
|
||||
url = "https://files.pythonhosted.org/packages/9d/1a/0c89c070ee2829c934cb6c7082287c822e28236a4fcf90063e6be7c35532/WebOb-1.8.5.tar.gz";
|
||||
sha256 = "11khpzaxc88q31v25ic330gsf56fwmbdc9b30br8mvp0fmwspah5";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
};
|
||||
};
|
||||
"webtest" = super.buildPythonPackage {
|
||||
name = "webtest-2.0.32";
|
||||
name = "webtest-2.0.33";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."six"
|
||||
|
|
@ -2238,8 +2243,8 @@ self: super: {
|
|||
self."beautifulsoup4"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/27/9f/9e74449d272ffbef4fb3012e6dbc53c0b24822d545e7a33a342f80131e59/WebTest-2.0.32.tar.gz";
|
||||
sha256 = "0qp0nnbazzm4ibjiyqfcn6f230svk09i4g58zg2i9x1ga06h48a2";
|
||||
url = "https://files.pythonhosted.org/packages/a8/b0/ffc9413b637dbe26e291429bb0f6ed731e518d0cd03da28524a8fe2e8a8f/WebTest-2.0.33.tar.gz";
|
||||
sha256 = "1l3z0cwqslsf4rcrhi2gr8kdfh74wn2dw76376i4g9i38gz8wd21";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.mit ];
|
||||
|
|
@ -2293,42 +2298,42 @@ self: super: {
|
|||
};
|
||||
};
|
||||
"zope.deprecation" = super.buildPythonPackage {
|
||||
name = "zope.deprecation-4.3.0";
|
||||
name = "zope.deprecation-4.4.0";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."setuptools"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/a1/18/2dc5e6bfe64fdc3b79411b67464c55bb0b43b127051a20f7f492ab767758/zope.deprecation-4.3.0.tar.gz";
|
||||
sha256 = "095jas41wbxgmw95kwdxqhbc3bgihw2hzj9b3qpdg85apcsf2lkx";
|
||||
url = "https://files.pythonhosted.org/packages/34/da/46e92d32d545dd067b9436279d84c339e8b16de2ca393d7b892bc1e1e9fd/zope.deprecation-4.4.0.tar.gz";
|
||||
sha256 = "1pz2cv7gv9y1r3m0bdv7ks1alagmrn5msm5spwdzkb2by0w36i8d";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.zpl21 ];
|
||||
};
|
||||
};
|
||||
"zope.event" = super.buildPythonPackage {
|
||||
name = "zope.event-4.3.0";
|
||||
name = "zope.event-4.4";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."setuptools"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/9e/d0/54ba59f19a0635f6591b74be259cf6fbf67e73f4edda27b5cd0cf4d26efa/zope.event-4.3.0.tar.gz";
|
||||
sha256 = "1rrkyx42bcq8dkpj23c2v99kczlrg8d39c06q5qpr0vs4hjfmv70";
|
||||
url = "https://files.pythonhosted.org/packages/4c/b2/51c0369adcf5be2334280eed230192ab3b03f81f8efda9ddea6f65cc7b32/zope.event-4.4.tar.gz";
|
||||
sha256 = "1ksbc726av9xacml6jhcfyn828hlhb9xlddpx6fcvnlvmpmpvhk9";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.zpl21 ];
|
||||
};
|
||||
};
|
||||
"zope.interface" = super.buildPythonPackage {
|
||||
name = "zope.interface-4.5.0";
|
||||
name = "zope.interface-4.6.0";
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
self."setuptools"
|
||||
];
|
||||
src = fetchurl {
|
||||
url = "https://files.pythonhosted.org/packages/ac/8a/657532df378c2cd2a1fe6b12be3b4097521570769d4852ec02c24bd3594e/zope.interface-4.5.0.tar.gz";
|
||||
sha256 = "0k67m60ij06wkg82n15qgyn96waf4pmrkhv0njpkfzpmv5q89hsp";
|
||||
url = "https://files.pythonhosted.org/packages/4e/d0/c9d16bd5b38de44a20c6dc5d5ed80a49626fafcb3db9f9efdc2a19026db6/zope.interface-4.6.0.tar.gz";
|
||||
sha256 = "1rgh2x3rcl9r0v0499kf78xy86rnmanajf4ywmqb943wpk50sg8v";
|
||||
};
|
||||
meta = {
|
||||
license = [ pkgs.lib.licenses.zpl21 ];
|
||||
|
|
|
|||
|
|
@ -1,37 +1,31 @@
|
|||
## dependencies
|
||||
|
||||
setuptools-scm==2.1.0
|
||||
amqp==2.3.1
|
||||
# not released authomatic that has updated some oauth providers
|
||||
https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801#egg=authomatic==0.1.0.post1
|
||||
atomicwrites==1.2.1
|
||||
attrs==18.2.0
|
||||
https://code.rhodecode.com/upstream/authomatic/artifacts/download/0-4fe9c041-a567-4f84-be4c-7efa2a606d3c.tar.gz?md5=f6bdc3c769688212db68233e8d2b0383#egg=authomatic==0.1.0.post1
|
||||
|
||||
babel==1.3
|
||||
beaker==1.9.1
|
||||
bleach==3.0.2
|
||||
bleach==3.1.0
|
||||
celery==4.1.1
|
||||
chameleon==2.24
|
||||
channelstream==0.5.2
|
||||
click==7.0
|
||||
colander==1.5.1
|
||||
colander==1.7.0
|
||||
# our custom configobj
|
||||
https://code.rhodecode.com/upstream/configobj/archive/a11ff0a0bd4fbda9e3a91267e720f88329efb4a6.tar.gz?md5=9916c524ea11a6c418217af6b28d4b3c#egg=configobj==5.0.6
|
||||
https://code.rhodecode.com/upstream/configobj/artifacts/download/0-012de99a-b1e1-4f64-a5c0-07a98a41b324.tar.gz?md5=6a513f51fe04b2c18cf84c1395a7c626#egg=configobj==5.0.6
|
||||
cssselect==1.0.3
|
||||
cryptography==2.6.1
|
||||
decorator==4.1.2
|
||||
deform==2.0.7
|
||||
docutils==0.14.0
|
||||
dogpile.cache==0.7.1
|
||||
dogpile.core==0.4.1
|
||||
ecdsa==0.13
|
||||
formencode==1.2.4
|
||||
future==0.14.3
|
||||
futures==3.0.2
|
||||
gnureadline==6.3.8
|
||||
infrae.cache==1.0.1
|
||||
iso8601==0.1.12
|
||||
itsdangerous==0.24
|
||||
jinja2==2.9.6
|
||||
billiard==3.5.0.3
|
||||
kombu==4.2.1
|
||||
lxml==4.2.5
|
||||
mako==1.0.7
|
||||
|
|
@ -40,23 +34,20 @@ markupsafe==1.1.0
|
|||
msgpack-python==0.5.6
|
||||
pyotp==2.2.7
|
||||
packaging==15.2
|
||||
paste==3.0.5
|
||||
pathlib2==2.3.4
|
||||
paste==3.0.8
|
||||
pastedeploy==2.0.1
|
||||
pastescript==3.0.0
|
||||
pathlib2==2.3.3
|
||||
pastescript==3.1.0
|
||||
peppercorn==0.6
|
||||
psutil==5.4.8
|
||||
psutil==5.5.1
|
||||
py-bcrypt==0.4
|
||||
pycrypto==2.6.1
|
||||
pycurl==7.43.0.2
|
||||
pyflakes==0.8.1
|
||||
pygments==2.3.1
|
||||
pycrypto==2.6.1
|
||||
pygments==2.4.2
|
||||
pyparsing==2.3.0
|
||||
pyramid-beaker==0.8
|
||||
pyramid-debugtoolbar==4.5.0
|
||||
pyramid-jinja2==2.7
|
||||
pyramid-mako==1.0.2
|
||||
pyramid==1.10.1
|
||||
pyramid==1.10.4
|
||||
pyramid_mailer==0.15.1
|
||||
python-dateutil
|
||||
python-ldap==3.1.0
|
||||
|
|
@ -74,10 +65,9 @@ routes==2.4.1
|
|||
simplejson==3.16.0
|
||||
six==1.11.0
|
||||
sqlalchemy==1.1.18
|
||||
sshpubkeys==2.2.0
|
||||
subprocess32==3.5.3
|
||||
supervisor==3.3.5
|
||||
tempita==0.5.2
|
||||
sshpubkeys==3.1.0
|
||||
subprocess32==3.5.4
|
||||
supervisor==4.0.3
|
||||
translationstring==1.3
|
||||
urllib3==1.24.1
|
||||
urlobject==2.4.3
|
||||
|
|
@ -85,29 +75,29 @@ venusian==1.2.0
|
|||
weberror==0.10.3
|
||||
webhelpers2==2.0
|
||||
webhelpers==1.3
|
||||
webob==1.8.4
|
||||
webob==1.8.5
|
||||
whoosh==2.7.4
|
||||
wsgiref==0.1.2
|
||||
zope.cachedescriptors==4.3.1
|
||||
zope.deprecation==4.3.0
|
||||
zope.event==4.3.0
|
||||
zope.interface==4.5.0
|
||||
zope.deprecation==4.4.0
|
||||
zope.event==4.4.0
|
||||
zope.interface==4.6.0
|
||||
|
||||
# DB drivers
|
||||
mysql-python==1.2.5
|
||||
pymysql==0.8.1
|
||||
pysqlite==2.8.3
|
||||
psycopg2==2.7.5
|
||||
psycopg2==2.8.3
|
||||
|
||||
# IPYTHON RENDERING
|
||||
# entrypoints backport, pypi version doesn't support egg installs
|
||||
https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1
|
||||
https://code.rhodecode.com/upstream/entrypoints/artifacts/download/0-8e9ee9e4-c4db-409c-b07e-81568fd1832d.tar.gz?md5=3a027b8ff1d257b91fe257de6c43357d#egg=entrypoints==0.2.2.rhodecode-upstream1
|
||||
nbconvert==5.3.1
|
||||
nbformat==4.4.0
|
||||
jupyter_client==5.0.0
|
||||
|
||||
## cli tools
|
||||
alembic==1.0.5
|
||||
alembic==1.0.10
|
||||
invoke==0.13.0
|
||||
bumpversion==0.5.3
|
||||
|
||||
|
|
@ -115,15 +105,14 @@ bumpversion==0.5.3
|
|||
gevent==1.4.0
|
||||
greenlet==0.4.15
|
||||
gunicorn==19.9.0
|
||||
waitress==1.1.0
|
||||
setproctitle==1.1.10
|
||||
waitress==1.3.0
|
||||
|
||||
## debug
|
||||
ipdb==0.11.0
|
||||
ipdb==0.12.0
|
||||
ipython==5.1.0
|
||||
|
||||
## rhodecode-tools, special case
|
||||
https://code.rhodecode.com/rhodecode-tools-ce/archive/v1.2.1.tar.gz?md5=25bc2f7de1da318e547236d3fb463d28#egg=rhodecode-tools==1.2.1
|
||||
https://code.rhodecode.com/rhodecode-tools-ce/artifacts/download/0-10ac93f4-bb7d-4b97-baea-68110743dd5a.tar.gz?md5=962dc77c06aceee62282b98d33149661#egg=rhodecode-tools==1.2.1
|
||||
|
||||
## appenlight
|
||||
appenlight-client==0.6.26
|
||||
|
|
|
|||
19
requirements_pinned.txt
Normal file
19
requirements_pinned.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# contains not directly required libraries we want to pin the version.
|
||||
|
||||
atomicwrites==1.2.1
|
||||
attrs==18.2.0
|
||||
billiard==3.5.0.3
|
||||
chameleon==2.24
|
||||
cffi==1.12.2
|
||||
ecdsa==0.13.2
|
||||
hupper==1.6.1
|
||||
gnureadline==6.3.8
|
||||
jinja2==2.9.6
|
||||
jsonschema==2.6.0
|
||||
pyramid-jinja2==2.7
|
||||
pluggy==0.11.0
|
||||
setproctitle==1.1.10
|
||||
scandir==1.10.0
|
||||
tempita==0.5.2
|
||||
vine==1.3.0
|
||||
configparser==3.7.4
|
||||
|
|
@ -10,7 +10,7 @@ gprof2dot==2017.9.19
|
|||
|
||||
mock==1.0.1
|
||||
cov-core==1.15.0
|
||||
coverage==4.5.1
|
||||
coverage==4.5.3
|
||||
|
||||
webtest==2.0.32
|
||||
webtest==2.0.33
|
||||
beautifulsoup4==4.6.3
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
4.16.2
|
||||
4.17.0
|
||||
|
|
@ -45,7 +45,7 @@ PYRAMID_SETTINGS = {}
|
|||
EXTENSIONS = {}
|
||||
|
||||
__version__ = ('.'.join((str(each) for each in VERSION[:3])))
|
||||
__dbversion__ = 95 # defines current db version for migrations
|
||||
__dbversion__ = 98 # defines current db version for migrations
|
||||
__platform__ = platform.system()
|
||||
__license__ = 'AGPLv3, and Commercial License'
|
||||
__author__ = 'RhodeCode GmbH'
|
||||
|
|
|
|||
|
|
@ -37,11 +37,11 @@ class TestCommentCommit(object):
|
|||
assert_error(id_, expected, given=response.body)
|
||||
|
||||
@pytest.mark.parametrize("commit_id, expected_err", [
|
||||
('abcabca', {'hg': 'Commit {commit} does not exist for {repo}',
|
||||
'git': 'Commit {commit} does not exist for {repo}',
|
||||
('abcabca', {'hg': 'Commit {commit} does not exist for `{repo}`',
|
||||
'git': 'Commit {commit} does not exist for `{repo}`',
|
||||
'svn': 'Commit id {commit} not understood.'}),
|
||||
('idontexist', {'hg': 'Commit {commit} does not exist for {repo}',
|
||||
'git': 'Commit {commit} does not exist for {repo}',
|
||||
('idontexist', {'hg': 'Commit {commit} does not exist for `{repo}`',
|
||||
'git': 'Commit {commit} does not exist for `{repo}`',
|
||||
'svn': 'Commit id {commit} not understood.'}),
|
||||
])
|
||||
def test_api_comment_commit_wrong_hash(self, backend, commit_id, expected_err):
|
||||
|
|
@ -53,7 +53,7 @@ class TestCommentCommit(object):
|
|||
|
||||
expected_err = expected_err[backend.alias]
|
||||
expected_err = expected_err.format(
|
||||
repo=backend.repo.scm_instance(), commit=commit_id)
|
||||
repo=backend.repo.scm_instance().name, commit=commit_id)
|
||||
assert_error(id_, expected_err, given=response.body)
|
||||
|
||||
@pytest.mark.parametrize("status_change, message, commit_id", [
|
||||
|
|
|
|||
93
rhodecode/api/tests/test_fts_search.py
Normal file
93
rhodecode/api/tests/test_fts_search.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-2019 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import pytest
|
||||
from rhodecode.tests import HG_REPO
|
||||
from rhodecode.api.tests.utils import (
|
||||
build_data, api_call, assert_error, assert_ok)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("testuser_api", "app")
|
||||
class TestApiSearch(object):
|
||||
|
||||
@pytest.mark.parametrize("query, expected_hits, expected_paths", [
|
||||
('todo', 23, [
|
||||
'vcs/backends/hg/inmemory.py',
|
||||
'vcs/tests/test_git.py']),
|
||||
('extension:rst installation', 6, [
|
||||
'docs/index.rst',
|
||||
'docs/installation.rst']),
|
||||
('def repo', 87, [
|
||||
'vcs/tests/test_git.py',
|
||||
'vcs/tests/test_changesets.py']),
|
||||
('repository:%s def test' % HG_REPO, 18, [
|
||||
'vcs/tests/test_git.py',
|
||||
'vcs/tests/test_changesets.py']),
|
||||
('"def main"', 9, [
|
||||
'vcs/__init__.py',
|
||||
'vcs/tests/__init__.py',
|
||||
'vcs/utils/progressbar.py']),
|
||||
('owner:test_admin', 358, [
|
||||
'vcs/tests/base.py',
|
||||
'MANIFEST.in',
|
||||
'vcs/utils/termcolors.py',
|
||||
'docs/theme/ADC/static/documentation.png']),
|
||||
('owner:test_admin def main', 72, [
|
||||
'vcs/__init__.py',
|
||||
'vcs/tests/test_utils_filesize.py',
|
||||
'vcs/tests/test_cli.py']),
|
||||
('owner:michał test', 0, []),
|
||||
])
|
||||
def test_search_content_results(self, query, expected_hits, expected_paths):
|
||||
id_, params = build_data(
|
||||
self.apikey_regular, 'search',
|
||||
search_query=query,
|
||||
search_type='content')
|
||||
|
||||
response = api_call(self.app, params)
|
||||
json_response = response.json
|
||||
|
||||
assert json_response['result']['item_count'] == expected_hits
|
||||
paths = [x['f_path'] for x in json_response['result']['results']]
|
||||
|
||||
for expected_path in expected_paths:
|
||||
assert expected_path in paths
|
||||
|
||||
@pytest.mark.parametrize("query, expected_hits, expected_paths", [
|
||||
('readme.rst', 3, []),
|
||||
('test*', 75, []),
|
||||
('*model*', 1, []),
|
||||
('extension:rst', 48, []),
|
||||
('extension:rst api', 24, []),
|
||||
])
|
||||
def test_search_file_paths(self, query, expected_hits, expected_paths):
|
||||
id_, params = build_data(
|
||||
self.apikey_regular, 'search',
|
||||
search_query=query,
|
||||
search_type='path')
|
||||
|
||||
response = api_call(self.app, params)
|
||||
json_response = response.json
|
||||
|
||||
assert json_response['result']['item_count'] == expected_hits
|
||||
paths = [x['f_path'] for x in json_response['result']['results']]
|
||||
|
||||
for expected_path in expected_paths:
|
||||
assert expected_path in paths
|
||||
|
|
@ -44,6 +44,7 @@ class TestGetRepo(object):
|
|||
self, apikey_attr, expect_secrets, cache_param, backend,
|
||||
user_util):
|
||||
repo = backend.create_repo()
|
||||
repo_id = repo.repo_id
|
||||
usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
|
||||
group = user_util.create_user_group(members=[usr])
|
||||
user_util.grant_user_group_permission_to_repo(
|
||||
|
|
@ -64,6 +65,8 @@ class TestGetRepo(object):
|
|||
permissions = expected_permissions(repo)
|
||||
|
||||
followers = []
|
||||
|
||||
repo = RepoModel().get(repo_id)
|
||||
for user in repo.followers:
|
||||
followers.append(user.user.get_api_data(
|
||||
include_secrets=expect_secrets))
|
||||
|
|
@ -84,6 +87,7 @@ class TestGetRepo(object):
|
|||
# TODO: Depending on which tests are running before this one, we
|
||||
# start with a different number of permissions in the database.
|
||||
repo = RepoModel().get_by_repo_name(backend.repo_name)
|
||||
repo_id = repo.repo_id
|
||||
permission_count = len(repo.repo_to_perm)
|
||||
|
||||
RepoModel().grant_user_permission(repo=backend.repo_name,
|
||||
|
|
@ -102,6 +106,8 @@ class TestGetRepo(object):
|
|||
permissions = expected_permissions(repo)
|
||||
|
||||
followers = []
|
||||
|
||||
repo = RepoModel().get(repo_id)
|
||||
for user in repo.followers:
|
||||
followers.append(user.user.get_api_data())
|
||||
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ def get_repo_nodes(request, apiuser, repoid, revision, root_path,
|
|||
result: [
|
||||
{
|
||||
"binary": false,
|
||||
"content": "File line\nLine2\n",
|
||||
"content": "File line",
|
||||
"extension": "md",
|
||||
"lines": 2,
|
||||
"md5": "059fa5d29b19c0657e384749480f6422",
|
||||
|
|
@ -529,6 +529,7 @@ def get_repo_file(request, apiuser, repoid, commit_id, file_path,
|
|||
:param cache: Use internal caches for fetching files. If disabled fetching
|
||||
files is slower but more memory efficient
|
||||
:type cache: Optional(bool)
|
||||
|
||||
Example output:
|
||||
|
||||
.. code-block:: bash
|
||||
|
|
|
|||
112
rhodecode/api/views/search_api.py
Normal file
112
rhodecode/api/views/search_api.py
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2011-2019 RhodeCode GmbH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License, version 3
|
||||
# (only), as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
|
||||
import logging
|
||||
|
||||
from rhodecode.api import jsonrpc_method
|
||||
from rhodecode.api.exc import JSONRPCValidationError
|
||||
from rhodecode.api.utils import Optional
|
||||
from rhodecode.lib.index import searcher_from_config
|
||||
from rhodecode.model import validation_schema
|
||||
from rhodecode.model.validation_schema.schemas import search_schema
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@jsonrpc_method()
|
||||
def search(request, apiuser, search_query, search_type, page_limit=Optional(10),
|
||||
page=Optional(1), search_sort=Optional('newfirst'),
|
||||
repo_name=Optional(None), repo_group_name=Optional(None)):
|
||||
"""
|
||||
Fetch Full Text Search results using API.
|
||||
|
||||
:param apiuser: This is filled automatically from the |authtoken|.
|
||||
:type apiuser: AuthUser
|
||||
:param search_query: Search query.
|
||||
:type search_query: str
|
||||
:param search_type: Search type. The following are valid options:
|
||||
* commit
|
||||
* content
|
||||
* path
|
||||
:type search_type: str
|
||||
:param page_limit: Page item limit, from 1 to 500. Default 10 items.
|
||||
:type page_limit: Optional(int)
|
||||
:param page: Page number. Default first page.
|
||||
:type page: Optional(int)
|
||||
:param search_sort: Search sort order. Default newfirst. The following are valid options:
|
||||
* newfirst
|
||||
* oldfirst
|
||||
:type search_sort: Optional(str)
|
||||
:param repo_name: Filter by one repo. Default is all.
|
||||
:type repo_name: Optional(str)
|
||||
:param repo_group_name: Filter by one repo group. Default is all.
|
||||
:type repo_group_name: Optional(str)
|
||||
"""
|
||||
|
||||
data = {'execution_time': ''}
|
||||
repo_name = Optional.extract(repo_name)
|
||||
repo_group_name = Optional.extract(repo_group_name)
|
||||
|
||||
schema = search_schema.SearchParamsSchema()
|
||||
|
||||
try:
|
||||
search_params = schema.deserialize(
|
||||
dict(search_query=search_query,
|
||||
search_type=search_type,
|
||||
search_sort=Optional.extract(search_sort),
|
||||
page_limit=Optional.extract(page_limit),
|
||||
requested_page=Optional.extract(page))
|
||||
)
|
||||
except validation_schema.Invalid as err:
|
||||
raise JSONRPCValidationError(colander_exc=err)
|
||||
|
||||
search_query = search_params.get('search_query')
|
||||
search_type = search_params.get('search_type')
|
||||
search_sort = search_params.get('search_sort')
|
||||
|
||||
if search_params.get('search_query'):
|
||||
page_limit = search_params['page_limit']
|
||||
requested_page = search_params['requested_page']
|
||||
|
||||
searcher = searcher_from_config(request.registry.settings)
|
||||
|
||||
try:
|
||||
search_result = searcher.search(
|
||||
search_query, search_type, apiuser, repo_name, repo_group_name,
|
||||
requested_page=requested_page, page_limit=page_limit, sort=search_sort)
|
||||
|
||||
data.update(dict(
|
||||
results=list(search_result['results']), page=requested_page,
|
||||
item_count=search_result['count'],
|
||||
items_per_page=page_limit))
|
||||
finally:
|
||||
searcher.cleanup()
|
||||
|
||||
if not search_result['error']:
|
||||
data['execution_time'] = '%s results (%.3f seconds)' % (
|
||||
search_result['count'],
|
||||
search_result['runtime'])
|
||||
else:
|
||||
node = schema['search_query']
|
||||
raise JSONRPCValidationError(
|
||||
colander_exc=validation_schema.Invalid(node, search_result['error']))
|
||||
|
||||
return data
|
||||
|
|
@ -168,6 +168,28 @@ class BaseAppView(object):
|
|||
from rhodecode.lib.base import attach_context_attributes
|
||||
attach_context_attributes(c, self.request, self.request.user.user_id)
|
||||
|
||||
c.is_super_admin = c.auth_user.is_admin
|
||||
|
||||
c.can_create_repo = c.is_super_admin
|
||||
c.can_create_repo_group = c.is_super_admin
|
||||
c.can_create_user_group = c.is_super_admin
|
||||
|
||||
c.is_delegated_admin = False
|
||||
|
||||
if not c.auth_user.is_default and not c.is_super_admin:
|
||||
c.can_create_repo = h.HasPermissionAny('hg.create.repository')(
|
||||
user=self.request.user)
|
||||
repositories = c.auth_user.repositories_admin or c.can_create_repo
|
||||
|
||||
c.can_create_repo_group = h.HasPermissionAny('hg.repogroup.create.true')(
|
||||
user=self.request.user)
|
||||
repository_groups = c.auth_user.repository_groups_admin or c.can_create_repo_group
|
||||
|
||||
c.can_create_user_group = h.HasPermissionAny('hg.usergroup.create.true')(
|
||||
user=self.request.user)
|
||||
user_groups = c.auth_user.user_groups_admin or c.can_create_user_group
|
||||
# delegated admin can create, or manage some objects
|
||||
c.is_delegated_admin = repositories or repository_groups or user_groups
|
||||
return c
|
||||
|
||||
def _get_template_context(self, tmpl_args, **kwargs):
|
||||
|
|
@ -215,12 +237,17 @@ class RepoAppView(BaseAppView):
|
|||
c.rhodecode_db_repo = self.db_repo
|
||||
c.repo_name = self.db_repo_name
|
||||
c.repository_pull_requests = self.db_repo_pull_requests
|
||||
c.repository_is_user_following = ScmModel().is_following_repo(
|
||||
self.db_repo_name, self._rhodecode_user.user_id)
|
||||
self.path_filter = PathFilter(None)
|
||||
|
||||
c.repository_requirements_missing = {}
|
||||
try:
|
||||
self.rhodecode_vcs_repo = self.db_repo.scm_instance()
|
||||
if self.rhodecode_vcs_repo:
|
||||
# NOTE(marcink):
|
||||
# comparison to None since if it's an object __bool__ is expensive to
|
||||
# calculate
|
||||
if self.rhodecode_vcs_repo is not None:
|
||||
path_perms = self.rhodecode_vcs_repo.get_path_permissions(
|
||||
c.auth_user.username)
|
||||
self.path_filter = PathFilter(path_perms)
|
||||
|
|
|
|||
|
|
@ -85,8 +85,6 @@ class NavigationRegistry(object):
|
|||
'admin_settings_hooks'),
|
||||
NavEntry('search', _('Full Text Search'),
|
||||
'admin_settings_search'),
|
||||
NavEntry('integrations', _('Integrations'),
|
||||
'global_integrations_home'),
|
||||
NavEntry('system', _('System Info'),
|
||||
'admin_settings_system'),
|
||||
NavEntry('exceptions', _('Exceptions Tracker'),
|
||||
|
|
|
|||
|
|
@ -423,6 +423,10 @@ def admin_routes(config):
|
|||
name='repo_groups',
|
||||
pattern='/repo_groups')
|
||||
|
||||
config.add_route(
|
||||
name='repo_groups_data',
|
||||
pattern='/repo_groups_data')
|
||||
|
||||
config.add_route(
|
||||
name='repo_group_new',
|
||||
pattern='/repo_group/new')
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ def route_path(name, params=None, **kwargs):
|
|||
|
||||
class TestAdminMainView(TestController):
|
||||
|
||||
def test_redirect_admin_home(self):
|
||||
def test_access_admin_home(self):
|
||||
self.log_user()
|
||||
response = self.app.get(route_path('admin_home'), status=302)
|
||||
assert response.location.endswith('/audit_logs')
|
||||
response = self.app.get(route_path('admin_home'), status=200)
|
||||
response.mustcontain("Administration area")
|
||||
|
||||
def test_redirect_pull_request_view(self, view):
|
||||
self.log_user()
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ import pytest
|
|||
|
||||
from rhodecode.apps._base import ADMIN_PREFIX
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.model.db import Repository, UserRepoToPerm, User
|
||||
from rhodecode.model.db import Repository, UserRepoToPerm, User, RepoGroup
|
||||
from rhodecode.model.meta import Session
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.tests import (
|
||||
assert_session_flash, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH, TestController)
|
||||
assert_session_flash, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH)
|
||||
from rhodecode.tests.fixture import Fixture
|
||||
|
||||
fixture = Fixture()
|
||||
|
|
@ -38,6 +38,7 @@ def route_path(name, params=None, **kwargs):
|
|||
|
||||
base_url = {
|
||||
'repo_groups': ADMIN_PREFIX + '/repo_groups',
|
||||
'repo_groups_data': ADMIN_PREFIX + '/repo_groups_data',
|
||||
'repo_group_new': ADMIN_PREFIX + '/repo_group/new',
|
||||
'repo_group_create': ADMIN_PREFIX + '/repo_group/create',
|
||||
|
||||
|
|
@ -59,13 +60,30 @@ def _get_permission_for_user(user, repo):
|
|||
|
||||
@pytest.mark.usefixtures("app")
|
||||
class TestAdminRepositoryGroups(object):
|
||||
def test_show_repo_groups(self, autologin_user):
|
||||
response = self.app.get(route_path('repo_groups'))
|
||||
response.mustcontain('data: []')
|
||||
|
||||
def test_show_repo_groups_after_creating_group(self, autologin_user):
|
||||
def test_show_repo_groups(self, autologin_user):
|
||||
self.app.get(route_path('repo_groups'))
|
||||
|
||||
def test_show_repo_groups_data(self, autologin_user, xhr_header):
|
||||
response = self.app.get(route_path(
|
||||
'repo_groups_data'), extra_environ=xhr_header)
|
||||
|
||||
all_repo_groups = RepoGroup.query().count()
|
||||
assert response.json['recordsTotal'] == all_repo_groups
|
||||
|
||||
def test_show_repo_groups_data_filtered(self, autologin_user, xhr_header):
|
||||
response = self.app.get(route_path(
|
||||
'repo_groups_data', params={'search[value]': 'empty_search'}),
|
||||
extra_environ=xhr_header)
|
||||
|
||||
all_repo_groups = RepoGroup.query().count()
|
||||
assert response.json['recordsTotal'] == all_repo_groups
|
||||
assert response.json['recordsFiltered'] == 0
|
||||
|
||||
def test_show_repo_groups_after_creating_group(self, autologin_user, xhr_header):
|
||||
fixture.create_repo_group('test_repo_group')
|
||||
response = self.app.get(route_path('repo_groups'))
|
||||
response = self.app.get(route_path(
|
||||
'repo_groups_data'), extra_environ=xhr_header)
|
||||
response.mustcontain('"name_raw": "test_repo_group"')
|
||||
fixture.destroy_repo_group('test_repo_group')
|
||||
|
||||
|
|
|
|||
|
|
@ -214,8 +214,7 @@ class TestAdminSettingsGlobal(object):
|
|||
})
|
||||
|
||||
response = response.follow()
|
||||
response.mustcontain(
|
||||
"""<div class="branding">- %s</div>""" % new_title)
|
||||
response.mustcontain(new_title)
|
||||
|
||||
def post_and_verify_settings(self, settings):
|
||||
old_title = 'RhodeCode'
|
||||
|
|
|
|||
|
|
@ -173,4 +173,4 @@ class TestAdminUsersSshKeysView(TestController):
|
|||
|
||||
response.mustcontain('Private key')
|
||||
response.mustcontain('Public key')
|
||||
response.mustcontain('-----BEGIN RSA PRIVATE KEY-----')
|
||||
response.mustcontain('-----BEGIN PRIVATE KEY-----')
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class ExceptionsTrackerView(BaseAppView):
|
|||
count +=1
|
||||
return count
|
||||
|
||||
def get_all_exceptions(self, read_metadata=False, limit=None):
|
||||
def get_all_exceptions(self, read_metadata=False, limit=None, type_filter=None):
|
||||
exc_store_path = exc_tracking.get_exc_store()
|
||||
exception_list = []
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ class ExceptionsTrackerView(BaseAppView):
|
|||
return val.split('_')[-1]
|
||||
except Exception:
|
||||
return 0
|
||||
count = 0
|
||||
|
||||
for fname in reversed(sorted(os.listdir(exc_store_path), key=key_sorter)):
|
||||
|
||||
parts = fname.split('_', 2)
|
||||
|
|
@ -83,13 +83,17 @@ class ExceptionsTrackerView(BaseAppView):
|
|||
except Exception:
|
||||
log.exception('Failed to read exc data from:{}'.format(full_path))
|
||||
pass
|
||||
|
||||
# convert our timestamp to a date obj, for nicer representation
|
||||
exc['exc_utc_date'] = time_to_utcdatetime(exc['exc_timestamp'])
|
||||
exception_list.append(exc)
|
||||
|
||||
count += 1
|
||||
if limit and count >= limit:
|
||||
type_present = exc.get('exc_type')
|
||||
if type_filter:
|
||||
if type_present and type_present == type_filter:
|
||||
exception_list.append(exc)
|
||||
else:
|
||||
exception_list.append(exc)
|
||||
|
||||
if limit and len(exception_list) >= limit:
|
||||
break
|
||||
return exception_list
|
||||
|
||||
|
|
@ -103,8 +107,10 @@ class ExceptionsTrackerView(BaseAppView):
|
|||
c = self.load_default_context()
|
||||
c.active = 'exceptions_browse'
|
||||
c.limit = safe_int(self.request.GET.get('limit')) or 50
|
||||
c.type_filter = self.request.GET.get('type_filter')
|
||||
c.next_limit = c.limit + 50
|
||||
c.exception_list = self.get_all_exceptions(read_metadata=True, limit=c.limit)
|
||||
c.exception_list = self.get_all_exceptions(
|
||||
read_metadata=True, limit=c.limit, type_filter=c.type_filter)
|
||||
c.exception_list_count = self.count_all_exceptions()
|
||||
c.exception_store_dir = exc_tracking.get_exc_store()
|
||||
return self._get_template_context(c)
|
||||
|
|
@ -132,12 +138,20 @@ class ExceptionsTrackerView(BaseAppView):
|
|||
def exception_delete_all(self):
|
||||
_ = self.request.translate
|
||||
c = self.load_default_context()
|
||||
type_filter = self.request.POST.get('type_filter')
|
||||
|
||||
c.active = 'exceptions'
|
||||
all_exc = self.get_all_exceptions()
|
||||
exc_count = len(all_exc)
|
||||
all_exc = self.get_all_exceptions(read_metadata=bool(type_filter), type_filter=type_filter)
|
||||
exc_count = 0
|
||||
|
||||
for exc in all_exc:
|
||||
exc_tracking.delete_exception(exc['exc_id'], prefix=None)
|
||||
if type_filter:
|
||||
if exc.get('exc_type') == type_filter:
|
||||
exc_tracking.delete_exception(exc['exc_id'], prefix=None)
|
||||
exc_count += 1
|
||||
else:
|
||||
exc_tracking.delete_exception(exc['exc_id'], prefix=None)
|
||||
exc_count += 1
|
||||
|
||||
h.flash(_('Removed {} Exceptions').format(exc_count), category='success')
|
||||
raise HTTPFound(h.route_path('admin_settings_exception_tracker'))
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@
|
|||
|
||||
import logging
|
||||
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
|
||||
from pyramid.view import view_config
|
||||
|
||||
from rhodecode.apps._base import BaseAppView
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
|
||||
from rhodecode.lib.auth import (LoginRequired, NotAnonymous)
|
||||
from rhodecode.model.db import PullRequest
|
||||
|
||||
|
||||
|
|
@ -33,14 +33,23 @@ log = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class AdminMainView(BaseAppView):
|
||||
def load_default_context(self):
|
||||
c = self._get_local_tmpl_context()
|
||||
return c
|
||||
|
||||
@LoginRequired()
|
||||
@HasPermissionAllDecorator('hg.admin')
|
||||
@NotAnonymous()
|
||||
@view_config(
|
||||
route_name='admin_home', request_method='GET')
|
||||
route_name='admin_home', request_method='GET',
|
||||
renderer='rhodecode:templates/admin/main.mako')
|
||||
def admin_main(self):
|
||||
# redirect _admin to audit logs...
|
||||
raise HTTPFound(h.route_path('admin_audit_logs'))
|
||||
c = self.load_default_context()
|
||||
c.active = 'admin'
|
||||
|
||||
if not (c.is_super_admin or c.is_delegated_admin):
|
||||
raise HTTPNotFound()
|
||||
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@view_config(route_name='pull_requests_global_0', request_method='GET')
|
||||
|
|
@ -49,8 +58,7 @@ class AdminMainView(BaseAppView):
|
|||
def pull_requests(self):
|
||||
"""
|
||||
Global redirect for Pull Requests
|
||||
|
||||
:param pull_request_id: id of pull requests in the system
|
||||
pull_request_id: id of pull requests in the system
|
||||
"""
|
||||
|
||||
pull_request = PullRequest.get_or_404(
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
# This program is dual-licensed. If you wish to learn more about the
|
||||
# RhodeCode Enterprise Edition, including its added features, Support services,
|
||||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import formencode
|
||||
import formencode.htmlfill
|
||||
|
|
@ -30,16 +30,16 @@ from pyramid.response import Response
|
|||
from rhodecode import events
|
||||
from rhodecode.apps._base import BaseAppView, DataGridAppView
|
||||
|
||||
from rhodecode.lib.ext_json import json
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, CSRFRequired, NotAnonymous,
|
||||
HasPermissionAny, HasRepoGroupPermissionAny)
|
||||
from rhodecode.lib import helpers as h, audit_logger
|
||||
from rhodecode.lib.utils2 import safe_int, safe_unicode
|
||||
from rhodecode.lib.utils2 import safe_int, safe_unicode, datetime_to_time
|
||||
from rhodecode.model.forms import RepoGroupForm
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.scm import RepoGroupList
|
||||
from rhodecode.model.db import Session, RepoGroup
|
||||
from rhodecode.model.db import (
|
||||
or_, count, func, in_filter_generator, Session, RepoGroup, User, Repository)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -88,23 +88,169 @@ class AdminRepoGroupsView(BaseAppView, DataGridAppView):
|
|||
return False
|
||||
return False
|
||||
|
||||
# permission check in data loading of
|
||||
# `repo_group_list_data` via RepoGroupList
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
# perms check inside
|
||||
@view_config(
|
||||
route_name='repo_groups', request_method='GET',
|
||||
renderer='rhodecode:templates/admin/repo_groups/repo_groups.mako')
|
||||
def repo_group_list(self):
|
||||
c = self.load_default_context()
|
||||
|
||||
repo_group_list = RepoGroup.get_all_repo_groups()
|
||||
repo_group_list_acl = RepoGroupList(
|
||||
repo_group_list, perm_set=['group.admin'])
|
||||
repo_group_data = RepoGroupModel().get_repo_groups_as_dict(
|
||||
repo_group_list=repo_group_list_acl, admin=True)
|
||||
c.data = json.dumps(repo_group_data)
|
||||
return self._get_template_context(c)
|
||||
|
||||
# permission check inside
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
@view_config(
|
||||
route_name='repo_groups_data', request_method='GET',
|
||||
renderer='json_ext', xhr=True)
|
||||
def repo_group_list_data(self):
|
||||
self.load_default_context()
|
||||
column_map = {
|
||||
'name_raw': 'group_name_hash',
|
||||
'desc': 'group_description',
|
||||
'last_change_raw': 'updated_on',
|
||||
'top_level_repos': 'repos_total',
|
||||
'owner': 'user_username',
|
||||
}
|
||||
draw, start, limit = self._extract_chunk(self.request)
|
||||
search_q, order_by, order_dir = self._extract_ordering(
|
||||
self.request, column_map=column_map)
|
||||
|
||||
_render = self.request.get_partial_renderer(
|
||||
'rhodecode:templates/data_table/_dt_elements.mako')
|
||||
c = _render.get_call_context()
|
||||
|
||||
def quick_menu(repo_group_name):
|
||||
return _render('quick_repo_group_menu', repo_group_name)
|
||||
|
||||
def repo_group_lnk(repo_group_name):
|
||||
return _render('repo_group_name', repo_group_name)
|
||||
|
||||
def last_change(last_change):
|
||||
if isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
|
||||
delta = datetime.timedelta(
|
||||
seconds=(datetime.datetime.now() - datetime.datetime.utcnow()).seconds)
|
||||
last_change = last_change + delta
|
||||
return _render("last_change", last_change)
|
||||
|
||||
def desc(desc, personal):
|
||||
return _render(
|
||||
'repo_group_desc', desc, personal, c.visual.stylify_metatags)
|
||||
|
||||
def repo_group_actions(repo_group_id, repo_group_name, gr_count):
|
||||
return _render(
|
||||
'repo_group_actions', repo_group_id, repo_group_name, gr_count)
|
||||
|
||||
def user_profile(username):
|
||||
return _render('user_profile', username)
|
||||
|
||||
auth_repo_group_list = RepoGroupList(
|
||||
RepoGroup.query().all(), perm_set=['group.admin'])
|
||||
|
||||
allowed_ids = [-1]
|
||||
for repo_group in auth_repo_group_list:
|
||||
allowed_ids.append(repo_group.group_id)
|
||||
|
||||
repo_groups_data_total_count = RepoGroup.query()\
|
||||
.filter(or_(
|
||||
# generate multiple IN to fix limitation problems
|
||||
*in_filter_generator(RepoGroup.group_id, allowed_ids)
|
||||
)) \
|
||||
.count()
|
||||
|
||||
repo_groups_data_total_inactive_count = RepoGroup.query()\
|
||||
.filter(RepoGroup.group_id.in_(allowed_ids))\
|
||||
.count()
|
||||
|
||||
repo_count = count(Repository.repo_id)
|
||||
base_q = Session.query(
|
||||
RepoGroup.group_name,
|
||||
RepoGroup.group_name_hash,
|
||||
RepoGroup.group_description,
|
||||
RepoGroup.group_id,
|
||||
RepoGroup.personal,
|
||||
RepoGroup.updated_on,
|
||||
User,
|
||||
repo_count.label('repos_count')
|
||||
) \
|
||||
.filter(or_(
|
||||
# generate multiple IN to fix limitation problems
|
||||
*in_filter_generator(RepoGroup.group_id, allowed_ids)
|
||||
)) \
|
||||
.outerjoin(Repository) \
|
||||
.join(User, User.user_id == RepoGroup.user_id) \
|
||||
.group_by(RepoGroup, User)
|
||||
|
||||
if search_q:
|
||||
like_expression = u'%{}%'.format(safe_unicode(search_q))
|
||||
base_q = base_q.filter(or_(
|
||||
RepoGroup.group_name.ilike(like_expression),
|
||||
))
|
||||
|
||||
repo_groups_data_total_filtered_count = base_q.count()
|
||||
# the inactive isn't really used, but we still make it same as other data grids
|
||||
# which use inactive (users,user groups)
|
||||
repo_groups_data_total_filtered_inactive_count = repo_groups_data_total_filtered_count
|
||||
|
||||
sort_defined = False
|
||||
if order_by == 'group_name':
|
||||
sort_col = func.lower(RepoGroup.group_name)
|
||||
sort_defined = True
|
||||
elif order_by == 'repos_total':
|
||||
sort_col = repo_count
|
||||
sort_defined = True
|
||||
elif order_by == 'user_username':
|
||||
sort_col = User.username
|
||||
else:
|
||||
sort_col = getattr(RepoGroup, order_by, None)
|
||||
|
||||
if sort_defined or sort_col:
|
||||
if order_dir == 'asc':
|
||||
sort_col = sort_col.asc()
|
||||
else:
|
||||
sort_col = sort_col.desc()
|
||||
|
||||
base_q = base_q.order_by(sort_col)
|
||||
base_q = base_q.offset(start).limit(limit)
|
||||
|
||||
# authenticated access to user groups
|
||||
auth_repo_group_list = base_q.all()
|
||||
|
||||
repo_groups_data = []
|
||||
for repo_gr in auth_repo_group_list:
|
||||
row = {
|
||||
"menu": quick_menu(repo_gr.group_name),
|
||||
"name": repo_group_lnk(repo_gr.group_name),
|
||||
"name_raw": repo_gr.group_name,
|
||||
"last_change": last_change(repo_gr.updated_on),
|
||||
"last_change_raw": datetime_to_time(repo_gr.updated_on),
|
||||
|
||||
"last_changeset": "",
|
||||
"last_changeset_raw": "",
|
||||
|
||||
"desc": desc(repo_gr.group_description, repo_gr.personal),
|
||||
"owner": user_profile(repo_gr.User.username),
|
||||
"top_level_repos": repo_gr.repos_count,
|
||||
"action": repo_group_actions(
|
||||
repo_gr.group_id, repo_gr.group_name, repo_gr.repos_count),
|
||||
|
||||
}
|
||||
|
||||
repo_groups_data.append(row)
|
||||
|
||||
data = ({
|
||||
'draw': draw,
|
||||
'data': repo_groups_data,
|
||||
'recordsTotal': repo_groups_data_total_count,
|
||||
'recordsTotalInactive': repo_groups_data_total_inactive_count,
|
||||
'recordsFiltered': repo_groups_data_total_filtered_count,
|
||||
'recordsFilteredInactive': repo_groups_data_total_filtered_inactive_count,
|
||||
})
|
||||
|
||||
return data
|
||||
|
||||
@LoginRequired()
|
||||
@NotAnonymous()
|
||||
# perm checks inside
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ from rhodecode.model.forms import UserGroupForm
|
|||
from rhodecode.model.permission import PermissionModel
|
||||
from rhodecode.model.scm import UserGroupList
|
||||
from rhodecode.model.db import (
|
||||
or_, count, User, UserGroup, UserGroupMember)
|
||||
or_, count, User, UserGroup, UserGroupMember, in_filter_generator)
|
||||
from rhodecode.model.meta import Session
|
||||
from rhodecode.model.user_group import UserGroupModel
|
||||
from rhodecode.model.db import true
|
||||
|
|
@ -107,11 +107,17 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
|
|||
allowed_ids.append(user_group.users_group_id)
|
||||
|
||||
user_groups_data_total_count = UserGroup.query()\
|
||||
.filter(UserGroup.users_group_id.in_(allowed_ids))\
|
||||
.filter(or_(
|
||||
# generate multiple IN to fix limitation problems
|
||||
*in_filter_generator(UserGroup.users_group_id, allowed_ids)
|
||||
))\
|
||||
.count()
|
||||
|
||||
user_groups_data_total_inactive_count = UserGroup.query()\
|
||||
.filter(UserGroup.users_group_id.in_(allowed_ids))\
|
||||
.filter(or_(
|
||||
# generate multiple IN to fix limitation problems
|
||||
*in_filter_generator(UserGroup.users_group_id, allowed_ids)
|
||||
))\
|
||||
.filter(UserGroup.users_group_active != true()).count()
|
||||
|
||||
member_count = count(UserGroupMember.user_id)
|
||||
|
|
@ -123,11 +129,14 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
|
|||
UserGroup.group_data,
|
||||
User,
|
||||
member_count.label('member_count')
|
||||
) \
|
||||
.filter(UserGroup.users_group_id.in_(allowed_ids)) \
|
||||
.outerjoin(UserGroupMember) \
|
||||
.join(User, User.user_id == UserGroup.user_id) \
|
||||
.group_by(UserGroup, User)
|
||||
) \
|
||||
.filter(or_(
|
||||
# generate multiple IN to fix limitation problems
|
||||
*in_filter_generator(UserGroup.users_group_id, allowed_ids)
|
||||
)) \
|
||||
.outerjoin(UserGroupMember) \
|
||||
.join(User, User.user_id == UserGroup.user_id) \
|
||||
.group_by(UserGroup, User)
|
||||
|
||||
base_q_inactive = base_q.filter(UserGroup.users_group_active != true())
|
||||
|
||||
|
|
@ -141,14 +150,16 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
|
|||
user_groups_data_total_filtered_count = base_q.count()
|
||||
user_groups_data_total_filtered_inactive_count = base_q_inactive.count()
|
||||
|
||||
sort_defined = False
|
||||
if order_by == 'members_total':
|
||||
sort_col = member_count
|
||||
sort_defined = True
|
||||
elif order_by == 'user_username':
|
||||
sort_col = User.username
|
||||
else:
|
||||
sort_col = getattr(UserGroup, order_by, None)
|
||||
|
||||
if isinstance(sort_col, count) or sort_col:
|
||||
if sort_defined or sort_col:
|
||||
if order_dir == 'asc':
|
||||
sort_col = sort_col.asc()
|
||||
else:
|
||||
|
|
@ -162,7 +173,7 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
|
|||
|
||||
user_groups_data = []
|
||||
for user_gr in auth_user_group_list:
|
||||
user_groups_data.append({
|
||||
row = {
|
||||
"users_group_name": user_group_name(user_gr.users_group_name),
|
||||
"name_raw": h.escape(user_gr.users_group_name),
|
||||
"description": h.escape(user_gr.user_group_description),
|
||||
|
|
@ -175,7 +186,8 @@ class AdminUserGroupsView(BaseAppView, DataGridAppView):
|
|||
"owner": user_profile(user_gr.User.username),
|
||||
"action": user_group_actions(
|
||||
user_gr.users_group_id, user_gr.users_group_name)
|
||||
})
|
||||
}
|
||||
user_groups_data.append(row)
|
||||
|
||||
data = ({
|
||||
'draw': draw,
|
||||
|
|
|
|||
|
|
@ -682,8 +682,7 @@ class UsersView(UserAppView):
|
|||
if personal_repo_group:
|
||||
raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id))
|
||||
|
||||
personal_repo_group_name = RepoGroupModel().get_personal_group_name(
|
||||
c.user)
|
||||
personal_repo_group_name = RepoGroupModel().get_personal_group_name(c.user)
|
||||
named_personal_group = RepoGroup.get_by_group_name(
|
||||
personal_repo_group_name)
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -38,19 +38,18 @@ class LocalFileStorage(object):
|
|||
"""
|
||||
Resolves a unique name and the correct path. If a filename
|
||||
for that path already exists then a numeric prefix with values > 0 will be
|
||||
added, for example test.jpg -> test-1.jpg etc. initially file would have 0 prefix.
|
||||
added, for example test.jpg -> 1-test.jpg etc. initially file would have 0 prefix.
|
||||
|
||||
:param name: base name of file
|
||||
:param directory: absolute directory path
|
||||
"""
|
||||
|
||||
basename, ext = os.path.splitext(name)
|
||||
counter = 0
|
||||
while True:
|
||||
name = '%s-%d%s' % (basename, counter, ext)
|
||||
name = '%d-%s' % (counter, name)
|
||||
|
||||
# sub_store prefix to optimize disk usage, e.g some_path/ab/final_file
|
||||
sub_store = cls._sub_store_from_filename(basename)
|
||||
sub_store = cls._sub_store_from_filename(name)
|
||||
sub_store_path = os.path.join(directory, sub_store)
|
||||
if not os.path.exists(sub_store_path):
|
||||
os.makedirs(sub_store_path)
|
||||
|
|
@ -209,3 +208,16 @@ class LocalFileStorage(object):
|
|||
filename = os.path.join(directory, filename)
|
||||
|
||||
return filename, metadata
|
||||
|
||||
def get_metadata(self, filename):
|
||||
"""
|
||||
Reads JSON stored metadata for a file
|
||||
|
||||
:param filename:
|
||||
:return:
|
||||
"""
|
||||
filename = self.store_path(filename)
|
||||
filename_meta = filename + '.meta'
|
||||
|
||||
with open(filename_meta, "rb") as source_meta:
|
||||
return json.loads(source_meta.read())
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import os
|
|||
import pytest
|
||||
|
||||
from rhodecode.lib.ext_json import json
|
||||
from rhodecode.model.db import Session, FileStore
|
||||
from rhodecode.tests import TestController
|
||||
from rhodecode.apps.file_store import utils, config_keys
|
||||
|
||||
|
|
@ -46,9 +47,12 @@ class TestFileStoreViews(TestController):
|
|||
('abcde-0.exe', "1234567", True),
|
||||
('abcde-0.jpg', "xxxxx", False),
|
||||
])
|
||||
def test_get_files_from_store(self, fid, content, exists, tmpdir):
|
||||
self.log_user()
|
||||
def test_get_files_from_store(self, fid, content, exists, tmpdir, user_util):
|
||||
user = self.log_user()
|
||||
user_id = user['user_id']
|
||||
repo_id = user_util.create_repo().repo_id
|
||||
store_path = self.app._pyramid_settings[config_keys.store_path]
|
||||
store_uid = fid
|
||||
|
||||
if exists:
|
||||
status = 200
|
||||
|
|
@ -58,17 +62,28 @@ class TestFileStoreViews(TestController):
|
|||
f.write(content)
|
||||
|
||||
with open(filesystem_file, 'rb') as f:
|
||||
fid, metadata = store.save_file(f, fid, extra_metadata={'filename': fid})
|
||||
store_uid, metadata = store.save_file(f, fid, extra_metadata={'filename': fid})
|
||||
|
||||
entry = FileStore.create(
|
||||
file_uid=store_uid, filename=metadata["filename"],
|
||||
file_hash=metadata["sha256"], file_size=metadata["size"],
|
||||
file_display_name='file_display_name',
|
||||
file_description='repo artifact `{}`'.format(metadata["filename"]),
|
||||
check_acl=True, user_id=user_id,
|
||||
scope_repo_id=repo_id
|
||||
)
|
||||
Session().add(entry)
|
||||
Session().commit()
|
||||
|
||||
else:
|
||||
status = 404
|
||||
|
||||
response = self.app.get(route_path('download_file', fid=fid), status=status)
|
||||
response = self.app.get(route_path('download_file', fid=store_uid), status=status)
|
||||
|
||||
if exists:
|
||||
assert response.text == content
|
||||
file_store_path = os.path.dirname(store.resolve_name(fid, store_path)[1])
|
||||
metadata_file = os.path.join(file_store_path, fid + '.meta')
|
||||
file_store_path = os.path.dirname(store.resolve_name(store_uid, store_path)[1])
|
||||
metadata_file = os.path.join(file_store_path, store_uid + '.meta')
|
||||
assert os.path.exists(metadata_file)
|
||||
with open(metadata_file, 'rb') as f:
|
||||
json_data = json.loads(f.read())
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@
|
|||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
|
||||
import os
|
||||
import uuid
|
||||
|
||||
import pathlib2
|
||||
|
||||
|
||||
def get_file_storage(settings):
|
||||
from rhodecode.apps.file_store.local_store import LocalFileStorage
|
||||
|
|
@ -30,6 +31,11 @@ def get_file_storage(settings):
|
|||
return LocalFileStorage(base_path=store_path)
|
||||
|
||||
|
||||
def splitext(filename):
|
||||
ext = ''.join(pathlib2.Path(filename).suffixes)
|
||||
return filename, ext
|
||||
|
||||
|
||||
def uid_filename(filename, randomized=True):
|
||||
"""
|
||||
Generates a randomized or stable (uuid) filename,
|
||||
|
|
@ -38,7 +44,8 @@ def uid_filename(filename, randomized=True):
|
|||
:param filename: the original filename
|
||||
:param randomized: define if filename should be stable (sha1 based) or randomized
|
||||
"""
|
||||
_, ext = os.path.splitext(filename)
|
||||
|
||||
_, ext = splitext(filename)
|
||||
if randomized:
|
||||
uid = uuid.uuid4()
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ from rhodecode.apps.file_store.exceptions import (
|
|||
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.lib import audit_logger
|
||||
from rhodecode.lib.auth import (CSRFRequired, NotAnonymous)
|
||||
from rhodecode.lib.auth import (CSRFRequired, NotAnonymous, HasRepoPermissionAny, HasRepoGroupPermissionAny)
|
||||
from rhodecode.model.db import Session, FileStore
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
@ -68,7 +68,7 @@ class FileStoreView(BaseAppView):
|
|||
'user_id': self._rhodecode_user.user_id,
|
||||
'ip': self._rhodecode_user.ip_addr}}
|
||||
try:
|
||||
store_fid, metadata = self.storage.save_file(
|
||||
store_uid, metadata = self.storage.save_file(
|
||||
file_obj.file, filename, extra_metadata=metadata)
|
||||
except FileNotAllowedException:
|
||||
return {'store_fid': None,
|
||||
|
|
@ -82,7 +82,7 @@ class FileStoreView(BaseAppView):
|
|||
|
||||
try:
|
||||
entry = FileStore.create(
|
||||
file_uid=store_fid, filename=metadata["filename"],
|
||||
file_uid=store_uid, filename=metadata["filename"],
|
||||
file_hash=metadata["sha256"], file_size=metadata["size"],
|
||||
file_description='upload attachment',
|
||||
check_acl=False, user_id=self._rhodecode_user.user_id
|
||||
|
|
@ -96,8 +96,8 @@ class FileStoreView(BaseAppView):
|
|||
'access_path': None,
|
||||
'error': 'File {} failed to store in DB.'.format(filename)}
|
||||
|
||||
return {'store_fid': store_fid,
|
||||
'access_path': h.route_path('download_file', fid=store_fid)}
|
||||
return {'store_fid': store_uid,
|
||||
'access_path': h.route_path('download_file', fid=store_uid)}
|
||||
|
||||
@view_config(route_name='download_file')
|
||||
def download_file(self):
|
||||
|
|
@ -109,6 +109,35 @@ class FileStoreView(BaseAppView):
|
|||
log.debug('File with FID:%s not found in the store', file_uid)
|
||||
raise HTTPNotFound()
|
||||
|
||||
db_obj = FileStore().query().filter(FileStore.file_uid == file_uid).scalar()
|
||||
if not db_obj:
|
||||
raise HTTPNotFound()
|
||||
|
||||
# private upload for user
|
||||
if db_obj.check_acl and db_obj.scope_user_id:
|
||||
user = db_obj.user
|
||||
if self._rhodecode_db_user.user_id != user.user_id:
|
||||
log.warning('Access to file store object forbidden')
|
||||
raise HTTPNotFound()
|
||||
|
||||
# scoped to repository permissions
|
||||
if db_obj.check_acl and db_obj.scope_repo_id:
|
||||
repo = db_obj.repo
|
||||
perm_set = ['repository.read', 'repository.write', 'repository.admin']
|
||||
has_perm = HasRepoPermissionAny(*perm_set)(repo.repo_name, 'FileStore check')
|
||||
if not has_perm:
|
||||
log.warning('Access to file store object forbidden')
|
||||
raise HTTPNotFound()
|
||||
|
||||
# scoped to repository group permissions
|
||||
if db_obj.check_acl and db_obj.scope_repo_group_id:
|
||||
repo_group = db_obj.repo_group
|
||||
perm_set = ['group.read', 'group.write', 'group.admin']
|
||||
has_perm = HasRepoGroupPermissionAny(*perm_set)(repo_group.group_name, 'FileStore check')
|
||||
if not has_perm:
|
||||
log.warning('Access to file store object forbidden')
|
||||
raise HTTPNotFound()
|
||||
|
||||
FileStore.bump_access_counter(file_uid)
|
||||
|
||||
file_path = self.storage.store_path(file_uid)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import formencode
|
|||
import formencode.htmlfill
|
||||
import peppercorn
|
||||
|
||||
from pyramid.httpexceptions import HTTPNotFound, HTTPFound
|
||||
from pyramid.httpexceptions import HTTPNotFound, HTTPFound, HTTPBadRequest
|
||||
from pyramid.view import view_config
|
||||
from pyramid.renderers import render
|
||||
from pyramid.response import Response
|
||||
|
|
@ -67,7 +67,6 @@ class GistView(BaseAppView):
|
|||
(Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users"))
|
||||
]
|
||||
|
||||
|
||||
return c
|
||||
|
||||
@LoginRequired()
|
||||
|
|
@ -296,6 +295,8 @@ class GistView(BaseAppView):
|
|||
response = Response(content)
|
||||
response.content_type = 'text/plain'
|
||||
return response
|
||||
elif return_format:
|
||||
raise HTTPBadRequest()
|
||||
|
||||
return self._get_template_context(c)
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ def includeme(config):
|
|||
name='markup_preview',
|
||||
pattern='/_markup_preview')
|
||||
|
||||
config.add_route(
|
||||
name='file_preview',
|
||||
pattern='/_file_preview')
|
||||
|
||||
config.add_route(
|
||||
name='store_user_session_value',
|
||||
pattern='/_store_session_attr')
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ from pyramid.view import view_config
|
|||
from rhodecode.apps._base import BaseAppView
|
||||
from rhodecode.lib import helpers as h
|
||||
from rhodecode.lib.auth import (
|
||||
LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator,
|
||||
CSRFRequired)
|
||||
LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator, CSRFRequired)
|
||||
from rhodecode.lib.codeblocks import filenode_as_lines_tokens
|
||||
from rhodecode.lib.index import searcher_from_config
|
||||
from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
|
||||
from rhodecode.lib.ext_json import json
|
||||
from rhodecode.lib.vcs.nodes import FileNode
|
||||
from rhodecode.model.db import (
|
||||
func, true, or_, in_filter_generator, Repository, RepoGroup, User, UserGroup)
|
||||
func, true, or_, case, in_filter_generator, Repository, RepoGroup, User, UserGroup)
|
||||
from rhodecode.model.repo import RepoModel
|
||||
from rhodecode.model.repo_group import RepoGroupModel
|
||||
from rhodecode.model.scm import RepoGroupList, RepoList
|
||||
|
|
@ -105,21 +106,27 @@ class HomeView(BaseAppView):
|
|||
|
||||
return {'suggestions': _user_groups}
|
||||
|
||||
def _get_repo_list(self, name_contains=None, repo_type=None, limit=20):
|
||||
def _get_repo_list(self, name_contains=None, repo_type=None, repo_group_name='', limit=20):
|
||||
org_query = name_contains
|
||||
allowed_ids = self._rhodecode_user.repo_acl_ids(
|
||||
['repository.read', 'repository.write', 'repository.admin'],
|
||||
cache=False, name_filter=name_contains) or [-1]
|
||||
|
||||
query = Repository.query()\
|
||||
.order_by(func.length(Repository.repo_name))\
|
||||
.order_by(Repository.repo_name)\
|
||||
.filter(Repository.archived.isnot(true()))\
|
||||
.filter(or_(
|
||||
# generate multiple IN to fix limitation problems
|
||||
*in_filter_generator(Repository.repo_id, allowed_ids)
|
||||
))
|
||||
|
||||
query = query.order_by(case(
|
||||
[
|
||||
(Repository.repo_name.startswith(repo_group_name), repo_group_name+'/'),
|
||||
],
|
||||
))
|
||||
query = query.order_by(func.length(Repository.repo_name))
|
||||
query = query.order_by(Repository.repo_name)
|
||||
|
||||
if repo_type:
|
||||
query = query.filter(Repository.repo_type == repo_type)
|
||||
|
||||
|
|
@ -145,20 +152,26 @@ class HomeView(BaseAppView):
|
|||
}
|
||||
for obj in acl_iter]
|
||||
|
||||
def _get_repo_group_list(self, name_contains=None, limit=20):
|
||||
def _get_repo_group_list(self, name_contains=None, repo_group_name='', limit=20):
|
||||
org_query = name_contains
|
||||
allowed_ids = self._rhodecode_user.repo_group_acl_ids(
|
||||
['group.read', 'group.write', 'group.admin'],
|
||||
cache=False, name_filter=name_contains) or [-1]
|
||||
|
||||
query = RepoGroup.query()\
|
||||
.order_by(func.length(RepoGroup.group_name))\
|
||||
.order_by(RepoGroup.group_name) \
|
||||
.filter(or_(
|
||||
# generate multiple IN to fix limitation problems
|
||||
*in_filter_generator(RepoGroup.group_id, allowed_ids)
|
||||
))
|
||||
|
||||
query = query.order_by(case(
|
||||
[
|
||||
(RepoGroup.group_name.startswith(repo_group_name), repo_group_name+'/'),
|
||||
],
|
||||
))
|
||||
query = query.order_by(func.length(RepoGroup.group_name))
|
||||
query = query.order_by(RepoGroup.group_name)
|
||||
|
||||
if name_contains:
|
||||
ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
|
||||
query = query.filter(
|
||||
|
|
@ -183,11 +196,17 @@ class HomeView(BaseAppView):
|
|||
def _get_user_list(self, name_contains=None, limit=20):
|
||||
org_query = name_contains
|
||||
if not name_contains:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
name_contains = re.compile('(?:user:)(.+)').findall(name_contains)
|
||||
# TODO(marcink): should all logged in users be allowed to search others?
|
||||
allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
|
||||
if not allowed_user_search:
|
||||
return [], False
|
||||
|
||||
name_contains = re.compile('(?:user:[ ]?)(.+)').findall(name_contains)
|
||||
if len(name_contains) != 1:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
name_contains = name_contains[0]
|
||||
|
||||
query = User.query()\
|
||||
|
|
@ -207,22 +226,28 @@ class HomeView(BaseAppView):
|
|||
{
|
||||
'id': obj.user_id,
|
||||
'value': org_query,
|
||||
'value_display': obj.username,
|
||||
'value_display': 'user: `{}`'.format(obj.username),
|
||||
'type': 'user',
|
||||
'icon_link': h.gravatar_url(obj.email, 30),
|
||||
'url': h.route_path(
|
||||
'user_profile', username=obj.username)
|
||||
}
|
||||
for obj in acl_iter]
|
||||
for obj in acl_iter], True
|
||||
|
||||
def _get_user_groups_list(self, name_contains=None, limit=20):
|
||||
org_query = name_contains
|
||||
if not name_contains:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
name_contains = re.compile('(?:user_group:)(.+)').findall(name_contains)
|
||||
# TODO(marcink): should all logged in users be allowed to search others?
|
||||
allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
|
||||
if not allowed_user_search:
|
||||
return [], False
|
||||
|
||||
name_contains = re.compile('(?:user_group:[ ]?)(.+)').findall(name_contains)
|
||||
if len(name_contains) != 1:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
name_contains = name_contains[0]
|
||||
|
||||
query = UserGroup.query()\
|
||||
|
|
@ -241,27 +266,34 @@ class HomeView(BaseAppView):
|
|||
{
|
||||
'id': obj.users_group_id,
|
||||
'value': org_query,
|
||||
'value_display': obj.users_group_name,
|
||||
'value_display': 'user_group: `{}`'.format(obj.users_group_name),
|
||||
'type': 'user_group',
|
||||
'url': h.route_path(
|
||||
'user_group_profile', user_group_name=obj.users_group_name)
|
||||
}
|
||||
for obj in acl_iter]
|
||||
for obj in acl_iter], True
|
||||
|
||||
def _get_hash_commit_list(self, auth_user, searcher, query, repo=None, repo_group=None):
|
||||
repo_name = repo_group_name = None
|
||||
if repo:
|
||||
repo_name = repo.repo_name
|
||||
if repo_group:
|
||||
repo_group_name = repo_group.group_name
|
||||
|
||||
def _get_hash_commit_list(self, auth_user, searcher, query):
|
||||
org_query = query
|
||||
if not query or len(query) < 3 or not searcher:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query)
|
||||
commit_hashes = re.compile('(?:commit:[ ]?)([0-9a-f]{2,40})').findall(query)
|
||||
|
||||
if len(commit_hashes) != 1:
|
||||
return []
|
||||
return [], False
|
||||
|
||||
commit_hash = commit_hashes[0]
|
||||
|
||||
result = searcher.search(
|
||||
'commit_id:{}*'.format(commit_hash), 'commit', auth_user,
|
||||
raise_on_exc=False)
|
||||
repo_name, repo_group_name, raise_on_exc=False)
|
||||
|
||||
commits = []
|
||||
for entry in result['results']:
|
||||
|
|
@ -286,7 +318,55 @@ class HomeView(BaseAppView):
|
|||
}
|
||||
|
||||
commits.append(commit_entry)
|
||||
return commits
|
||||
return commits, True
|
||||
|
||||
def _get_path_list(self, auth_user, searcher, query, repo=None, repo_group=None):
|
||||
repo_name = repo_group_name = None
|
||||
if repo:
|
||||
repo_name = repo.repo_name
|
||||
if repo_group:
|
||||
repo_group_name = repo_group.group_name
|
||||
|
||||
org_query = query
|
||||
if not query or len(query) < 3 or not searcher:
|
||||
return [], False
|
||||
|
||||
paths_re = re.compile('(?:file:[ ]?)(.+)').findall(query)
|
||||
if len(paths_re) != 1:
|
||||
return [], False
|
||||
|
||||
file_path = paths_re[0]
|
||||
|
||||
search_path = searcher.escape_specials(file_path)
|
||||
result = searcher.search(
|
||||
'file.raw:*{}*'.format(search_path), 'path', auth_user,
|
||||
repo_name, repo_group_name, raise_on_exc=False)
|
||||
|
||||
files = []
|
||||
for entry in result['results']:
|
||||
repo_data = {
|
||||
'repository_id': entry.get('repository_id'),
|
||||
'repository_type': entry.get('repo_type'),
|
||||
'repository_name': entry.get('repository'),
|
||||
}
|
||||
|
||||
file_entry = {
|
||||
'id': entry['commit_id'],
|
||||
'value': org_query,
|
||||
'value_display': '`{}` file: {}'.format(
|
||||
entry['repository'], entry['file']),
|
||||
'type': 'file',
|
||||
'repo': entry['repository'],
|
||||
'repo_data': repo_data,
|
||||
|
||||
'url': h.route_path(
|
||||
'repo_files',
|
||||
repo_name=entry['repository'], commit_id=entry['commit_id'],
|
||||
f_path=entry['file'])
|
||||
}
|
||||
|
||||
files.append(file_entry)
|
||||
return files, True
|
||||
|
||||
@LoginRequired()
|
||||
@view_config(
|
||||
|
|
@ -363,36 +443,42 @@ class HomeView(BaseAppView):
|
|||
def query_modifier():
|
||||
qry = query
|
||||
return {'q': qry, 'type': 'content'}
|
||||
label = u'File search for `{}` in this repository.'.format(query)
|
||||
queries.append(
|
||||
{
|
||||
'id': -10,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo',
|
||||
repo_name=repo_name,
|
||||
_query=query_modifier())
|
||||
|
||||
label = u'File search for `{}`'.format(h.escape(query))
|
||||
file_qry = {
|
||||
'id': -10,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'subtype': 'repo',
|
||||
'url': h.route_path('search_repo',
|
||||
repo_name=repo_name,
|
||||
_query=query_modifier())
|
||||
}
|
||||
)
|
||||
|
||||
# commits
|
||||
def query_modifier():
|
||||
qry = query
|
||||
return {'q': qry, 'type': 'commit'}
|
||||
|
||||
label = u'Commit search for `{}` in this repository.'.format(query)
|
||||
queries.append(
|
||||
{
|
||||
'id': -20,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo',
|
||||
repo_name=repo_name,
|
||||
_query=query_modifier())
|
||||
label = u'Commit search for `{}`'.format(h.escape(query))
|
||||
commit_qry = {
|
||||
'id': -20,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'subtype': 'repo',
|
||||
'url': h.route_path('search_repo',
|
||||
repo_name=repo_name,
|
||||
_query=query_modifier())
|
||||
}
|
||||
)
|
||||
|
||||
if repo_context in ['commit', 'commits']:
|
||||
queries.extend([commit_qry, file_qry])
|
||||
elif repo_context in ['files', 'summary']:
|
||||
queries.extend([file_qry, commit_qry])
|
||||
else:
|
||||
queries.extend([commit_qry, file_qry])
|
||||
|
||||
elif is_es_6 and repo_group_name:
|
||||
# files
|
||||
|
|
@ -400,37 +486,43 @@ class HomeView(BaseAppView):
|
|||
qry = query
|
||||
return {'q': qry, 'type': 'content'}
|
||||
|
||||
label = u'File search for `{}` in this repository group'.format(query)
|
||||
queries.append(
|
||||
{
|
||||
'id': -30,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo_group',
|
||||
repo_group_name=repo_group_name,
|
||||
_query=query_modifier())
|
||||
label = u'File search for `{}`'.format(query)
|
||||
file_qry = {
|
||||
'id': -30,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'subtype': 'repo_group',
|
||||
'url': h.route_path('search_repo_group',
|
||||
repo_group_name=repo_group_name,
|
||||
_query=query_modifier())
|
||||
}
|
||||
)
|
||||
|
||||
# commits
|
||||
def query_modifier():
|
||||
qry = query
|
||||
return {'q': qry, 'type': 'commit'}
|
||||
|
||||
label = u'Commit search for `{}` in this repository group'.format(query)
|
||||
queries.append(
|
||||
{
|
||||
'id': -40,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'url': h.route_path('search_repo_group',
|
||||
repo_group_name=repo_group_name,
|
||||
_query=query_modifier())
|
||||
label = u'Commit search for `{}`'.format(query)
|
||||
commit_qry = {
|
||||
'id': -40,
|
||||
'value': query,
|
||||
'value_display': label,
|
||||
'type': 'search',
|
||||
'subtype': 'repo_group',
|
||||
'url': h.route_path('search_repo_group',
|
||||
repo_group_name=repo_group_name,
|
||||
_query=query_modifier())
|
||||
}
|
||||
)
|
||||
|
||||
if repo_context in ['commit', 'commits']:
|
||||
queries.extend([commit_qry, file_qry])
|
||||
elif repo_context in ['files', 'summary']:
|
||||
queries.extend([file_qry, commit_qry])
|
||||
else:
|
||||
queries.extend([commit_qry, file_qry])
|
||||
|
||||
# Global, not scoped
|
||||
if not queries:
|
||||
queries.append(
|
||||
{
|
||||
|
|
@ -438,6 +530,7 @@ class HomeView(BaseAppView):
|
|||
'value': query,
|
||||
'value_display': u'File search for: `{}`'.format(query),
|
||||
'type': 'search',
|
||||
'subtype': 'global',
|
||||
'url': h.route_path('search',
|
||||
_query={'q': query, 'type': 'content'})
|
||||
})
|
||||
|
|
@ -447,6 +540,7 @@ class HomeView(BaseAppView):
|
|||
'value': query,
|
||||
'value_display': u'Commit search for: `{}`'.format(query),
|
||||
'type': 'search',
|
||||
'subtype': 'global',
|
||||
'url': h.route_path('search',
|
||||
_query={'q': query, 'type': 'commit'})
|
||||
})
|
||||
|
|
@ -469,54 +563,107 @@ class HomeView(BaseAppView):
|
|||
if not query:
|
||||
return {'suggestions': res}
|
||||
|
||||
def no_match(name):
|
||||
return {
|
||||
'id': -1,
|
||||
'value': "",
|
||||
'value_display': name,
|
||||
'type': 'text',
|
||||
'url': ""
|
||||
}
|
||||
searcher = searcher_from_config(self.request.registry.settings)
|
||||
for _q in self._get_default_search_queries(self.request.GET, searcher, query):
|
||||
res.append(_q)
|
||||
has_specialized_search = False
|
||||
|
||||
# set repo context
|
||||
repo = None
|
||||
repo_id = safe_int(self.request.GET.get('search_context[repo_id]'))
|
||||
if repo_id:
|
||||
repo = Repository.get(repo_id)
|
||||
|
||||
# set group context
|
||||
repo_group = None
|
||||
repo_group_id = safe_int(self.request.GET.get('search_context[repo_group_id]'))
|
||||
if repo_group_id:
|
||||
repo_group = RepoGroup.get(repo_group_id)
|
||||
composed_hint = '{}/{}'.format(repo_group.group_name, query)
|
||||
show_hint = not query.startswith(repo_group.group_name)
|
||||
if repo_group and show_hint:
|
||||
hint = u'Repository search inside: `{}`'.format(composed_hint)
|
||||
res.append({
|
||||
'id': -1,
|
||||
'value': composed_hint,
|
||||
'value_display': hint,
|
||||
'type': 'hint',
|
||||
'url': ""
|
||||
})
|
||||
prefix_match = False
|
||||
|
||||
repo_groups = self._get_repo_group_list(query)
|
||||
for serialized_repo_group in repo_groups:
|
||||
res.append(serialized_repo_group)
|
||||
# user: type search
|
||||
if not prefix_match:
|
||||
users, prefix_match = self._get_user_list(query)
|
||||
if users:
|
||||
has_specialized_search = True
|
||||
for serialized_user in users:
|
||||
res.append(serialized_user)
|
||||
elif prefix_match:
|
||||
has_specialized_search = True
|
||||
res.append(no_match('No matching users found'))
|
||||
|
||||
repos = self._get_repo_list(query)
|
||||
for serialized_repo in repos:
|
||||
res.append(serialized_repo)
|
||||
# user_group: type search
|
||||
if not prefix_match:
|
||||
user_groups, prefix_match = self._get_user_groups_list(query)
|
||||
if user_groups:
|
||||
has_specialized_search = True
|
||||
for serialized_user_group in user_groups:
|
||||
res.append(serialized_user_group)
|
||||
elif prefix_match:
|
||||
has_specialized_search = True
|
||||
res.append(no_match('No matching user groups found'))
|
||||
|
||||
# TODO(marcink): should all logged in users be allowed to search others?
|
||||
allowed_user_search = self._rhodecode_user.username != User.DEFAULT_USER
|
||||
if allowed_user_search:
|
||||
users = self._get_user_list(query)
|
||||
for serialized_user in users:
|
||||
res.append(serialized_user)
|
||||
|
||||
user_groups = self._get_user_groups_list(query)
|
||||
for serialized_user_group in user_groups:
|
||||
res.append(serialized_user_group)
|
||||
|
||||
commits = self._get_hash_commit_list(c.auth_user, searcher, query)
|
||||
if commits:
|
||||
unique_repos = collections.OrderedDict()
|
||||
for commit in commits:
|
||||
repo_name = commit['repo']
|
||||
unique_repos.setdefault(repo_name, []).append(commit)
|
||||
|
||||
for repo, commits in unique_repos.items():
|
||||
# FTS commit: type search
|
||||
if not prefix_match:
|
||||
commits, prefix_match = self._get_hash_commit_list(
|
||||
c.auth_user, searcher, query, repo, repo_group)
|
||||
if commits:
|
||||
has_specialized_search = True
|
||||
unique_repos = collections.OrderedDict()
|
||||
for commit in commits:
|
||||
res.append(commit)
|
||||
repo_name = commit['repo']
|
||||
unique_repos.setdefault(repo_name, []).append(commit)
|
||||
|
||||
for _repo, commits in unique_repos.items():
|
||||
for commit in commits:
|
||||
res.append(commit)
|
||||
elif prefix_match:
|
||||
has_specialized_search = True
|
||||
res.append(no_match('No matching commits found'))
|
||||
|
||||
# FTS file: type search
|
||||
if not prefix_match:
|
||||
paths, prefix_match = self._get_path_list(
|
||||
c.auth_user, searcher, query, repo, repo_group)
|
||||
if paths:
|
||||
has_specialized_search = True
|
||||
unique_repos = collections.OrderedDict()
|
||||
for path in paths:
|
||||
repo_name = path['repo']
|
||||
unique_repos.setdefault(repo_name, []).append(path)
|
||||
|
||||
for repo, paths in unique_repos.items():
|
||||
for path in paths:
|
||||
res.append(path)
|
||||
elif prefix_match:
|
||||
has_specialized_search = True
|
||||
res.append(no_match('No matching files found'))
|
||||
|
||||
# main suggestions
|
||||
if not has_specialized_search:
|
||||
repo_group_name = ''
|
||||
if repo_group:
|
||||
repo_group_name = repo_group.group_name
|
||||
|
||||
for _q in self._get_default_search_queries(self.request.GET, searcher, query):
|
||||
res.append(_q)
|
||||
|
||||
repo_groups = self._get_repo_group_list(query, repo_group_name=repo_group_name)
|
||||
for serialized_repo_group in repo_groups:
|
||||
res.append(serialized_repo_group)
|
||||
|
||||
repos = self._get_repo_list(query, repo_group_name=repo_group_name)
|
||||
for serialized_repo in repos:
|
||||
res.append(serialized_repo)
|
||||
|
||||
if not repos and not repo_groups:
|
||||
res.append(no_match('No matches found'))
|
||||
|
||||
return {'suggestions': res}
|
||||
|
||||
|
|
@ -564,8 +711,11 @@ class HomeView(BaseAppView):
|
|||
def repo_group_main_page(self):
|
||||
c = self.load_default_context()
|
||||
c.repo_group = self.request.db_repo_group
|
||||
repo_data, repo_group_data = self._get_groups_and_repos(
|
||||
c.repo_group.group_id)
|
||||
repo_data, repo_group_data = self._get_groups_and_repos(c.repo_group.group_id)
|
||||
|
||||
# update every 5 min
|
||||
if self.request.db_repo_group.last_commit_cache_update_diff > 60 * 5:
|
||||
self.request.db_repo_group.update_commit_cache()
|
||||
|
||||
# json used to render the grids
|
||||
c.repos_data = json.dumps(repo_data)
|
||||
|
|
@ -591,6 +741,34 @@ class HomeView(BaseAppView):
|
|||
return h.render(text, renderer=renderer, mentions=True)
|
||||
return ''
|
||||
|
||||
@LoginRequired()
|
||||
@CSRFRequired()
|
||||
@view_config(
|
||||
route_name='file_preview', request_method='POST',
|
||||
renderer='string', xhr=True)
|
||||
def file_preview(self):
|
||||
# Technically a CSRF token is not needed as no state changes with this
|
||||
# call. However, as this is a POST is better to have it, so automated
|
||||
# tools don't flag it as potential CSRF.
|
||||
# Post is required because the payload could be bigger than the maximum
|
||||
# allowed by GET.
|
||||
|
||||
text = self.request.POST.get('text')
|
||||
file_path = self.request.POST.get('file_path')
|
||||
|
||||
renderer = h.renderer_from_filename(file_path)
|
||||
|
||||
if renderer:
|
||||
return h.render(text, renderer=renderer, mentions=True)
|
||||
else:
|
||||
self.load_default_context()
|
||||
_render = self.request.get_partial_renderer(
|
||||
'rhodecode:templates/files/file_content.mako')
|
||||
|
||||
lines = filenode_as_lines_tokens(FileNode(file_path, text))
|
||||
|
||||
return _render('render_lines', lines)
|
||||
|
||||
@LoginRequired()
|
||||
@CSRFRequired()
|
||||
@view_config(
|
||||
|
|
@ -604,4 +782,4 @@ class HomeView(BaseAppView):
|
|||
if existing_value != val:
|
||||
self.request.session[key] = val
|
||||
|
||||
return 'stored:{}'.format(key)
|
||||
return 'stored:{}:{}'.format(key, val)
|
||||
|
|
|
|||
|
|
@ -31,12 +31,12 @@ from pyramid.renderers import render
|
|||
|
||||
from rhodecode.apps._base import BaseAppView
|
||||
from rhodecode.model.db import (
|
||||
or_, joinedload, UserLog, UserFollowing, User, UserApiKeys)
|
||||
or_, joinedload, Repository, UserLog, UserFollowing, User, UserApiKeys)
|
||||
from rhodecode.model.meta import Session
|
||||
import rhodecode.lib.helpers as h
|
||||
from rhodecode.lib.helpers import Page
|
||||
from rhodecode.lib.user_log_filter import user_log_filter
|
||||
from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
|
||||
from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired, HasRepoPermissionAny
|
||||
from rhodecode.lib.utils2 import safe_int, AttributeDict, md5_safe
|
||||
from rhodecode.model.scm import ScmModel
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ class JournalView(BaseAppView):
|
|||
desc = action_extra()
|
||||
_url = h.route_url('home')
|
||||
if entry.repository is not None:
|
||||
_url = h.route_url('repo_changelog',
|
||||
_url = h.route_url('repo_commits',
|
||||
repo_name=entry.repository.repo_name)
|
||||
|
||||
feed.add_item(
|
||||
|
|
@ -199,7 +199,7 @@ class JournalView(BaseAppView):
|
|||
desc = action_extra()
|
||||
_url = h.route_url('home')
|
||||
if entry.repository is not None:
|
||||
_url = h.route_url('repo_changelog',
|
||||
_url = h.route_url('repo_commits',
|
||||
repo_name=entry.repository.repo_name)
|
||||
|
||||
feed.add_item(
|
||||
|
|
@ -297,18 +297,19 @@ class JournalView(BaseAppView):
|
|||
user_id = self.request.POST.get('follows_user_id')
|
||||
if user_id:
|
||||
try:
|
||||
ScmModel().toggle_following_user(
|
||||
user_id, self._rhodecode_user.user_id)
|
||||
ScmModel().toggle_following_user(user_id, self._rhodecode_user.user_id)
|
||||
Session().commit()
|
||||
return 'ok'
|
||||
except Exception:
|
||||
raise HTTPBadRequest()
|
||||
|
||||
repo_id = self.request.POST.get('follows_repo_id')
|
||||
if repo_id:
|
||||
repo = Repository.get_or_404(repo_id)
|
||||
perm_set = ['repository.read', 'repository.write', 'repository.admin']
|
||||
has_perm = HasRepoPermissionAny(*perm_set)(repo.repo_name, 'RepoWatch check')
|
||||
if repo and has_perm:
|
||||
try:
|
||||
ScmModel().toggle_following_repo(
|
||||
repo_id, self._rhodecode_user.user_id)
|
||||
ScmModel().toggle_following_repo(repo_id, self._rhodecode_user.user_id)
|
||||
Session().commit()
|
||||
return 'ok'
|
||||
except Exception:
|
||||
|
|
|
|||
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