diff --git a/.bumpversion.cfg b/.bumpversion.cfg --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 4.10.6 +current_version = 4.11.0 message = release: Bump version {current_version} to {new_version} [bumpversion:file:rhodecode/VERSION] diff --git a/.coveragerc b/.coveragerc --- a/.coveragerc +++ b/.coveragerc @@ -3,15 +3,11 @@ branch = True include = - rhodecode/lib/* - rhodecode/model/* - rhodecode/controllers/* + rhodecode/* omit = - rhodecode/lib/vcs/remote/* rhodecode/lib/dbmigrate/* rhodecode/lib/paster_commands/* - rhodecode/tests/* [report] diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -21,7 +21,7 @@ syntax: regexp ^\.rhodecode$ ^rcextensions -^_dev +^.dev ^._dev ^build/ ^bower_components/ diff --git a/.release.cfg b/.release.cfg --- a/.release.cfg +++ b/.release.cfg @@ -5,25 +5,20 @@ 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 + +[task:updated_translation] [release] -state = prepared -version = 4.10.6 - -[task:updated_translation] +state = in_progress +version = 4.11.0 [task:generate_js_routes] diff --git a/configs/development.ini b/configs/development.ini --- a/configs/development.ini +++ b/configs/development.ini @@ -79,7 +79,7 @@ asyncore_use_poll = true #proc_name = rhodecode ## type of worker class, one of sync, gevent ## recommended for bigger setup is using of of other than sync one -#worker_class = sync +#worker_class = gevent ## The maximum number of simultaneous clients. Valid only for Gevent #worker_connections = 10 ## max number of requests that worker will handle before being gracefully @@ -295,29 +295,21 @@ labs_settings_active = true #################################### ### CELERY CONFIG #### #################################### -use_celery = false -broker.host = localhost -broker.vhost = rabbitmqhost -broker.port = 5672 -broker.user = rabbitmq -broker.password = qweqwe - -celery.imports = rhodecode.lib.celerylib.tasks +## run: /path/to/celery worker \ +## -E --beat --app rhodecode.lib.celerylib.loader \ +## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \ +## --loglevel DEBUG --ini /path/to/rhodecode.ini -celery.result.backend = amqp -celery.result.dburi = amqp:// -celery.result.serialier = json +use_celery = false -#celery.send.task.error.emails = true -#celery.amqp.task.result.expires = 18000 +## connection url to the message broker (default rabbitmq) +celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost -celeryd.concurrency = 2 -#celeryd.log.file = celeryd.log -celeryd.log.level = debug -celeryd.max.tasks.per.child = 1 +## maximum tasks to execute before worker restart +celery.max_tasks_per_child = 100 ## tasks will never be sent to the queue, but executed locally instead. -celery.always.eager = false +celery.task_always_eager = false #################################### ### BEAKER CACHE #### @@ -567,7 +559,7 @@ vcs.hooks.protocol = http vcs.server.log_level = debug ## Start VCSServer with this instance as a subprocess, usefull for development -vcs.start_server = true +vcs.start_server = false ## List of enabled VCS backends, available options are: ## `hg` - mercurial @@ -649,7 +641,7 @@ custom.conf = 1 ### LOGGING CONFIGURATION #### ################################ [loggers] -keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper +keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery [handlers] keys = console, console_sql @@ -688,6 +680,11 @@ handlers = qualname = ssh_wrapper propagate = 1 +[logger_celery] +level = DEBUG +handlers = +qualname = celery + ############## ## HANDLERS ## diff --git a/configs/gunicorn_config.py b/configs/gunicorn_config.py --- a/configs/gunicorn_config.py +++ b/configs/gunicorn_config.py @@ -28,9 +28,30 @@ accesslog = '-' loglevel = 'debug' # SECURITY + +# The maximum size of HTTP request line in bytes. limit_request_line = 4094 -limit_request_fields = 100 -limit_request_field_size = 8190 + +# Limit the number of HTTP headers fields in a request. +limit_request_fields = 1024 + +# Limit the allowed size of an HTTP request header field. +# Value is a positive number or 0. +# Setting it to 0 will allow unlimited header field sizes. +limit_request_field_size = 0 + + +# Timeout for graceful workers restart. +# After receiving a restart signal, workers have this much time to finish +# serving requests. Workers still alive after the timeout (starting from the +# receipt of the restart signal) are force killed. +graceful_timeout = 30 + + +# The number of seconds to wait for requests on a Keep-Alive connection. +# Generally set in the 1-5 seconds range. +keepalive = 2 + # SERVER MECHANICS # None == system temp dir @@ -57,10 +78,18 @@ def pre_exec(server): server.log.info("Forked child, re-executing.") +def on_starting(server): + server.log.info("Server is starting.") + + def when_ready(server): server.log.info("Server is ready. Spawning workers") +def on_reload(server): + pass + + def worker_int(worker): worker.log.info("[<%-10s>] worker received INT or QUIT signal", worker.pid) @@ -81,6 +110,14 @@ def worker_abort(worker): worker.log.info("[<%-10s>] worker received SIGABRT signal", worker.pid) +def worker_exit(server, worker): + worker.log.info("[<%-10s>] worker exit", worker.pid) + + +def child_exit(server, worker): + worker.log.info("[<%-10s>] worker child exit", worker.pid) + + def pre_request(worker, req): return worker.log.debug("[<%-10s>] PRE WORKER: %s %s", @@ -93,6 +130,7 @@ def post_request(worker, req, environ, r req.method, req.path, resp.status_code) + class RhodeCodeLogger(Logger): """ Custom Logger that allows some customization that gunicorn doesn't allow diff --git a/configs/production.ini b/configs/production.ini --- a/configs/production.ini +++ b/configs/production.ini @@ -79,7 +79,7 @@ workers = 2 proc_name = rhodecode ## type of worker class, one of sync, gevent ## recommended for bigger setup is using of of other than sync one -worker_class = sync +worker_class = gevent ## The maximum number of simultaneous clients. Valid only for Gevent #worker_connections = 10 ## max number of requests that worker will handle before being gracefully @@ -270,29 +270,21 @@ labs_settings_active = true #################################### ### CELERY CONFIG #### #################################### -use_celery = false -broker.host = localhost -broker.vhost = rabbitmqhost -broker.port = 5672 -broker.user = rabbitmq -broker.password = qweqwe - -celery.imports = rhodecode.lib.celerylib.tasks +## run: /path/to/celery worker \ +## -E --beat --app rhodecode.lib.celerylib.loader \ +## --scheduler rhodecode.lib.celerylib.scheduler.RcScheduler \ +## --loglevel DEBUG --ini /path/to/rhodecode.ini -celery.result.backend = amqp -celery.result.dburi = amqp:// -celery.result.serialier = json +use_celery = false -#celery.send.task.error.emails = true -#celery.amqp.task.result.expires = 18000 +## connection url to the message broker (default rabbitmq) +celery.broker_url = amqp://rabbitmq:qweqwe@localhost:5672/rabbitmqhost -celeryd.concurrency = 2 -#celeryd.log.file = celeryd.log -celeryd.log.level = debug -celeryd.max.tasks.per.child = 1 +## maximum tasks to execute before worker restart +celery.max_tasks_per_child = 100 ## tasks will never be sent to the queue, but executed locally instead. -celery.always.eager = false +celery.task_always_eager = false #################################### ### BEAKER CACHE #### @@ -619,7 +611,7 @@ custom.conf = 1 ### LOGGING CONFIGURATION #### ################################ [loggers] -keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper +keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper, celery [handlers] keys = console, console_sql @@ -658,6 +650,11 @@ handlers = qualname = ssh_wrapper propagate = 1 +[logger_celery] +level = DEBUG +handlers = +qualname = celery + ############## ## HANDLERS ## diff --git a/default.nix b/default.nix --- a/default.nix +++ b/default.nix @@ -185,6 +185,7 @@ let ln -s ${self.supervisor}/bin/supervisor* $out/bin/ ln -s ${self.PasteScript}/bin/paster $out/bin/ ln -s ${self.channelstream}/bin/channelstream $out/bin/ + ln -s ${self.celery}/bin/celery $out/bin/ # rhodecode-tools ln -s ${self.rhodecode-tools}/bin/rhodecode-* $out/bin/ diff --git a/docs/admin/backup-restore.rst b/docs/admin/backup-restore.rst --- a/docs/admin/backup-restore.rst +++ b/docs/admin/backup-restore.rst @@ -70,7 +70,7 @@ backup location: $ mysql -u -p rhodecode_db_name < mysql-db-backup # For PostgreSQL DBs - $ PGPASSWORD= pg_dump rhodecode_db_name > postgresql-db-backup + $ PGPASSWORD= pg_dump --inserts -U -h localhost rhodecode_db_name > postgresql-db-backup # PosgreSQL restore $ PGPASSWORD= psql -U -h localhost -d rhodecode_db_name -1 -f postgresql-db-backup diff --git a/docs/admin/enable-debug.rst b/docs/admin/enable-debug.rst --- a/docs/admin/enable-debug.rst +++ b/docs/admin/enable-debug.rst @@ -47,7 +47,7 @@ the ``debug`` level. ### LOGGING CONFIGURATION #### ################################ [loggers] - keys = root, routes, rhodecode, sqlalchemy, beaker, templates + keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper [handlers] keys = console, console_sql, file, file_rotating @@ -75,12 +75,6 @@ the ``debug`` level. qualname = beaker.container propagate = 1 - [logger_templates] - level = INFO - handlers = - qualname = pylons.templating - propagate = 1 - [logger_rhodecode] level = DEBUG handlers = diff --git a/docs/admin/nginx-tuning.rst b/docs/admin/nginx-tuning.rst --- a/docs/admin/nginx-tuning.rst +++ b/docs/admin/nginx-tuning.rst @@ -9,7 +9,7 @@ timeout during large pushes. .. code-block:: nginx proxy_redirect off; - proxy_set_header Host $host; + proxy_set_header Host $http_host; ## needed for container auth # proxy_set_header REMOTE_USER $remote_user; diff --git a/docs/admin/sec-sophos-umc.rst b/docs/admin/sec-sophos-umc.rst new file mode 100644 --- /dev/null +++ b/docs/admin/sec-sophos-umc.rst @@ -0,0 +1,101 @@ +.. _sec-your-server: + +Securing Your Server via Sophos UTM 9 +------------------------------------- + + + +Below is an example configuration for Sophos UTM 9 Webserver Protection:: + + Sophos UTM 9 Webserver Protection + Web Application Firewall based on apache2 modesecurity2 + -------------------------------------------------- + 1. Firewall Profiles -> Firewall Profile + -------------------------------------------------- + Name: RhodeCode (can be anything) + Mode: Reject + Hardening & Signing: + [ ] Static URL hardeninig + [ ] Form hardening + [x] Cookie Signing + Filtering: + [x] Block clients with bad reputation + [x] Common Threats Filter + [ ] Rigid Filtering + Skip Filter Rules: + 960015 + 950120 + 981173 + 970901 + 960010 + 960032 + 960035 + 958291 + 970903 + 970003 + Common Threat Filter Categories: + [x] Protocol violations + [x] Protocol anomalies + [x] Request limit + [x] HTTP policy + [x] Bad robots + [x] Generic attacks + [x] SQL injection attacks + [x] XSS attacks + [x] Tight security + [x] Trojans + [x] Outbound + Scanning: + [ ] Enable antivirus scanning + [ ] Block uploads by MIME type + -------------------------------------------------- + 2. Web Application Firewall -> Real Webservers + -------------------------------------------------- + Name: RhodeCode (can be anything) + Host: Your RhodeCode-Server (UTM object) + Type: Encrypted (HTTPS) + Port: 443 + -------------------------------------------------- + 3. Web Application Firewall -> Virual Webservers + -------------------------------------------------- + Name: RhodeCode (can be anything) + Interface: WAN (your WAN interface) + Type: Encrypted (HTTPS) & redirect + Certificate: Wildcard or matching domain certificate + Domains (in case of Wildcard certificate): + rhodecode.yourcompany.com (match your DNS configuration) + gist.yourcompany.com (match your DNS & RhodeCode configuration) + Real Webservers for path '/': + [x] RhodeCode (created in step 2) + Firewall: RhodeCode (created in step 1) + -------------------------------------------------- + 4. Firewall Profiles -> Exceptions + -------------------------------------------------- + Name: RhodeCode exceptions (can be anything) + Skip these checks: + [ ] Cookie signing + [ ] Static URL Hardening + [ ] Form hardening + [x] Antivirus scanning + [x] True file type control + [ ] Block clients with bad reputation + Skip these categories: + [ ] Protocol violations + [x] Protocol anomalies + [x] Request limits + [ ] HTTP policy + [ ] Bad robots + [ ] Generic attacks + [ ] SQL injection attacks + [ ] XSS attacks + [ ] Tight security + [ ] Trojans + [x] Outbound + Virtual Webservers: + [x] RhodeCode (created in step 3) + For All Requests: + Web requests matching this pattern: + /_channelstream/ws + /Repository1/* + /Repository2/* + /Repository3/* \ No newline at end of file diff --git a/docs/admin/security-tips.rst b/docs/admin/security-tips.rst --- a/docs/admin/security-tips.rst +++ b/docs/admin/security-tips.rst @@ -13,3 +13,4 @@ instances are configured in as secure a sec-x-frame sec-instance-basics sec-ip-white + sec-sophos-umc diff --git a/docs/api/methods/deprecated-methods.rst b/docs/api/methods/deprecated-methods.rst --- a/docs/api/methods/deprecated-methods.rst +++ b/docs/api/methods/deprecated-methods.rst @@ -38,13 +38,13 @@ changeset_comment Example error output: - .. code-block:: javascript + .. code-block:: json { - "id" : "", + "id" : , "result" : { "msg": "Commented on commit `` for repository ``", - "status_change": null or "", + "status_change": null or , "success": true }, "error" : null diff --git a/docs/api/methods/pull-request-methods.rst b/docs/api/methods/pull-request-methods.rst --- a/docs/api/methods/pull-request-methods.rst +++ b/docs/api/methods/pull-request-methods.rst @@ -6,7 +6,7 @@ pull_request methods close_pull_request ------------------ -.. py:function:: close_pull_request(apiuser, repoid, pullrequestid, userid=>, message=) +.. py:function:: close_pull_request(apiuser, pullrequestid, repoid=, userid=>, message=) Close the pull request specified by `pullrequestid`. @@ -39,7 +39,7 @@ close_pull_request comment_pull_request -------------------- -.. py:function:: comment_pull_request(apiuser, repoid, pullrequestid, message=, commit_id=, status=, comment_type=, resolves_comment_id=, userid=>) +.. py:function:: comment_pull_request(apiuser, pullrequestid, repoid=, message=, commit_id=, status=, comment_type=, resolves_comment_id=, userid=>) Comment on the pull request specified with the `pullrequestid`, in the |repo| specified by the `repoid`, and optionally change the @@ -47,7 +47,7 @@ comment_pull_request :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: The repository name or repository ID. + :param repoid: Optional repository name or repository ID. :type repoid: str or int :param pullrequestid: The pull request ID. :type pullrequestid: int @@ -120,14 +120,14 @@ create_pull_request get_pull_request ---------------- -.. py:function:: get_pull_request(apiuser, repoid, pullrequestid) +.. py:function:: get_pull_request(apiuser, pullrequestid, repoid=) Get a pull request based on the given ID. :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: Repository name or repository ID from where the pull - request was opened. + :param repoid: Optional, repository name or repository ID from where + the pull request was opened. :type repoid: str or int :param pullrequestid: ID of the requested pull request. :type pullrequestid: int @@ -199,6 +199,48 @@ get_pull_request "error": null +get_pull_request_comments +------------------------- + +.. py:function:: get_pull_request_comments(apiuser, pullrequestid, repoid=) + + Get all comments of pull request specified with the `pullrequestid` + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Optional repository name or repository ID. + :type repoid: str or int + :param pullrequestid: The pull request ID. + :type pullrequestid: int + + Example output: + + .. code-block:: bash + + id : + result : [ + { + "comment_author": { + "active": true, + "full_name_or_username": "Tom Gore", + "username": "admin" + }, + "comment_created_on": "2017-01-02T18:43:45.533", + "comment_f_path": null, + "comment_id": 25, + "comment_lineno": null, + "comment_status": { + "status": "under_review", + "status_lbl": "Under Review" + }, + "comment_text": "Example text", + "comment_type": null, + "pull_request_version": null + } + ], + error : null + + get_pull_requests ----------------- @@ -208,7 +250,7 @@ get_pull_requests :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: Repository name or repository ID. + :param repoid: Optional repository name or repository ID. :type repoid: str or int :param status: Only return pull requests with the specified status. Valid options are. @@ -289,14 +331,14 @@ get_pull_requests merge_pull_request ------------------ -.. py:function:: merge_pull_request(apiuser, repoid, pullrequestid, userid=>) +.. py:function:: merge_pull_request(apiuser, pullrequestid, repoid=, userid=>) Merge the pull request specified by `pullrequestid` into its target repository. :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: The Repository name or repository ID of the + :param repoid: Optional, repository name or repository ID of the target repository to which the |pr| is to be merged. :type repoid: str or int :param pullrequestid: ID of the pull request which shall be merged. @@ -326,13 +368,13 @@ merge_pull_request update_pull_request ------------------- -.. py:function:: update_pull_request(apiuser, repoid, pullrequestid, title=, description=, reviewers=, update_commits=) +.. py:function:: update_pull_request(apiuser, pullrequestid, repoid=, title=, description=, reviewers=, update_commits=) Updates a pull request. :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: The repository name or repository ID. + :param repoid: Optional repository name or repository ID. :type repoid: str or int :param pullrequestid: The pull request ID. :type pullrequestid: int diff --git a/docs/api/methods/repo-group-methods.rst b/docs/api/methods/repo-group-methods.rst --- a/docs/api/methods/repo-group-methods.rst +++ b/docs/api/methods/repo-group-methods.rst @@ -115,7 +115,7 @@ get_repo_group "group_description": "repo group description", "group_id": 14, "group_name": "group name", - "members": [ + "permissions": [ { "name": "super-admin-username", "origin": "super-admin", diff --git a/docs/api/methods/repo-methods.rst b/docs/api/methods/repo-methods.rst --- a/docs/api/methods/repo-methods.rst +++ b/docs/api/methods/repo-methods.rst @@ -306,26 +306,6 @@ get_repo "lock_reason": null, "locked_by": null, "locked_date": null, - "members": [ - { - "name": "super-admin-name", - "origin": "super-admin", - "permission": "repository.admin", - "type": "user" - }, - { - "name": "owner-name", - "origin": "owner", - "permission": "repository.admin", - "type": "user" - }, - { - "name": "user-group-name", - "origin": "permission", - "permission": "repository.write", - "type": "user_group" - } - ], "owner": "owner-name", "permissions": [ { @@ -533,9 +513,6 @@ get_repo_settings "hooks_outgoing_pull_logger": true, "phases_publish": "True", "rhodecode_hg_use_rebase_for_merging": true, - "rhodecode_hg_close_branch_before_merging": false, - "rhodecode_git_use_rebase_for_merging": true, - "rhodecode_git_close_branch_before_merging": false, "rhodecode_pr_merge_enabled": true, "rhodecode_use_outdated_comments": true } diff --git a/docs/api/methods/user-group-methods.rst b/docs/api/methods/user-group-methods.rst --- a/docs/api/methods/user-group-methods.rst +++ b/docs/api/methods/user-group-methods.rst @@ -162,7 +162,7 @@ get_user_group "active": true, "group_description": "group description", "group_name": "group name", - "members": [ + "permissions": [ { "name": "owner-name", "origin": "owner", @@ -183,6 +183,12 @@ get_user_group "type": "user_group" } ], + "permissions_summary": { + "repositories": { + "aa-root-level-repo-1": "repository.admin" + }, + "repositories_groups": {} + }, "owner": "owner name", "users": [], "users_group_id": 2 diff --git a/docs/api/methods/user-methods.rst b/docs/api/methods/user-methods.rst --- a/docs/api/methods/user-methods.rst +++ b/docs/api/methods/user-methods.rst @@ -160,7 +160,8 @@ get_user "last_login": "Timestamp", "last_activity": "Timestamp", "lastname": "surnae", - "permissions": { + "permissions": , + "permissions_summary": { "global": [ "hg.inherit_default_perms.true", "usergroup.read", @@ -178,7 +179,7 @@ get_user "repositories": { "username/example": "repository.write"}, "repositories_groups": { "user-group/repo": "group.none" }, "user_groups": { "user_group_name": "usergroup.read" } - }, + } "user_id": 32, "username": "username" } diff --git a/docs/auth/ssh-connection.rst b/docs/auth/ssh-connection.rst --- a/docs/auth/ssh-connection.rst +++ b/docs/auth/ssh-connection.rst @@ -64,7 +64,7 @@ 2. Enable the SSH module on instance. ssh.wrapper_cmd_allow_shell = false ## Enables logging, and detailed output send back to the client during SSH - ## operations. Usefull for debugging, shouldn't be used in production. + ## operations. Useful for debugging, shouldn't be used in production. ssh.enable_debug_logging = false ## Paths to binary executable, by default they are the names, but we can @@ -111,20 +111,22 @@ 4. Add the public key to your user accou Then add, remove your SSH key and try connecting again. Debug logging will be printed to help find the problems on the server side. - Test connection using the ssh command from the local machine + Test connection using the ssh command from the local machine. Make sure + to use the use who is running the |RCE| server, and not your username from + the web interface. For SVN: .. code-block:: bash - SVN_SSH="ssh -i ~/.ssh/id_rsa_test_ssh" svn checkout svn+ssh://rhodecode@rc-server/repo_name + SVN_SSH="ssh -i ~/.ssh/id_rsa_test_ssh_private.key" svn checkout svn+ssh://rhodecode@rc-server/repo_name For GIT: .. code-block:: bash - GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa_test_ssh' git clone ssh://rhodecode@rc-server/repo_name + GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa_test_ssh_private.key' git clone ssh://rhodecode@rc-server/repo_name For Mercurial: @@ -133,6 +135,6 @@ 4. Add the public key to your user accou Add to hgrc: [ui] - ssh = ssh -C -i ~/.ssh/id_rsa_test_ssh + ssh = ssh -C -i ~/.ssh/id_rsa_test_ssh_private.key hg clone ssh://rhodecode@rc-server/repo_name diff --git a/docs/default.nix b/docs/default.nix --- a/docs/default.nix +++ b/docs/default.nix @@ -11,128 +11,253 @@ let python = pkgs.python27Packages.python; Jinja2 = buildPythonPackage rec { - name = "Jinja2-2.7.3"; + name = "Jinja2-2.9.6"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = [MarkupSafe]; src = fetchurl { - url = "http://pypi.python.org/packages/source/J/Jinja2/${name}.tar.gz"; - md5 = "b9dffd2f3b43d673802fe857c8445b1a"; + url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz"; + md5 = "6411537324b4dba0956aaa8109f3c77b"; }; - propagatedBuildInputs = [ MarkupSafe ]; }; MarkupSafe = buildPythonPackage rec { - name = "MarkupSafe-0.23"; + name = "MarkupSafe-1.0"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; src = fetchurl { - url = "https://pypi.python.org/packages/source/M/MarkupSafe/${name}.tar.gz"; - md5 = "f5ab3deee4c37cd6a922fb81e730da6e"; + url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz"; + md5 = "2fcedc9284d50e577b5192e8e3578355"; }; }; - Pygments = buildPythonPackage rec { - name = "Pygments-2.1.3"; + Pygments = buildPythonPackage { + name = "Pygments-2.2.0"; + buildInputs = []; doCheck = false; + propagatedBuildInputs = []; src = fetchurl { - url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz"; - md5 = "ed3fba2467c8afcda4d317e4ef2c6150"; - }; - }; - - alabaster = buildPythonPackage rec { - name = "alabaster-0.7.3"; - src = fetchurl { - url = "https://pypi.python.org/packages/source/a/alabaster/${name}.tar.gz"; - md5 = "67428d1383fd833f1282fed5deba0898"; + url = "https://pypi.python.org/packages/71/2a/2e4e77803a8bd6408a2903340ac498cb0a2181811af7c9ec92cb70b0308a/Pygments-2.2.0.tar.gz"; + md5 = "13037baca42f16917cbd5ad2fab50844"; }; }; - six = buildPythonPackage rec { - name = "six-1.9.0"; + Sphinx = buildPythonPackage (rec { + name = "Sphinx-1.6.5"; src = fetchurl { - url = "https://pypi.python.org/packages/source/s/six/${name}.tar.gz"; - md5 = "476881ef4012262dfc8adc645ee786c4"; + url = "https://pypi.python.org/packages/8b/7e/b188d9a3b9c938e736e02a74c1363c2888e095d770df2c72b4c312f9fdcb/Sphinx-1.6.5.tar.gz"; + md5 = "cd73118c21ec610432e63e6421ec54f1"; + }; + propagatedBuildInputs = [ + six + Jinja2 + Pygments + docutils + snowballstemmer + babel + alabaster + imagesize + requests + setuptools + sphinxcontrib-websupport + typing + + # special cases + pytz + sphinx_rtd_theme + + ]; + }); + + alabaster = buildPythonPackage rec { + name = "alabaster-0.7.10"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; + src = fetchurl { + url = "https://pypi.python.org/packages/d0/a5/e3a9ad3ee86aceeff71908ae562580643b955ea1b1d4f08ed6f7e8396bd7/alabaster-0.7.10.tar.gz"; + md5 = "7934dccf38801faa105f6e7b4784f493"; }; }; - snowballstemmer = buildPythonPackage rec { - name = "snowballstemmer-1.2.0"; + babel = buildPythonPackage { + name = "babel-2.5.1"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = [pytz]; src = fetchurl { - url = "https://pypi.python.org/packages/source/s/snowballstemmer/${name}.tar.gz"; - md5 = "51f2ef829db8129dd0f2354f0b209970"; + url = "https://pypi.python.org/packages/5a/22/63f1dbb8514bb7e0d0c8a85cc9b14506599a075e231985f98afd70430e1f/Babel-2.5.1.tar.gz"; + md5 = "60228b3ce93a203357158b909afe8ae1"; }; }; - pytz = buildPythonPackage rec { - name = "pytz-2015.2"; + certifi = buildPythonPackage { + name = "certifi-2017.11.5"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; src = fetchurl { - url = "https://pypi.python.org/packages/source/p/pytz/${name}.tar.gz"; - md5 = "08440d994cfbbf13d3343362cc3173f7"; + url = "https://pypi.python.org/packages/23/3f/8be01c50ed24a4bd6b8da799839066ce0288f66f5e11f0367323467f0cbc/certifi-2017.11.5.tar.gz"; + md5 = "c15ac46ed1fe4b607ff3405928f9a992"; + }; + }; + + chardet = buildPythonPackage { + name = "chardet-3.0.4"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; + src = fetchurl { + url = "https://pypi.python.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz"; + md5 = "7dd1ba7f9c77e32351b0a0cfacf4055c"; }; }; - babel = buildPythonPackage rec { - name = "Babel-1.3"; + docutils = buildPythonPackage { + name = "docutils-0.14"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; src = fetchurl { - url = "https://pypi.python.org/packages/source/B/Babel/${name}.tar.gz"; - md5 = "5264ceb02717843cbc9ffce8e6e06bdb"; + url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz"; + md5 = "c53768d63db3873b7d452833553469de"; }; - propagatedBuildInputs = [ - pytz - ]; }; - imagesize = buildPythonPackage rec { + idna = buildPythonPackage { + name = "idna-2.6"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; + src = fetchurl { + url = "https://pypi.python.org/packages/f4/bd/0467d62790828c23c47fc1dfa1b1f052b24efdf5290f071c7a91d0d82fd3/idna-2.6.tar.gz"; + md5 = "c706e2790b016bd0ed4edd2d4ba4d147"; + }; + }; + + imagesize = buildPythonPackage { name = "imagesize-0.7.1"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; src = fetchurl { - url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/${name}.tar.gz"; + url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/imagesize-0.7.1.tar.gz"; md5 = "976148283286a6ba5f69b0f81aef8052"; }; }; - Sphinx = buildPythonPackage (rec { - name = "Sphinx-1.4.8"; + pytz = buildPythonPackage { + name = "pytz-2017.3"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; src = fetchurl { - url = "https://pypi.python.org/packages/1f/f6/e54a7aad73e35232356103771ae76306dadd8546b024c646fbe75135571c/${name}.tar.gz"; - md5 = "5ec718a4855917e149498bba91b74e67"; + url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip"; + md5 = "7006b56c0d68a162d9fe57d4249c3171"; + }; + }; + + requests = buildPythonPackage { + name = "requests-2.18.4"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = [chardet idna urllib3 certifi]; + src = fetchurl { + url = "https://pypi.python.org/packages/b0/e1/eab4fc3752e3d240468a8c0b284607899d2fbfb236a56b7377a329aa8d09/requests-2.18.4.tar.gz"; + md5 = "081412b2ef79bdc48229891af13f4d82"; }; - propagatedBuildInputs = [ - docutils - Jinja2 - Pygments - alabaster - six - snowballstemmer - pytz - babel - imagesize + }; + + setuptools = buildPythonPackage { + name = "setuptools-36.6.0"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; + src = fetchurl { + url = "https://pypi.python.org/packages/45/29/8814bf414e7cd1031e1a3c8a4169218376e284ea2553cc0822a6ea1c2d78/setuptools-36.6.0.zip"; + md5 = "74663b15117d9a2cc5295d76011e6fd1"; + }; + }; - # TODO: johbo: Had to include it here so that can be imported - sphinx_rtd_theme - ]; - }); + six = buildPythonPackage { + name = "six-1.11.0"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; + src = fetchurl { + url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz"; + md5 = "d12789f9baf7e9fb2524c0c64f1773f8"; + }; + }; - docutils = buildPythonPackage rec { - name = "docutils-0.12"; + snowballstemmer = buildPythonPackage { + name = "snowballstemmer-1.2.1"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; src = fetchurl { - url = "https://pypi.python.org/packages/source/d/docutils/${name}.tar.gz"; - md5 = "4622263b62c5c771c03502afa3157768"; + url = "https://pypi.python.org/packages/20/6b/d2a7cb176d4d664d94a6debf52cd8dbae1f7203c8e42426daa077051d59c/snowballstemmer-1.2.1.tar.gz"; + md5 = "643b019667a708a922172e33a99bf2fa"; }; }; - sphinx_rtd_theme = buildPythonPackage rec { - name = "sphinx_rtd_theme-0.1.9"; + sphinx-rtd-theme = buildPythonPackage { + name = "sphinx-rtd-theme-0.2.5b1"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; + src = fetchurl { + url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz"; + md5 = "0923473a43bd2527f32151f195f2a521"; + }; + }; + + sphinxcontrib-websupport = buildPythonPackage { + name = "sphinxcontrib-websupport-1.0.1"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; src = fetchurl { - url = "https://pypi.python.org/packages/source/s/sphinx_rtd_theme/${name}.tar.gz"; - md5 = "86a25c8d47147c872e42dc84cc66f97b"; + url = "https://pypi.python.org/packages/c5/6b/f0630436b931ad4f8331a9399ca18a7d447f0fcc0c7178fb56b1aee68d01/sphinxcontrib-websupport-1.0.1.tar.gz"; + md5 = "84df26463b1ba65b07f926dbe2055665"; + }; + }; + + typing = buildPythonPackage { + name = "typing-3.6.2"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; + src = fetchurl { + url = "https://pypi.python.org/packages/ca/38/16ba8d542e609997fdcd0214628421c971f8c395084085354b11ff4ac9c3/typing-3.6.2.tar.gz"; + md5 = "143af0bf3afd1887622771f2f1ffe8e1"; + }; + }; + + urllib3 = buildPythonPackage { + name = "urllib3-1.22"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; + src = fetchurl { + url = "https://pypi.python.org/packages/ee/11/7c59620aceedcc1ef65e156cc5ce5a24ef87be4107c2b74458464e437a5d/urllib3-1.22.tar.gz"; + md5 = "0da7bed3fe94bf7dc59ae37885cc72f7"; + }; + }; + + + sphinx_rtd_theme = buildPythonPackage rec { + name = "sphinx-rtd-theme-0.2.5b1"; + buildInputs = []; + doCheck = false; + propagatedBuildInputs = []; + src = fetchurl { + url = "https://pypi.python.org/packages/59/e4/9e3a74a3271e6734911d3f549e8439db53b8ac29adf10c8f698e6c86246b/sphinx_rtd_theme-0.2.5b1.tar.gz"; + md5 = "0923473a43bd2527f32151f195f2a521"; }; - # Note: johbo: Sphinx needs this package and this package needs sphinx, - # ignore the requirements file to solve this cycle. - postPatch = '' - rm requirements.txt - touch requirements.txt - ''; - # TODO: johbo: Tests would require sphinx and this creates recursion issues - doCheck = false; }; in python.buildEnv.override { diff --git a/docs/release-notes/release-notes-4.11.0.rst b/docs/release-notes/release-notes-4.11.0.rst new file mode 100644 --- /dev/null +++ b/docs/release-notes/release-notes-4.11.0.rst @@ -0,0 +1,152 @@ +|RCE| 4.11.0 |RNS| +------------------ + +Release Date +^^^^^^^^^^^^ + +- 2018-02-01 + + +New Features +^^^^^^^^^^^^ + +- Default reviewers(EE only): introduced new voting rule logic that allows + defining how many members of user group need to vote for approvals. E.g + adding 4 people group with security people, it can be specified that at least + 1 (or all) need to vote for approval from that group. +- Default reviewers(EE only): added source/target branch flow distinction and + option to add names to rules. +- RhodeCode-Scheduler (Beta, EE only): after celery 4.X upgrade we introduced a + new scheduler option. RhodeCode scheduler now allows specifying via super-admin + interface periodic tasks that should be run crontab style. + Currently available tasks are: + - repo maintenance: (repo quality/git gc) + - repo remote code pull: pull changed on periodic bases from given url + - repo remote code push: push all changes on periodic bases to given url + - check for updates +- Ui: a ssh clone uri was added to summary view for clone. This allows to + customize how the ssh clone url would look like, and also exposes SSH clone + url to summary page. +- Integrations: parse pushed tags, and lightweight tags for git. + - now aggregated as 'tags' key + - handles the case for email/webhook integrations +- Files browser: allow making a range selection of code lines with + shift-click from line numbers. +- Pull requests: allow opening PR from changelog based on selected refs for + git as well as hg. +- Process management: auto refresh option was added to the processes + page to live track usage. +- Api: pull-requests added option to fetch comments from a pull requests. +- Api: added new data called `permissions_summary` for user and + user_groups that expose the summary of permissions for each of those. + + +General +^^^^^^^ + +- Core: removed all pylons dependencies and backward compatibility code. + RhodeCode is now 100% pyramid app. +- Audit logs: added user.register audit log entry. +- Celery: update celery support 4.X series. +- Logging: log traceback for errors that are known to help debugging. +- Pull requests: don't select first commit in case we don't have a default + branch for repository. Loading compare from commit 0 to something selected + is very heavy to compute. Now it's left to users to decide what + compare base to pick. +- Dependencies: bumped Mercurial version to 4.4.2 +- Dependencies: bumped hgevolve to 7.0.1 +- Dependencies: bumped libs not explicitly set by requirements + - ws4py to 0.4.2 + - scandir to 1.6 + - plaster to 1.0 + - mistune to 0.8 + - jupyter-core to 4.4.0 +- Dependencies: pin to rhodecode-tools 0.14.0 +- Dependencies: bumped click to 6.6.0 +- Dependencies: bumped transifex-clients to 0.12.5 +- Dependencies: bumped six to 1.11.0 +- Dependencies: bumped waitress to 1.1.0 +- Dependencies: bumped setproctitle 1.1.10 +- Dependencies: bumped iso8601 to 0.1.12 +- Dependencies: bumped repoze.lru to 0.7.0 +- Dependencies: bumped python-ldap to 2.4.45 +- Dependencies: bumped gnureadline 6.3.8 +- Dependencies: bumped bottle to 0.12.13 +- Dependencies: bumped psycopg2 2.7.3.2 +- Dependencies: bumped alembic to 0.9.6 +- Dependencies: bumped sqlalchemy to 1.1.15 +- Dependencies: bumped markupsafe to 1.0.0 +- Dependencies: bumped markdown to 2.6.9 +- Dependencies: bumped objgraph to 3.1.1 +- Dependencies: bumped psutil to 5.4.0 +- Dependencies: bumped docutils to 0.14.0 +- Dependencies: bumped decorator to 4.1.2 +- Dependencies: bumped pyramid-jinja to 2.7.0 +- Dependencies: bumped jinja to 2.9.6 +- Dependencies: bumped colander to 1.4.0 +- Dependencies: bumped mistune to 0.8.1 +- Dependencies: bumped webob to 1.7.4 +- Dependencies: dropped nose dependency. + + +Security +^^^^^^^^ + +- Security(low): fix self xss on repo downloads picker for svn case. + + +Performance +^^^^^^^^^^^ + +- Pyramid: removed pylons layer, this should result in general speed + improvement over previous version. +- Authentication: use cache_ttl for anonymous access taken from the + rhodecode main auth plugin. For operations like svn this boosts performance + significantly with anonymous access enabled. +- Issue trackers: cache the fetched issue tracker patterns in changelog + page before loop iteration to speed up fetching and parsing the tracker + patterns. + + +Fixes +^^^^^ + +- Slack: expose the FULL message instead of title. + Slack uses it's own trim, we should avoid sending trimmed data and + let users via Slack trim logic control the data. +- Comments: place the left over comments (outdated/misplaced) to the left or + right side-by-side pane. This way the original context where they were + placed is kept. +- Comments: allow to properly initialize outdated comments that are attached + to the end of diffs. This allows resolving TODOs that are outdated. +- Git: handle cases of git push without branch specified in the eventing system. +- Git: merge simulation fixes. Fetch other branch data if it's different + from target. This prevents potentially missing commits error when doing a test merge. + Also fix edge cases using .gitattributes file modification that could + lead to the same problem. +- Age component: use local flag to fix the problem of wrongly reported last + update times on repository groups. + + +Upgrade notes +^^^^^^^^^^^^^ + +Please note that this release is first in series that drops completely pylons +dependency. This means that certain `paster` commands are no longer available. + +Commands changed after dropping pylons compatibility layer: + - paster upgrade-db /path/ini_file => rc-upgrade-db /path/ini_file + - paster setup-app /path/ini_file => rc-setup-app /path/ini_file + - paster ishell /path/ini_file => rc-ishell /path/ini_file + - paster celeryd /path/ini_file => celery worker --app rhodecode.lib.celerylib.loader /path/ini_file + +Commands no longer available: + - paster make-config (replaced by rhodecode-config from rhodecode-tools package) + - paster update-repoinfo (replaced by API calls) + - paster cache-keys, no equivalent available, this command was removed. + + +RhodeCode 4.11 uses latest Celery 4.X series. This means that there's a new way to +run the celery workers. To upgrade to latest simply run +`rccontrol enable-module celery` to convert the currently running celery setup +into a new version that also powers the RhodeCode scheduler. diff --git a/docs/release-notes/release-notes.rst b/docs/release-notes/release-notes.rst --- a/docs/release-notes/release-notes.rst +++ b/docs/release-notes/release-notes.rst @@ -9,6 +9,7 @@ Release Notes .. toctree:: :maxdepth: 1 + release-notes-4.11.0.rst release-notes-4.10.6.rst release-notes-4.10.5.rst release-notes-4.10.4.rst diff --git a/docs/requirements_docs.txt b/docs/requirements_docs.txt new file mode 100644 --- /dev/null +++ b/docs/requirements_docs.txt @@ -0,0 +1,8 @@ +Sphinx==1.6.5 +six==1.11.0 +sphinx_rtd_theme==0.2.5b1 +docutils==0.14.0 +Pygments==2.2.0 +MarkupSafe==1.0.0 +Jinja2==2.9.6 +pytz \ No newline at end of file diff --git a/grunt_config.json b/grunt_config.json --- a/grunt_config.json +++ b/grunt_config.json @@ -42,6 +42,8 @@ "<%= dirs.js.src %>/bootstrap.js", "<%= dirs.js.src %>/i18n_utils.js", "<%= dirs.js.src %>/deform.js", + "<%= dirs.js.src %>/ejs.js", + "<%= dirs.js.src %>/ejs_templates/utils.js", "<%= dirs.js.src %>/plugins/jquery.pjax.js", "<%= dirs.js.src %>/plugins/jquery.dataTables.js", "<%= dirs.js.src %>/plugins/flavoured_checkbox.js", diff --git a/pkgs/bower-packages.nix b/pkgs/bower-packages.nix --- a/pkgs/bower-packages.nix +++ b/pkgs/bower-packages.nix @@ -7,7 +7,7 @@ buildEnv { name = "bower-env"; ignoreCol (fetchbower "paper-tooltip" "PolymerElements/paper-tooltip#1.1.3" "PolymerElements/paper-tooltip#^1.1.2" "0vmrm1n8k9sk9nvqy03q177axy22pia6i3j1gxbk72j3pqiqvg6k") (fetchbower "paper-toast" "PolymerElements/paper-toast#1.3.0" "PolymerElements/paper-toast#^1.3.0" "0x9rqxsks5455s8pk4aikpp99ijdn6kxr9gvhwh99nbcqdzcxq1m") (fetchbower "paper-toggle-button" "PolymerElements/paper-toggle-button#1.2.0" "PolymerElements/paper-toggle-button#^1.2.0" "0mphcng3ngspbpg4jjn0mb91nvr4xc1phq3qswib15h6sfww1b2w") - (fetchbower "iron-ajax" "PolymerElements/iron-ajax#1.4.3" "PolymerElements/iron-ajax#^1.4.3" "1b1z3112ggjdflgrwbpmnbsh3kgcm4hn255wshvrlzds4w069gja") + (fetchbower "iron-ajax" "PolymerElements/iron-ajax#1.4.4" "PolymerElements/iron-ajax#^1.4.4" "0jpi7ik3zljw8yh2ccc85r26lcpzmkc2nl1kn6fqdx57zkzk9v5b") (fetchbower "iron-autogrow-textarea" "PolymerElements/iron-autogrow-textarea#1.0.13" "PolymerElements/iron-autogrow-textarea#^1.0.13" "0zwhpl97vii1s8k0lgain8i9dnw29b0mxc5ixdscx9las13n2lqq") (fetchbower "iron-a11y-keys" "PolymerElements/iron-a11y-keys#1.0.6" "PolymerElements/iron-a11y-keys#^1.0.6" "1xz3mgghfcxixq28sdb654iaxj4nyi1bzcwf77ydkms6fviqs9mv") (fetchbower "iron-flex-layout" "PolymerElements/iron-flex-layout#1.3.1" "PolymerElements/iron-flex-layout#^1.0.0" "0nswv3ih3bhflgcd2wjfmddqswzgqxb2xbq65jk9w3rkj26hplbl") diff --git a/pkgs/patch-celery-dateutil.diff b/pkgs/patch-celery-dateutil.diff deleted file mode 100644 --- a/pkgs/patch-celery-dateutil.diff +++ /dev/null @@ -1,12 +0,0 @@ -diff -rup celery-2.2.10-orig/setup.py celery-2.2.10/setup.py ---- celery-2.2.10-orig/setup.py 2017-02-25 15:30:34.000000000 +0100 -+++ celery-2.2.10/setup.py 2017-02-25 15:30:34.000000000 +0100 -@@ -48,7 +48,7 @@ try: - except ImportError: - install_requires.append("importlib") - install_requires.extend([ -- "python-dateutil>=1.5.0,<2.0.0", -+ "python-dateutil>=1.5.0,<2.2.0", - "anyjson>=0.3.1", - "kombu>=1.1.2,<2.0.0", - "pyparsing>=1.5.0,<2.0.0", diff --git a/pkgs/patch-kombu-msgpack.diff b/pkgs/patch-kombu-msgpack.diff deleted file mode 100644 --- a/pkgs/patch-kombu-msgpack.diff +++ /dev/null @@ -1,12 +0,0 @@ -diff -rup kombu-1.5.1-orig/kombu/serialization.py kombu-1.5.1/kombu/serialization.py ---- kombu-1.5.1-orig/kombu/serialization.py 2016-03-09 15:11:34.000000000 +0100 -+++ kombu-1.5.1/kombu/serialization.py 2016-03-09 15:19:20.000000000 +0100 -@@ -318,7 +318,7 @@ def register_msgpack(): - """See http://msgpack.sourceforge.net/""" - try: - import msgpack -- registry.register('msgpack', msgpack.packs, msgpack.unpacks, -+ registry.register('msgpack', msgpack.packb, msgpack.unpackb, - content_type='application/x-msgpack', - content_encoding='binary') - except ImportError: diff --git a/pkgs/patch-kombu-py-2-7-11.diff b/pkgs/patch-kombu-py-2-7-11.diff deleted file mode 100644 --- a/pkgs/patch-kombu-py-2-7-11.diff +++ /dev/null @@ -1,15 +0,0 @@ -diff -rup kombu-1.5.1-orig/kombu/utils/__init__.py kombu-1.5.1/kombu/utils/__init__.py ---- kombu-1.5.1-orig/kombu/utils/__init__.py 2016-03-09 15:11:34.000000000 +0100 -+++ kombu-1.5.1/kombu/utils/__init__.py 2016-03-09 15:15:52.000000000 +0100 -@@ -11,7 +11,10 @@ Internal utilities. - import sys - - from time import sleep --from uuid import UUID, uuid4 as _uuid4, _uuid_generate_random -+from uuid import UUID, uuid4 as _uuid4 -+ -+# Fix for Python 2.7.11 -+_uuid_generate_random = None - - from kombu.utils.encoding import safe_repr as _safe_repr - diff --git a/pkgs/python-packages-overrides.nix b/pkgs/python-packages-overrides.nix --- a/pkgs/python-packages-overrides.nix +++ b/pkgs/python-packages-overrides.nix @@ -31,6 +31,12 @@ self: super: { }; }); + testpath = super.testpath.override (attrs: { + meta = { + license = [ pkgs.lib.licenses.mit ]; + }; + }); + gnureadline = super.gnureadline.override (attrs: { buildInputs = attrs.buildInputs ++ [ pkgs.ncurses @@ -61,23 +67,6 @@ self: super: { ]; }); - celery = super.celery.override (attrs: { - # The current version of kombu needs some patching to work with the - # other libs. Should be removed once we update celery and kombu. - patches = [ - ./patch-celery-dateutil.diff - ]; - }); - - kombu = super.kombu.override (attrs: { - # The current version of kombu needs some patching to work with the - # other libs. Should be removed once we update celery and kombu. - patches = [ - ./patch-kombu-py-2-7-11.diff - ./patch-kombu-msgpack.diff - ]; - }); - lxml = super.lxml.override (attrs: { # johbo: On 16.09 we need this to compile on darwin, otherwise compilation # fails on Darwin. @@ -114,10 +103,6 @@ self: super: { }; }); - py-gfm = super.py-gfm.override { - name = "py-gfm-0.1.3.rhodecode-upstream1"; - }; - pycurl = super.pycurl.override (attrs: { propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ pkgs.curl @@ -133,10 +118,6 @@ self: super: { }; }); - Pylons = super.Pylons.override (attrs: { - name = "Pylons-1.0.2.rhodecode-patch1"; - }); - pyramid = super.pyramid.override (attrs: { postFixup = '' wrapPythonPrograms @@ -208,12 +189,6 @@ self: super: { }; }); - amqplib = super.amqplib.override (attrs: { - meta = { - license = pkgs.lib.licenses.lgpl3; - }; - }); - docutils = super.docutils.override (attrs: { meta = { license = pkgs.lib.licenses.bsd2; diff --git a/pkgs/python-packages.nix b/pkgs/python-packages.nix --- a/pkgs/python-packages.nix +++ b/pkgs/python-packages.nix @@ -68,13 +68,13 @@ }; }; Jinja2 = super.buildPythonPackage { - name = "Jinja2-2.7.3"; + name = "Jinja2-2.9.6"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [MarkupSafe]; src = fetchurl { - url = "https://pypi.python.org/packages/b0/73/eab0bca302d6d6a0b5c402f47ad1760dc9cb2dd14bbc1873ad48db258e4d/Jinja2-2.7.3.tar.gz"; - md5 = "b9dffd2f3b43d673802fe857c8445b1a"; + url = "https://pypi.python.org/packages/90/61/f820ff0076a2599dd39406dcb858ecb239438c02ce706c8e91131ab9c7f1/Jinja2-2.9.6.tar.gz"; + md5 = "6411537324b4dba0956aaa8109f3c77b"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -94,26 +94,26 @@ }; }; Markdown = super.buildPythonPackage { - name = "Markdown-2.6.8"; + name = "Markdown-2.6.9"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/1d/25/3f6d2cb31ec42ca5bd3bfbea99b63892b735d76e26f20dd2dcc34ffe4f0d/Markdown-2.6.8.tar.gz"; - md5 = "d9ef057a5bd185f6f536400a31fc5d45"; + url = "https://pypi.python.org/packages/29/82/dfe242bcfd9eec0e7bf93a80a8f8d8515a95b980c44f5c0b45606397a423/Markdown-2.6.9.tar.gz"; + md5 = "56547d362a9abcf30955b8950b08b5e3"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; }; }; MarkupSafe = super.buildPythonPackage { - name = "MarkupSafe-0.23"; + name = "MarkupSafe-1.0"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz"; - md5 = "f5ab3deee4c37cd6a922fb81e730da6e"; + url = "https://pypi.python.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz"; + md5 = "2fcedc9284d50e577b5192e8e3578355"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -159,13 +159,13 @@ }; }; PasteScript = super.buildPythonPackage { - name = "PasteScript-1.7.5"; + name = "PasteScript-2.0.2"; buildInputs = with self; []; doCheck = false; - propagatedBuildInputs = with self; [Paste PasteDeploy]; + propagatedBuildInputs = with self; [Paste PasteDeploy six]; src = fetchurl { - url = "https://pypi.python.org/packages/a5/05/fc60efa7c2f17a1dbaeccb2a903a1e90902d92b9d00eebabe3095829d806/PasteScript-1.7.5.tar.gz"; - md5 = "4c72d78dcb6bb993f30536842c16af4d"; + url = "https://pypi.python.org/packages/e5/f0/78e766c3dcc61a4f3a6f71dd8c95168ae9c7a31722b5663d19c1fdf62cb6/PasteScript-2.0.2.tar.gz"; + md5 = "ccb3045445097192ca71a13b746c77b2"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -184,56 +184,30 @@ license = [ pkgs.lib.licenses.bsdOriginal ]; }; }; - Pylons = super.buildPythonPackage { - name = "Pylons-1.0.2.dev20171106"; - buildInputs = with self; []; - doCheck = false; - propagatedBuildInputs = with self; [Routes WebHelpers Beaker Paste PasteDeploy PasteScript FormEncode simplejson decorator nose Mako WebError WebTest Tempita MarkupSafe WebOb]; - src = fetchurl { - url = "https://code.rhodecode.com/upstream/pylons/archive/707354ee4261b9c10450404fc9852ccea4fd667d.tar.gz?md5=f26633726fa2cd3a340316ee6a5d218f"; - md5 = "f26633726fa2cd3a340316ee6a5d218f"; - }; - meta = { - license = [ pkgs.lib.licenses.bsdOriginal ]; - }; - }; Routes = super.buildPythonPackage { - name = "Routes-1.13"; + name = "Routes-2.4.1"; buildInputs = with self; []; doCheck = false; - propagatedBuildInputs = with self; [repoze.lru]; + propagatedBuildInputs = with self; [six repoze.lru]; src = fetchurl { - url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz"; - md5 = "d527b0ab7dd9172b1275a41f97448783"; - }; - meta = { - license = [ pkgs.lib.licenses.bsdOriginal ]; - }; - }; - SQLAlchemy = super.buildPythonPackage { - name = "SQLAlchemy-1.1.11"; - buildInputs = with self; []; - doCheck = false; - propagatedBuildInputs = with self; []; - src = fetchurl { - url = "https://pypi.python.org/packages/59/f1/28f2205c3175e6bf32300c0f30f9d91dbc9eb910debbff3ffecb88d18528/SQLAlchemy-1.1.11.tar.gz"; - md5 = "3de387eddb4012083a4562928c511e43"; + url = "https://pypi.python.org/packages/33/38/ea827837e68d9c7dde4cff7ec122a93c319f0effc08ce92a17095576603f/Routes-2.4.1.tar.gz"; + md5 = "c058dff6832941dec47e0d0052548ad8"; }; meta = { license = [ pkgs.lib.licenses.mit ]; }; }; - Sphinx = super.buildPythonPackage { - name = "Sphinx-1.2.2"; + SQLAlchemy = super.buildPythonPackage { + name = "SQLAlchemy-1.1.15"; buildInputs = with self; []; doCheck = false; - propagatedBuildInputs = with self; [Pygments docutils Jinja2]; + propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/0a/50/34017e6efcd372893a416aba14b84a1a149fc7074537b0e9cb6ca7b7abe9/Sphinx-1.2.2.tar.gz"; - md5 = "3dc73ccaa8d0bfb2d62fb671b1f7e8a4"; + url = "https://pypi.python.org/packages/c2/f6/11fcc1ce19a7cb81b1c9377f4e27ce3813265611922e355905e57c44d164/SQLAlchemy-1.1.15.tar.gz"; + md5 = "077f9bd3339957f53068b5572a152674"; }; meta = { - license = [ pkgs.lib.licenses.bsdOriginal ]; + license = [ pkgs.lib.licenses.mit ]; }; }; Tempita = super.buildPythonPackage { @@ -315,13 +289,13 @@ }; }; WebTest = super.buildPythonPackage { - name = "WebTest-2.0.27"; + name = "WebTest-2.0.29"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [six WebOb waitress beautifulsoup4]; src = fetchurl { - url = "https://pypi.python.org/packages/80/fa/ca3a759985c72e3a124cbca3e1f8a2e931a07ffd31fd45d8f7bf21cb95cf/WebTest-2.0.27.tar.gz"; - md5 = "54e6515ac71c51b6fc90179483c749ad"; + url = "https://pypi.python.org/packages/94/de/8f94738be649997da99c47b104aa3c3984ecec51a1d8153ed09638253d56/WebTest-2.0.29.tar.gz"; + md5 = "30b4cf0d340b9a5335fac4389e6f84fc"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -341,52 +315,39 @@ }; }; alembic = super.buildPythonPackage { - name = "alembic-0.9.2"; + name = "alembic-0.9.6"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor python-dateutil]; src = fetchurl { - url = "https://pypi.python.org/packages/78/48/b5b26e7218b415f40b60b92c53853d242e5456c0f19f6c66101d98ff5f2a/alembic-0.9.2.tar.gz"; - md5 = "40daf8bae50969beea40efaaf0839ff4"; + url = "https://pypi.python.org/packages/bf/b3/b28ea715824f8455635ece3c12f59d5d205f98cc378858e414e3aa6ebdbc/alembic-0.9.6.tar.gz"; + md5 = "fcb096bccc87c8770bd07a04606cb989"; }; meta = { license = [ pkgs.lib.licenses.mit ]; }; }; - amqplib = super.buildPythonPackage { - name = "amqplib-1.0.2"; + amqp = super.buildPythonPackage { + name = "amqp-2.2.2"; buildInputs = with self; []; doCheck = false; - propagatedBuildInputs = with self; []; + propagatedBuildInputs = with self; [vine]; src = fetchurl { - url = "https://pypi.python.org/packages/75/b7/8c2429bf8d92354a0118614f9a4d15e53bc69ebedce534284111de5a0102/amqplib-1.0.2.tgz"; - md5 = "5c92f17fbedd99b2b4a836d4352d1e2f"; - }; - meta = { - license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ]; - }; - }; - anyjson = super.buildPythonPackage { - name = "anyjson-0.3.3"; - buildInputs = with self; []; - doCheck = false; - propagatedBuildInputs = with self; []; - src = fetchurl { - url = "https://pypi.python.org/packages/c3/4d/d4089e1a3dd25b46bebdb55a992b0797cff657b4477bc32ce28038fdecbc/anyjson-0.3.3.tar.gz"; - md5 = "2ea28d6ec311aeeebaf993cb3008b27c"; + url = "https://pypi.python.org/packages/e0/70/9ab9ccd8247fb7d2adb717e9f6a0ed358c9e1ab2c349048b0352f9e80ee2/amqp-2.2.2.tar.gz"; + md5 = "0971a3fd2d635ded45c349cfc17106bd"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; }; }; appenlight-client = super.buildPythonPackage { - name = "appenlight-client-0.6.21"; + name = "appenlight-client-0.6.22"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [WebOb requests six]; src = fetchurl { - url = "https://pypi.python.org/packages/c9/23/91b66cfa0b963662c10b2a06ccaadf3f3a4848a7a2aa16255cb43d5160ec/appenlight_client-0.6.21.tar.gz"; - md5 = "273999ac854fdaefa8d0fb61965a4ed9"; + url = "https://pypi.python.org/packages/73/37/0a64460fa9670b17c061adc433bc8be5079cba21e8b3a92d824adccb12bc/appenlight_client-0.6.22.tar.gz"; + md5 = "641afc114a9a3b3af4f75b11c70968ee"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -431,27 +392,40 @@ license = [ pkgs.lib.licenses.mit ]; }; }; + billiard = super.buildPythonPackage { + name = "billiard-3.5.0.3"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/39/ac/f5571210cca2e4f4532e38aaff242f26c8654c5e2436bee966c230647ccc/billiard-3.5.0.3.tar.gz"; + md5 = "113ba481e48400adbf6fbbf59a2f8554"; + }; + meta = { + license = [ pkgs.lib.licenses.bsdOriginal ]; + }; + }; bleach = super.buildPythonPackage { - name = "bleach-1.5.0"; + name = "bleach-2.1.1"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [six html5lib]; src = fetchurl { - url = "https://pypi.python.org/packages/99/00/25a8fce4de102bf6e3cc76bc4ea60685b2fee33bde1b34830c70cacc26a7/bleach-1.5.0.tar.gz"; - md5 = "b663300efdf421b3b727b19d7be9c7e7"; + url = "https://pypi.python.org/packages/d4/3f/d517089af35b01bb9bc4eac5ea04bae342b37a5e9abbb27b7c3ce0eae070/bleach-2.1.1.tar.gz"; + md5 = "7c5dfb1d66ea979b5a465afb12c82ec4"; }; meta = { license = [ pkgs.lib.licenses.asl20 ]; }; }; bottle = super.buildPythonPackage { - name = "bottle-0.12.8"; + name = "bottle-0.12.13"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/52/df/e4a408f3a7af396d186d4ecd3b389dd764f0f943b4fa8d257bfe7b49d343/bottle-0.12.8.tar.gz"; - md5 = "13132c0a8f607bf860810a6ee9064c5b"; + url = "https://pypi.python.org/packages/bd/99/04dc59ced52a8261ee0f965a8968717a255ea84a36013e527944dbf3468c/bottle-0.12.13.tar.gz"; + md5 = "d2fe1b48c1d49217e78bf326b1cad437"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -471,13 +445,13 @@ }; }; celery = super.buildPythonPackage { - name = "celery-2.2.10"; + name = "celery-4.1.0"; buildInputs = with self; []; doCheck = false; - propagatedBuildInputs = with self; [python-dateutil anyjson kombu pyparsing]; + propagatedBuildInputs = with self; [pytz billiard kombu]; src = fetchurl { - url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz"; - md5 = "898bc87e54f278055b561316ba73e222"; + url = "https://pypi.python.org/packages/07/65/88a2a45fc80f487872c93121a701a53bbbc3d3d832016876fac84fc8d46a/celery-4.1.0.tar.gz"; + md5 = "db91e1d26936381127f01e150fe3054a"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -497,26 +471,26 @@ }; }; click = super.buildPythonPackage { - name = "click-5.1"; + name = "click-6.6"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/b7/34/a496632c4fb6c1ee76efedf77bb8d28b29363d839953d95095b12defe791/click-5.1.tar.gz"; - md5 = "9c5323008cccfe232a8b161fc8196d41"; + url = "https://pypi.python.org/packages/7a/00/c14926d8232b36b08218067bcd5853caefb4737cda3f0a47437151344792/click-6.6.tar.gz"; + md5 = "d0b09582123605220ad6977175f3e51d"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; }; }; colander = super.buildPythonPackage { - name = "colander-1.3.3"; + name = "colander-1.4"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [translationstring iso8601]; src = fetchurl { - url = "https://pypi.python.org/packages/54/a9/9862a561e015b2c7b56404c0b13828a8bdc51e05ab3703bd792cec064487/colander-1.3.3.tar.gz"; - md5 = "f5d783768c51d73695f49bbe95778ab4"; + url = "https://pypi.python.org/packages/cc/e2/c4e716ac4a426d8ad4dfe306c34f0018a22275d2420815784005bf771c84/colander-1.4.tar.gz"; + md5 = "cbb8e403c2ba05aeaa419d51fdb93736"; }; meta = { license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; @@ -588,13 +562,13 @@ }; }; decorator = super.buildPythonPackage { - name = "decorator-4.0.11"; + name = "decorator-4.1.2"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/cc/ac/5a16f1fc0506ff72fcc8fd4e858e3a1c231f224ab79bb7c4c9b2094cc570/decorator-4.0.11.tar.gz"; - md5 = "73644c8f0bd4983d1b6a34b49adec0ae"; + url = "https://pypi.python.org/packages/bb/e0/f6e41e9091e130bf16d4437dabbac3993908e4d6485ecbc985ef1352db94/decorator-4.1.2.tar.gz"; + md5 = "a0f7f4fe00ae2dde93494d90c192cf8c"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal { fullName = "new BSD License"; } ]; @@ -614,13 +588,13 @@ }; }; docutils = super.buildPythonPackage { - name = "docutils-0.13.1"; + name = "docutils-0.14"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/05/25/7b5484aca5d46915493f1fd4ecb63c38c333bd32aa9ad6e19da8d08895ae/docutils-0.13.1.tar.gz"; - md5 = "ea4a893c633c788be9b8078b6b305d53"; + url = "https://pypi.python.org/packages/84/f4/5771e41fdf52aabebbadecc9381d11dea0fa34e4759b4071244fa094804c/docutils-0.14.tar.gz"; + md5 = "c53768d63db3873b7d452833553469de"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.publicDomain pkgs.lib.licenses.gpl1 { fullName = "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)"; } pkgs.lib.licenses.psfl ]; @@ -783,39 +757,39 @@ }; }; gnureadline = super.buildPythonPackage { - name = "gnureadline-6.3.3"; + name = "gnureadline-6.3.8"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/3a/ee/2c3f568b0a74974791ac590ec742ef6133e2fbd287a074ba72a53fa5e97c/gnureadline-6.3.3.tar.gz"; - md5 = "c4af83c9a3fbeac8f2da9b5a7c60e51c"; + url = "https://pypi.python.org/packages/50/64/86085c823cd78f9df9d8e33dce0baa71618016f8860460b82cf6610e1eb3/gnureadline-6.3.8.tar.gz"; + md5 = "ba341f4b907250bd1f47dbc06290604f"; }; meta = { - license = [ pkgs.lib.licenses.gpl1 ]; + license = [ { fullName = "GNU General Public License v3 (GPLv3)"; } pkgs.lib.licenses.gpl1 ]; }; }; gprof2dot = super.buildPythonPackage { - name = "gprof2dot-2016.10.13"; + name = "gprof2dot-2017.9.19"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/a0/e0/73c71baed306f0402a00a94ffc7b2be94ad1296dfcb8b46912655b93154c/gprof2dot-2016.10.13.tar.gz"; - md5 = "0125401f15fd2afe1df686a76c64a4fd"; + url = "https://pypi.python.org/packages/9d/36/f977122502979f3dfb50704979c9ed70e6b620787942b089bf1af15f5aba/gprof2dot-2017.9.19.tar.gz"; + md5 = "cda2d552bb0d0b9f16e6824a9aabd225"; }; meta = { - license = [ { fullName = "LGPL"; } ]; + license = [ { fullName = "GNU Lesser General Public License v3 or later (LGPLv3+)"; } { fullName = "LGPL"; } ]; }; }; graphviz = super.buildPythonPackage { - name = "graphviz-0.8"; + name = "graphviz-0.8.1"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/da/84/0e997520323d6b01124eb01c68d5c101814d0aab53083cd62bd75a90f70b/graphviz-0.8.zip"; - md5 = "9486a885360a5ee54a81eb2950470c71"; + url = "https://pypi.python.org/packages/a9/a6/ee6721349489a2da6eedd3dba124f2b5ac15ee1e0a7bd4d3cfdc4fff0327/graphviz-0.8.1.zip"; + md5 = "88d8efa88c02a735b3659fe0feaf0b96"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -848,13 +822,13 @@ }; }; html5lib = super.buildPythonPackage { - name = "html5lib-0.9999999"; + name = "html5lib-1.0b10"; buildInputs = with self; []; doCheck = false; - propagatedBuildInputs = with self; [six]; + propagatedBuildInputs = with self; [six webencodings setuptools]; src = fetchurl { - url = "https://pypi.python.org/packages/ae/ae/bcb60402c60932b32dfaf19bb53870b29eda2cd17551ba5639219fb5ebf9/html5lib-0.9999999.tar.gz"; - md5 = "ef43cb05e9e799f25d65d1135838a96f"; + url = "https://pypi.python.org/packages/97/16/982214624095c1420c75f3bd295d9e658794aafb95fc075823de107e0ae4/html5lib-1.0b10.tar.gz"; + md5 = "5ada1243b7a863624b2f35245b2186e9"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -952,13 +926,13 @@ }; }; iso8601 = super.buildPythonPackage { - name = "iso8601-0.1.11"; + name = "iso8601-0.1.12"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/c0/75/c9209ee4d1b5975eb8c2cba4428bde6b61bd55664a98290dd015cdb18e98/iso8601-0.1.11.tar.gz"; - md5 = "b06d11cd14a64096f907086044f0fe38"; + url = "https://pypi.python.org/packages/45/13/3db24895497345fb44c4248c08b16da34a9eb02643cea2754b21b5ed08b0/iso8601-0.1.12.tar.gz"; + md5 = "4de940f691c5ea759fb254384c8ddcf6"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -1004,26 +978,26 @@ }; }; jupyter-core = super.buildPythonPackage { - name = "jupyter-core-4.3.0"; + name = "jupyter-core-4.4.0"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [traitlets]; src = fetchurl { - url = "https://pypi.python.org/packages/2f/39/5138f975100ce14d150938df48a83cd852a3fd8e24b1244f4113848e69e2/jupyter_core-4.3.0.tar.gz"; - md5 = "18819511a809afdeed9a995a9c27bcfb"; + url = "https://pypi.python.org/packages/b6/2d/2804f4de3a95583f65e5dcb4d7c8c7183124882323758996e867f47e72af/jupyter_core-4.4.0.tar.gz"; + md5 = "7829fc07884ed98459e170f217e2a5ba"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; }; }; kombu = super.buildPythonPackage { - name = "kombu-1.5.1"; + name = "kombu-4.1.0"; buildInputs = with self; []; doCheck = false; - propagatedBuildInputs = with self; [anyjson amqplib]; + propagatedBuildInputs = with self; [amqp]; src = fetchurl { - url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz"; - md5 = "50662f3c7e9395b3d0721fb75d100b63"; + url = "https://pypi.python.org/packages/03/5e/1a47d1e543d4943d65330af4e4406049f443878818fb65bfdc651bb93a96/kombu-4.1.0.tar.gz"; + md5 = "2fb2be9fec0e6514231bba23a3779439"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -1056,13 +1030,13 @@ }; }; mistune = super.buildPythonPackage { - name = "mistune-0.7.4"; + name = "mistune-0.8.3"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/25/a4/12a584c0c59c9fed529f8b3c47ca8217c0cf8bcc5e1089d3256410cfbdbc/mistune-0.7.4.tar.gz"; - md5 = "92d01cb717e9e74429e9bde9d29ac43b"; + url = "https://pypi.python.org/packages/9d/be/e06d4346cc608a01dec6bf770d7d0303a4fd6db588b318ced18f5f257145/mistune-0.8.3.tar.gz"; + md5 = "a5e4043e93fb8f9082e27f29eeb5e054"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -1095,52 +1069,39 @@ }; }; nbconvert = super.buildPythonPackage { - name = "nbconvert-5.1.1"; + name = "nbconvert-5.3.1"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [mistune Jinja2 Pygments traitlets jupyter-core nbformat entrypoints bleach pandocfilters testpath]; src = fetchurl { - url = "https://pypi.python.org/packages/95/58/df1c91f1658ee5df19097f915a1e71c91fc824a708d82d2b2e35f8b80e9a/nbconvert-5.1.1.tar.gz"; - md5 = "d0263fb03a44db2f94eea09a608ed813"; + url = "https://pypi.python.org/packages/b9/a4/d0a0938ad6f5eeb4dea4e73d255c617ef94b0b2849d51194c9bbdb838412/nbconvert-5.3.1.tar.gz"; + md5 = "c128d0d93d02f70a85429a383dae96d2"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; }; }; nbformat = super.buildPythonPackage { - name = "nbformat-4.3.0"; + name = "nbformat-4.4.0"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [ipython-genutils traitlets jsonschema jupyter-core]; src = fetchurl { - url = "https://pypi.python.org/packages/f9/c5/89df4abf906f766727f976e170caa85b4f1c1d1feb1f45d716016e68e19f/nbformat-4.3.0.tar.gz"; - md5 = "9a00d20425914cd5ba5f97769d9963ca"; + url = "https://pypi.python.org/packages/6e/0e/160754f7ae3e984863f585a3743b0ed1702043a81245907c8fae2d537155/nbformat-4.4.0.tar.gz"; + md5 = "2d5f873138d9fbc2a3f9eaaebca3b8a1"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; }; }; - nose = super.buildPythonPackage { - name = "nose-1.3.6"; - buildInputs = with self; []; - doCheck = false; - propagatedBuildInputs = with self; []; - src = fetchurl { - url = "https://pypi.python.org/packages/70/c7/469e68148d17a0d3db5ed49150242fd70a74a8147b8f3f8b87776e028d99/nose-1.3.6.tar.gz"; - md5 = "0ca546d81ca8309080fc80cb389e7a16"; - }; - meta = { - license = [ { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "GNU LGPL"; } ]; - }; - }; objgraph = super.buildPythonPackage { - name = "objgraph-3.1.0"; + name = "objgraph-3.1.1"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [graphviz]; src = fetchurl { - url = "https://pypi.python.org/packages/f4/b3/082e54e62094cb2ec84f8d5a49e0142cef99016491cecba83309cff920ae/objgraph-3.1.0.tar.gz"; - md5 = "eddbd96039796bfbd13eee403701e64a"; + url = "https://pypi.python.org/packages/be/58/9ca81a20cc837054e94866df1475d899caaa94f3732b8a46006858b015f7/objgraph-3.1.1.tar.gz"; + md5 = "253af9944763377877c3678d8aaebb8b"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -1199,13 +1160,13 @@ }; }; pexpect = super.buildPythonPackage { - name = "pexpect-4.2.1"; + name = "pexpect-4.3.0"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [ptyprocess]; src = fetchurl { - url = "https://pypi.python.org/packages/e8/13/d0b0599099d6cd23663043a2a0bb7c61e58c6ba359b2656e6fb000ef5b98/pexpect-4.2.1.tar.gz"; - md5 = "3694410001a99dff83f0b500a1ca1c95"; + url = "https://pypi.python.org/packages/f8/44/5466c30e49762bb92e442bbdf4472d6904608d211258eb3198a11f0309a4/pexpect-4.3.0.tar.gz"; + md5 = "047a486dcd26134b74f2e67046bb61a0"; }; meta = { license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ]; @@ -1225,26 +1186,26 @@ }; }; plaster = super.buildPythonPackage { - name = "plaster-0.5"; + name = "plaster-1.0"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [setuptools]; src = fetchurl { - url = "https://pypi.python.org/packages/99/b3/d7ca1fe31d2b56dba68a238721fda6820770f9c2a3de17a582d4b5b2edcc/plaster-0.5.tar.gz"; - md5 = "c59345a67a860cfcaa1bd6a81451399d"; + url = "https://pypi.python.org/packages/37/e1/56d04382d718d32751017d32f351214384e529b794084eee20bb52405563/plaster-1.0.tar.gz"; + md5 = "80e6beb4760c16fea31754babcc0576e"; }; meta = { license = [ pkgs.lib.licenses.mit ]; }; }; plaster-pastedeploy = super.buildPythonPackage { - name = "plaster-pastedeploy-0.4.1"; + name = "plaster-pastedeploy-0.4.2"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [PasteDeploy plaster]; src = fetchurl { - url = "https://pypi.python.org/packages/9d/6e/f8be01ed41c94e6c54ac97cf2eb142a702aae0c8cce31c846f785e525b40/plaster_pastedeploy-0.4.1.tar.gz"; - md5 = "f48d5344b922e56c4978eebf1cd2e0d3"; + url = "https://pypi.python.org/packages/2c/62/0daf9c0be958e785023e583e51baac15863699e956bfb3d448898d80edd8/plaster_pastedeploy-0.4.2.tar.gz"; + md5 = "58fd7852002909378e818c9d5b71e90a"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -1264,26 +1225,26 @@ }; }; psutil = super.buildPythonPackage { - name = "psutil-4.3.1"; + name = "psutil-5.4.0"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/78/cc/f267a1371f229bf16db6a4e604428c3b032b823b83155bd33cef45e49a53/psutil-4.3.1.tar.gz"; - md5 = "199a366dba829c88bddaf5b41d19ddc0"; + url = "https://pypi.python.org/packages/8d/96/1fc6468be91521192861966c40bd73fdf8b065eae6d82dd0f870b9825a65/psutil-5.4.0.tar.gz"; + md5 = "01af6219b1e8fcfd53603023967713bf"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; }; }; psycopg2 = super.buildPythonPackage { - name = "psycopg2-2.7.1"; + name = "psycopg2-2.7.3.2"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/f8/e9/5793369ce8a41bf5467623ded8d59a434dfef9c136351aca4e70c2657ba0/psycopg2-2.7.1.tar.gz"; - md5 = "67848ac33af88336046802f6ef7081f3"; + url = "https://pypi.python.org/packages/dd/47/000b405d73ca22980684fd7bd3318690cc03cfa3b2ae1c5b7fff8050b28a/psycopg2-2.7.3.2.tar.gz"; + md5 = "8114e672d5f23fa5329874a4314fbd6f"; }; meta = { license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ]; @@ -1303,13 +1264,13 @@ }; }; py = super.buildPythonPackage { - name = "py-1.4.34"; + name = "py-1.5.2"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/68/35/58572278f1c097b403879c1e9369069633d1cbad5239b9057944bb764782/py-1.4.34.tar.gz"; - md5 = "d9c3d8f734b0819ff48e355d77bf1730"; + url = "https://pypi.python.org/packages/90/e3/e075127d39d35f09a500ebb4a90afd10f9ef0a1d28a6d09abeec0e444fdd/py-1.5.2.tar.gz"; + md5 = "279ca69c632069e1b71e11b14641ca28"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -1334,8 +1295,8 @@ doCheck = false; propagatedBuildInputs = with self; [setuptools Markdown]; src = fetchurl { - url = "https://code.rhodecode.com/upstream/py-gfm/archive/0d66a19bc16e3d49de273c0f797d4e4781e8c0f2.tar.gz?md5=0d0d5385bfb629eea636a80b9c2bfd16"; - md5 = "0d0d5385bfb629eea636a80b9c2bfd16"; + url = "https://pypi.python.org/packages/12/e4/6b3d8678da04f97d7490d8264d8de51c2dc9fb91209ccee9c515c95e14c5/py-gfm-0.1.3.tar.gz"; + md5 = "e588d9e69640a241b97e2c59c22527a6"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -1433,26 +1394,26 @@ }; }; pyramid-debugtoolbar = super.buildPythonPackage { - name = "pyramid-debugtoolbar-4.2.1"; + name = "pyramid-debugtoolbar-4.3"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments ipaddress]; src = fetchurl { - url = "https://pypi.python.org/packages/db/26/94620b7752936e2cd74838263ff366db9b454f7394bfb62d1eb2f84b29c1/pyramid_debugtoolbar-4.2.1.tar.gz"; - md5 = "3dfaced2fab1644ff5284017be9d92b9"; + url = "https://pypi.python.org/packages/a4/40/f09d8800bfc3c09bdb6c95f37bb61c890dc62c19c4e7caa304da7aa77403/pyramid_debugtoolbar-4.3.tar.gz"; + md5 = "9c49029e9f0695130499ef6416ffaaf8"; }; meta = { license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ]; }; }; pyramid-jinja2 = super.buildPythonPackage { - name = "pyramid-jinja2-2.5"; + name = "pyramid-jinja2-2.7"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [pyramid zope.deprecation Jinja2 MarkupSafe]; src = fetchurl { - url = "https://pypi.python.org/packages/a1/80/595e26ffab7deba7208676b6936b7e5a721875710f982e59899013cae1ed/pyramid_jinja2-2.5.tar.gz"; - md5 = "07cb6547204ac5e6f0b22a954ccee928"; + url = "https://pypi.python.org/packages/d8/80/d60a7233823de22ce77bd864a8a83736a1fe8b49884b08303a2e68b2c853/pyramid_jinja2-2.7.tar.gz"; + md5 = "c2f8b2cd7b73a6f1d9a311fcfaf4fb92"; }; meta = { license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; @@ -1485,13 +1446,13 @@ }; }; pytest = super.buildPythonPackage { - name = "pytest-3.1.2"; + name = "pytest-3.2.5"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [py setuptools]; src = fetchurl { - url = "https://pypi.python.org/packages/72/2b/2d3155e01f45a5a04427857352ee88220ee39550b2bc078f9db3190aea46/pytest-3.1.2.tar.gz"; - md5 = "c4d179f89043cc925e1c169d03128e02"; + url = "https://pypi.python.org/packages/1f/f8/8cd74c16952163ce0db0bd95fdd8810cbf093c08be00e6e665ebf0dc3138/pytest-3.2.5.tar.gz"; + md5 = "6dbe9bb093883f75394a689a1426ac6f"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -1524,39 +1485,39 @@ }; }; pytest-profiling = super.buildPythonPackage { - name = "pytest-profiling-1.2.6"; + name = "pytest-profiling-1.2.11"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [six pytest gprof2dot]; src = fetchurl { - url = "https://pypi.python.org/packages/f9/0d/df67fb9ce16c2cef201693da956321b1bccfbf9a4ead39748b9f9d1d74cb/pytest-profiling-1.2.6.tar.gz"; - md5 = "50eb4c66c3762a2f1a49669bedc0b894"; + url = "https://pypi.python.org/packages/c0/4a/b4aa786e93c07a86f1f87c581a36bf355a9e06a9da7e00dbd05047626bd2/pytest-profiling-1.2.11.tar.gz"; + md5 = "9ef6b60248731be5d44477980408e8f7"; }; meta = { license = [ pkgs.lib.licenses.mit ]; }; }; pytest-runner = super.buildPythonPackage { - name = "pytest-runner-2.11.1"; + name = "pytest-runner-3.0"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/9e/4d/08889e5e27a9f5d6096b9ad257f4dea1faabb03c5ded8f665ead448f5d8a/pytest-runner-2.11.1.tar.gz"; - md5 = "bdb73eb18eca2727944a2dcf963c5a81"; + url = "https://pypi.python.org/packages/65/b4/ae89338cd2d81e2cc54bd6db2e962bfe948f612303610d68ab24539ac2d1/pytest-runner-3.0.tar.gz"; + md5 = "8f8363a52bbabc4cedd5e239beb2ba11"; }; meta = { license = [ pkgs.lib.licenses.mit ]; }; }; pytest-sugar = super.buildPythonPackage { - name = "pytest-sugar-0.8.0"; + name = "pytest-sugar-0.9.0"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [pytest termcolor]; src = fetchurl { - url = "https://pypi.python.org/packages/a5/b0/b2773dee078f17773a5bf2dfad49b0be57b6354bbd84bbefe4313e509d87/pytest-sugar-0.8.0.tar.gz"; - md5 = "8cafbdad648068e0e44b8fc5f9faae42"; + url = "https://pypi.python.org/packages/49/d8/c5ff6cca3ce2ebd8b73eec89779bf6b4a7737456a70e8ea4d44c1ff90f71/pytest-sugar-0.9.0.tar.gz"; + md5 = "89fbff17277fa6a95a560a04b68cb9f9"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -1576,16 +1537,16 @@ }; }; python-dateutil = super.buildPythonPackage { - name = "python-dateutil-2.1"; + name = "python-dateutil-2.6.1"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [six]; src = fetchurl { - url = "https://pypi.python.org/packages/65/52/9c18dac21f174ad31b65e22d24297864a954e6fe65876eba3f5773d2da43/python-dateutil-2.1.tar.gz"; - md5 = "1534bb15cf311f07afaa3aacba1c028b"; + url = "https://pypi.python.org/packages/54/bb/f1db86504f7a49e1d9b9301531181b00a1c7325dc85a29160ee3eaa73a54/python-dateutil-2.6.1.tar.gz"; + md5 = "db38f6b4511cefd76014745bb0cc45a4"; }; meta = { - license = [ { fullName = "Simplified BSD"; } ]; + license = [ pkgs.lib.licenses.bsdOriginal { fullName = "Simplified BSD"; } ]; }; }; python-editor = super.buildPythonPackage { @@ -1602,13 +1563,13 @@ }; }; python-ldap = super.buildPythonPackage { - name = "python-ldap-2.4.40"; + name = "python-ldap-2.4.45"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [setuptools]; src = fetchurl { - url = "https://pypi.python.org/packages/4a/d8/7d70a7469058a3987d224061a81d778951ac2b48220bdcc511e4b1b37176/python-ldap-2.4.40.tar.gz"; - md5 = "aea0233f7d39b0c7549fcd310deeb0e5"; + url = "https://pypi.python.org/packages/ce/52/6b5372d0166820f4a4b0a88ed73dc7504219355049fc1d266d8ccdb7942e/python-ldap-2.4.45.tar.gz"; + md5 = "6108e189a44eea8bc7d1cc281c222978"; }; meta = { license = [ pkgs.lib.licenses.psfl ]; @@ -1641,13 +1602,13 @@ }; }; pytz = super.buildPythonPackage { - name = "pytz-2015.4"; + name = "pytz-2017.3"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip"; - md5 = "233f2a2b370d03f9b5911700cc9ebf3c"; + url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip"; + md5 = "7006b56c0d68a162d9fe57d4249c3171"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -1693,13 +1654,13 @@ }; }; repoze.lru = super.buildPythonPackage { - name = "repoze.lru-0.6"; + name = "repoze.lru-0.7"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/6e/1e/aa15cc90217e086dc8769872c8778b409812ff036bf021b15795638939e4/repoze.lru-0.6.tar.gz"; - md5 = "2c3b64b17a8e18b405f55d46173e14dd"; + url = "https://pypi.python.org/packages/12/bc/595a77c4b5e204847fdf19268314ef59c85193a9dc9f83630fc459c0fee5/repoze.lru-0.7.tar.gz"; + md5 = "c08cc030387e0b1fc53c5c7d964b35e2"; }; meta = { license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; @@ -1719,49 +1680,49 @@ }; }; rhodecode-enterprise-ce = super.buildPythonPackage { - name = "rhodecode-enterprise-ce-4.10.6"; + name = "rhodecode-enterprise-ce-4.11.0"; buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj]; doCheck = true; - propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments pygments-markdown-lexer Pylons Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic cssselect celery channelstream colander decorator deform docutils gevent gunicorn infrae.cache ipython iso8601 kombu lxml msgpack-python nbconvert packaging psycopg2 py-gfm pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client redis repoze.lru requests simplejson sshpubkeys subprocess32 waitress zope.cachedescriptors dogpile.cache dogpile.core psutil py-bcrypt]; + propagatedBuildInputs = with self; [setuptools-scm amqp authomatic Babel Beaker celery Chameleon channelstream click colander configobj cssselect decorator deform docutils dogpile.cache dogpile.core ecdsa FormEncode future futures gnureadline infrae.cache iso8601 itsdangerous Jinja2 billiard kombu lxml Mako Markdown MarkupSafe msgpack-python MySQL-python objgraph packaging Paste PasteDeploy PasteScript pathlib2 peppercorn psutil psycopg2 py-bcrypt pycrypto pycurl pyflakes pygments-markdown-lexer Pygments pyparsing pyramid-beaker pyramid-debugtoolbar pyramid-jinja2 pyramid-mako pyramid pysqlite python-dateutil python-ldap python-memcached python-pam pytz pyzmq py-gfm recaptcha-client redis repoze.lru requests Routes setproctitle simplejson six SQLAlchemy sshpubkeys subprocess32 supervisor Tempita translationstring trollius urllib3 URLObject venusian WebError WebHelpers2 WebHelpers WebOb Whoosh wsgiref zope.cachedescriptors zope.deprecation zope.event zope.interface nbconvert bleach nbformat jupyter-client alembic invoke bumpversion transifex-client gevent greenlet gunicorn waitress uWSGI ipdb ipython CProfileV bottle rhodecode-tools appenlight-client pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage]; src = ./.; meta = { license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ]; }; }; rhodecode-tools = super.buildPythonPackage { - name = "rhodecode-tools-0.13.1"; + name = "rhodecode-tools-0.14.1"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh]; src = fetchurl { - url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.13.1.tar.gz?md5=f72add4690c9b341f87127a0a79573ae"; - md5 = "f72add4690c9b341f87127a0a79573ae"; + url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2"; + md5 = "0b9c2caad160b68889f8172ea54af7b2"; }; meta = { license = [ { fullName = "AGPLv3 and Proprietary"; } ]; }; }; scandir = super.buildPythonPackage { - name = "scandir-1.5"; + name = "scandir-1.6"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/bd/f4/3143e0289faf0883228017dbc6387a66d0b468df646645e29e1eb89ea10e/scandir-1.5.tar.gz"; - md5 = "a2713043de681bba6b084be42e7a8a44"; + url = "https://pypi.python.org/packages/77/3f/916f524f50ee65e3f465a280d2851bd63685250fddb3020c212b3977664d/scandir-1.6.tar.gz"; + md5 = "0180ddb97c96cbb2d4f25d2ae11c64ac"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ]; }; }; setproctitle = super.buildPythonPackage { - name = "setproctitle-1.1.8"; + name = "setproctitle-1.1.10"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/33/c3/ad367a4f4f1ca90468863ae727ac62f6edb558fc09a003d344a02cfc6ea6/setproctitle-1.1.8.tar.gz"; - md5 = "728f4c8c6031bbe56083a48594027edd"; + url = "https://pypi.python.org/packages/5a/0d/dc0d2234aacba6cf1a729964383e3452c52096dc695581248b548786f2b3/setproctitle-1.1.10.tar.gz"; + md5 = "2dcdd1b761700a5a13252fea3dfd1977"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; @@ -1781,13 +1742,13 @@ }; }; setuptools-scm = super.buildPythonPackage { - name = "setuptools-scm-1.15.0"; + name = "setuptools-scm-1.15.6"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/80/b7/31b6ae5fcb188e37f7e31abe75f9be90490a5456a72860fa6e643f8a3cbc/setuptools_scm-1.15.0.tar.gz"; - md5 = "b6916c78ed6253d6602444fad4279c5b"; + url = "https://pypi.python.org/packages/03/6d/aafdd01edd227ee879b691455bf19895091872af7e48192bea1758c82032/setuptools_scm-1.15.6.tar.gz"; + md5 = "f17493d53f0d842bb0152f214775640b"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -1820,13 +1781,13 @@ }; }; six = super.buildPythonPackage { - name = "six-1.9.0"; + name = "six-1.11.0"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/16/64/1dc5e5976b17466fd7d712e59cbe9fb1e18bec153109e5ba3ed6c9102f1a/six-1.9.0.tar.gz"; - md5 = "476881ef4012262dfc8adc645ee786c4"; + url = "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz"; + md5 = "d12789f9baf7e9fb2524c0c64f1773f8"; }; meta = { license = [ pkgs.lib.licenses.mit ]; @@ -1911,13 +1872,13 @@ }; }; transifex-client = super.buildPythonPackage { - name = "transifex-client-0.10"; + name = "transifex-client-0.12.5"; buildInputs = with self; []; doCheck = false; - propagatedBuildInputs = with self; []; + propagatedBuildInputs = with self; [urllib3 six]; src = fetchurl { - url = "https://pypi.python.org/packages/f3/4e/7b925192aee656fb3e04fa6381c8b3dc40198047c3b4a356f6cfd642c809/transifex-client-0.10.tar.gz"; - md5 = "5549538d84b8eede6b254cd81ae024fa"; + url = "https://pypi.python.org/packages/7b/86/60f31a0c9b8d0b1266ce15b6c80b55f88522140c8acfc395d5aec5e23475/transifex-client-0.12.5.tar.gz"; + md5 = "e6e278117b23f60702c06e203b7e51ae"; }; meta = { license = [ pkgs.lib.licenses.gpl2 ]; @@ -1988,14 +1949,27 @@ license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; }; }; - waitress = super.buildPythonPackage { - name = "waitress-1.0.2"; + vine = super.buildPythonPackage { + name = "vine-1.1.4"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/cd/f4/400d00863afa1e03618e31fd7e2092479a71b8c9718b00eb1eeb603746c6/waitress-1.0.2.tar.gz"; - md5 = "b968f39e95d609f6194c6e50425d4bb7"; + url = "https://pypi.python.org/packages/32/23/36284986e011f3c130d802c3c66abd8f1aef371eae110ddf80c5ae22e1ff/vine-1.1.4.tar.gz"; + md5 = "9fdb971e7fd15b181b84f3bfcf20d11c"; + }; + meta = { + license = [ pkgs.lib.licenses.bsdOriginal ]; + }; + }; + waitress = super.buildPythonPackage { + name = "waitress-1.1.0"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/3c/68/1c10dd5c556872ceebe88483b0436140048d39de83a84a06a8baa8136f4f/waitress-1.1.0.tar.gz"; + md5 = "0f1eb7fdfdbf2e6d18decbda1733045c"; }; meta = { license = [ pkgs.lib.licenses.zpt21 ]; @@ -2014,14 +1988,27 @@ license = [ pkgs.lib.licenses.mit ]; }; }; - ws4py = super.buildPythonPackage { - name = "ws4py-0.3.5"; + webencodings = super.buildPythonPackage { + name = "webencodings-0.5.1"; buildInputs = with self; []; doCheck = false; propagatedBuildInputs = with self; []; src = fetchurl { - url = "https://pypi.python.org/packages/b6/4f/34af703be86939629479e74d6e650e39f3bd73b3b09212c34e5125764cbc/ws4py-0.3.5.zip"; - md5 = "a261b75c20b980e55ce7451a3576a867"; + url = "https://pypi.python.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz"; + md5 = "32f6e261d52e57bf7e1c4d41546d15b8"; + }; + meta = { + license = [ pkgs.lib.licenses.bsdOriginal ]; + }; + }; + ws4py = super.buildPythonPackage { + name = "ws4py-0.4.2"; + buildInputs = with self; []; + doCheck = false; + propagatedBuildInputs = with self; []; + src = fetchurl { + url = "https://pypi.python.org/packages/b8/98/a90f1d96ffcb15dfc220af524ce23e0a5881258dafa197673357ce1683dd/ws4py-0.4.2.tar.gz"; + md5 = "f0603ae376707a58d205bd87a67758a2"; }; meta = { license = [ pkgs.lib.licenses.bsdOriginal ]; diff --git a/pytest.ini b/pytest.ini --- a/pytest.ini +++ b/pytest.ini @@ -1,12 +1,12 @@ [pytest] -testpaths = ./rhodecode -pylons_config = rhodecode/tests/rhodecode.ini +testpaths = rhodecode +norecursedirs = rhodecode/public rhodecode/templates tests/scripts + +pyramid_config = rhodecode/tests/rhodecode.ini vcsserver_protocol = http vcsserver_config_http = rhodecode/tests/vcsserver_http.ini -norecursedirs = tests/scripts addopts = - -k "not _BaseTest" --pdbcls=IPython.terminal.debugger:TerminalPdb markers = diff --git a/requirements.txt b/requirements.txt --- a/requirements.txt +++ b/requirements.txt @@ -1,51 +1,49 @@ ## core setuptools==30.1.0 -setuptools-scm==1.15.0 +setuptools-scm==1.15.6 -amqplib==1.0.2 -anyjson==0.3.3 +amqp==2.2.2 authomatic==0.1.0.post1 Babel==1.3 Beaker==1.9.0 -celery==2.2.10 +celery==4.1.0 Chameleon==2.24 channelstream==0.5.2 -click==5.1 -colander==1.3.3 +click==6.6 +colander==1.4.0 configobj==5.0.6 cssselect==1.0.1 -decorator==4.0.11 +decorator==4.1.2 deform==2.0.4 -docutils==0.13.1 +docutils==0.14.0 dogpile.cache==0.6.4 dogpile.core==0.4.1 ecdsa==0.13 FormEncode==1.2.4 future==0.14.3 futures==3.0.2 -gnureadline==6.3.3 +gnureadline==6.3.8 infrae.cache==1.0.1 -iso8601==0.1.11 +iso8601==0.1.12 itsdangerous==0.24 -Jinja2==2.7.3 -kombu==1.5.1 +Jinja2==2.9.6 +billiard==3.5.0.3 +kombu==4.1.0 lxml==3.7.3 Mako==1.0.7 -Markdown==2.6.8 -MarkupSafe==0.23 -meld3==1.0.2 +Markdown==2.6.9 +MarkupSafe==1.0.0 msgpack-python==0.4.8 MySQL-python==1.2.5 -nose==1.3.6 -objgraph==3.1.0 +objgraph==3.1.1 packaging==15.2 Paste==2.0.3 PasteDeploy==1.5.2 -PasteScript==1.7.5 +PasteScript==2.0.2 pathlib2==2.3.0 peppercorn==0.5 -psutil==4.3.1 -psycopg2==2.7.1 +psutil==5.4.0 +psycopg2==2.7.3.2 py-bcrypt==0.4 pycrypto==2.6.1 pycurl==7.19.5 @@ -54,27 +52,27 @@ pygments-markdown-lexer==0.1.0.dev39 Pygments==2.2.0 pyparsing==1.5.7 pyramid-beaker==0.8 -pyramid-debugtoolbar==4.2.1 -pyramid-jinja2==2.5 +pyramid-debugtoolbar==4.3.0 +pyramid-jinja2==2.7 pyramid-mako==1.0.2 pyramid==1.9.1 pysqlite==2.8.3 -python-dateutil==2.1 -python-ldap==2.4.40 +python-dateutil +python-ldap==2.4.45 python-memcached==1.58 python-pam==1.8.2 -pytz==2015.4 +pytz==2017.3 pyzmq==14.6.0 +py-gfm==0.1.3 recaptcha-client==1.0.6 redis==2.10.6 -repoze.lru==0.6 +repoze.lru==0.7 requests==2.9.1 -Routes==1.13 -setproctitle==1.1.8 +Routes==2.4.1 +setproctitle==1.1.10 simplejson==3.11.1 -six==1.9.0 -Sphinx==1.2.2 -SQLAlchemy==1.1.11 +six==1.11.0 +SQLAlchemy==1.1.15 sshpubkeys==2.2.0 subprocess32==3.2.7 supervisor==3.3.3 @@ -95,44 +93,39 @@ zope.deprecation==4.1.2 zope.event==4.0.3 zope.interface==4.1.3 -## customized/patched libs -# our patched version of Pylons==1.0.2 -https://code.rhodecode.com/upstream/pylons/archive/707354ee4261b9c10450404fc9852ccea4fd667d.tar.gz?md5=f26633726fa2cd3a340316ee6a5d218f#egg=Pylons==1.0.2.rhodecode-patch-1 -# not released py-gfm==0.1.3 -https://code.rhodecode.com/upstream/py-gfm/archive/0d66a19bc16e3d49de273c0f797d4e4781e8c0f2.tar.gz?md5=0d0d5385bfb629eea636a80b9c2bfd16#egg=py-gfm==0.1.3.rhodecode-upstream1 # 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 -nbconvert==5.1.1 -bleach==1.5.0 -nbformat==4.3.0 +nbconvert==5.3.1 +bleach==2.1.1 +nbformat==4.4.0 jupyter_client==5.0.0 ## cli tools -alembic==0.9.2 +alembic==0.9.6 invoke==0.13.0 bumpversion==0.5.3 -transifex-client==0.10 +transifex-client==0.12.5 ## http servers gevent==1.2.2 greenlet==0.4.12 gunicorn==19.7.1 -waitress==1.0.2 +waitress==1.1.0 uWSGI==2.0.15 ## debug ipdb==0.10.3 ipython==5.1.0 CProfileV==1.0.7 -bottle==0.12.8 +bottle==0.12.13 ## rhodecode-tools, special case -https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.13.1.tar.gz?md5=f72add4690c9b341f87127a0a79573ae#egg=rhodecode-tools==0.13.1 +https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.14.1.tar.gz?md5=0b9c2caad160b68889f8172ea54af7b2#egg=rhodecode-tools==0.14.1 ## appenlight -appenlight-client==0.6.21 +appenlight-client==0.6.22 ## test related requirements -r requirements_test.txt diff --git a/requirements_test.txt b/requirements_test.txt --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,15 +1,15 @@ # test related requirements -pytest==3.1.2 -py==1.4.34 +pytest==3.2.5 +py==1.5.2 pytest-cov==2.5.1 -pytest-sugar==0.8.0 -pytest-runner==2.11.1 +pytest-sugar==0.9.0 +pytest-runner==3.0.0 pytest-catchlog==1.2.2 -pytest-profiling==1.2.6 -gprof2dot==2016.10.13 +pytest-profiling==1.2.11 +gprof2dot==2017.9.19 pytest-timeout==1.2.0 mock==1.0.1 -WebTest==2.0.27 +WebTest==2.0.29 cov-core==1.15.0 coverage==3.7.1 diff --git a/rhodecode/VERSION b/rhodecode/VERSION --- a/rhodecode/VERSION +++ b/rhodecode/VERSION @@ -1,1 +1,1 @@ -4.10.6 \ No newline at end of file +4.11.0 \ No newline at end of file diff --git a/rhodecode/__init__.py b/rhodecode/__init__.py --- a/rhodecode/__init__.py +++ b/rhodecode/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -40,7 +40,7 @@ BACKENDS = { CELERY_ENABLED = False CELERY_EAGER = False -# link to config for pylons +# link to config for pyramid CONFIG = {} # Populated with the settings dictionary from application init in @@ -51,7 +51,7 @@ PYRAMID_SETTINGS = {} EXTENSIONS = {} __version__ = ('.'.join((str(each) for each in VERSION[:3]))) -__dbversion__ = 81 # defines current db version for migrations +__dbversion__ = 85 # defines current db version for migrations __platform__ = platform.system() __license__ = 'AGPLv3, and Commercial License' __author__ = 'RhodeCode GmbH' diff --git a/rhodecode/api/__init__.py b/rhodecode/api/__init__.py --- a/rhodecode/api/__init__.py +++ b/rhodecode/api/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/api/exc.py b/rhodecode/api/exc.py --- a/rhodecode/api/exc.py +++ b/rhodecode/api/exc.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/api/tests/__init__.py b/rhodecode/api/tests/__init__.py --- a/rhodecode/api/tests/__init__.py +++ b/rhodecode/api/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/conftest.py b/rhodecode/api/tests/conftest.py --- a/rhodecode/api/tests/conftest.py +++ b/rhodecode/api/tests/conftest.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -27,7 +27,7 @@ from rhodecode.tests import TEST_USER_AD @pytest.fixture(scope="class") -def testuser_api(request, pylonsapp): +def testuser_api(request, baseapp): cls = request.cls # ADMIN USER diff --git a/rhodecode/api/tests/test_add_field_to_repo.py b/rhodecode/api/tests/test_add_field_to_repo.py --- a/rhodecode/api/tests/test_add_field_to_repo.py +++ b/rhodecode/api/tests/test_add_field_to_repo.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_add_user_to_user_group.py b/rhodecode/api/tests/test_add_user_to_user_group.py --- a/rhodecode/api/tests/test_add_user_to_user_group.py +++ b/rhodecode/api/tests/test_add_user_to_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_api.py b/rhodecode/api/tests/test_api.py --- a/rhodecode/api/tests/test_api.py +++ b/rhodecode/api/tests/test_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -86,7 +86,7 @@ class TestApi(object): def test_api_non_existing_method_have_similar(self, request): id_, params = build_data(self.apikey, 'comment', args='xx') response = api_call(self.app, params) - expected = 'No such method: comment. Similar methods: changeset_comment, comment_pull_request, comment_commit' + expected = 'No such method: comment. Similar methods: changeset_comment, comment_pull_request, get_pull_request_comments, comment_commit' assert_error(id_, expected, given=response.body) def test_api_disabled_user(self, request): diff --git a/rhodecode/api/tests/test_cleanup_sessions.py b/rhodecode/api/tests/test_cleanup_sessions.py --- a/rhodecode/api/tests/test_cleanup_sessions.py +++ b/rhodecode/api/tests/test_cleanup_sessions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2017-2017 RhodeCode GmbH +# Copyright (C) 2017-2018 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 diff --git a/rhodecode/api/tests/test_close_pull_request.py b/rhodecode/api/tests/test_close_pull_request.py --- a/rhodecode/api/tests/test_close_pull_request.py +++ b/rhodecode/api/tests/test_close_pull_request.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -70,10 +70,11 @@ class TestClosePullRequest(object): assert_error(id_, expected, given=response.body) @pytest.mark.backends("git", "hg") - def test_api_close_pull_request_repo_error(self): + def test_api_close_pull_request_repo_error(self, pr_util): + pull_request = pr_util.create_pull_request() id_, params = build_data( self.apikey, 'close_pull_request', - repoid=666, pullrequestid=1) + repoid=666, pullrequestid=pull_request.pull_request_id) response = api_call(self.app, params) expected = 'repository `666` does not exist' diff --git a/rhodecode/api/tests/test_comment_commit.py b/rhodecode/api/tests/test_comment_commit.py --- a/rhodecode/api/tests/test_comment_commit.py +++ b/rhodecode/api/tests/test_comment_commit.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_comment_pull_request.py b/rhodecode/api/tests/test_comment_pull_request.py --- a/rhodecode/api/tests/test_comment_pull_request.py +++ b/rhodecode/api/tests/test_comment_pull_request.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -170,10 +170,11 @@ class TestCommentPullRequest(object): assert_error(id_, expected, given=response.body) @pytest.mark.backends("git", "hg") - def test_api_comment_pull_request_repo_error(self): + def test_api_comment_pull_request_repo_error(self, pr_util): + pull_request = pr_util.create_pull_request() id_, params = build_data( self.apikey, 'comment_pull_request', - repoid=666, pullrequestid=1) + repoid=666, pullrequestid=pull_request.pull_request_id) response = api_call(self.app, params) expected = 'repository `666` does not exist' diff --git a/rhodecode/api/tests/test_create_gist.py b/rhodecode/api/tests/test_create_gist.py --- a/rhodecode/api/tests/test_create_gist.py +++ b/rhodecode/api/tests/test_create_gist.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_create_pull_request.py b/rhodecode/api/tests/test_create_pull_request.py --- a/rhodecode/api/tests/test_create_pull_request.py +++ b/rhodecode/api/tests/test_create_pull_request.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_create_repo.py b/rhodecode/api/tests/test_create_repo.py --- a/rhodecode/api/tests/test_create_repo.py +++ b/rhodecode/api/tests/test_create_repo.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_create_repo_group.py b/rhodecode/api/tests/test_create_repo_group.py --- a/rhodecode/api/tests/test_create_repo_group.py +++ b/rhodecode/api/tests/test_create_repo_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_create_user.py b/rhodecode/api/tests/test_create_user.py --- a/rhodecode/api/tests/test_create_user.py +++ b/rhodecode/api/tests/test_create_user.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_create_user_group.py b/rhodecode/api/tests/test_create_user_group.py --- a/rhodecode/api/tests/test_create_user_group.py +++ b/rhodecode/api/tests/test_create_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_delete_gist.py b/rhodecode/api/tests/test_delete_gist.py --- a/rhodecode/api/tests/test_delete_gist.py +++ b/rhodecode/api/tests/test_delete_gist.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_delete_repo.py b/rhodecode/api/tests/test_delete_repo.py --- a/rhodecode/api/tests/test_delete_repo.py +++ b/rhodecode/api/tests/test_delete_repo.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_delete_repo_group.py b/rhodecode/api/tests/test_delete_repo_group.py --- a/rhodecode/api/tests/test_delete_repo_group.py +++ b/rhodecode/api/tests/test_delete_repo_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_delete_user.py b/rhodecode/api/tests/test_delete_user.py --- a/rhodecode/api/tests/test_delete_user.py +++ b/rhodecode/api/tests/test_delete_user.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_delete_user_group.py b/rhodecode/api/tests/test_delete_user_group.py --- a/rhodecode/api/tests/test_delete_user_group.py +++ b/rhodecode/api/tests/test_delete_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_deprecated_api.py b/rhodecode/api/tests/test_deprecated_api.py --- a/rhodecode/api/tests/test_deprecated_api.py +++ b/rhodecode/api/tests/test_deprecated_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_fork_repo.py b/rhodecode/api/tests/test_fork_repo.py --- a/rhodecode/api/tests/test_fork_repo.py +++ b/rhodecode/api/tests/test_fork_repo.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_gist.py b/rhodecode/api/tests/test_get_gist.py --- a/rhodecode/api/tests/test_get_gist.py +++ b/rhodecode/api/tests/test_get_gist.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_gists.py b/rhodecode/api/tests/test_get_gists.py --- a/rhodecode/api/tests/test_get_gists.py +++ b/rhodecode/api/tests/test_get_gists.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_ip.py b/rhodecode/api/tests/test_get_ip.py --- a/rhodecode/api/tests/test_get_ip.py +++ b/rhodecode/api/tests/test_get_ip.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_locks.py b/rhodecode/api/tests/test_get_locks.py --- a/rhodecode/api/tests/test_get_locks.py +++ b/rhodecode/api/tests/test_get_locks.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_method.py b/rhodecode/api/tests/test_get_method.py --- a/rhodecode/api/tests/test_get_method.py +++ b/rhodecode/api/tests/test_get_method.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -38,11 +38,12 @@ class TestGetMethod(object): response = api_call(self.app, params) expected = ['changeset_comment', 'comment_pull_request', - 'comment_commit'] + 'get_pull_request_comments', 'comment_commit'] assert_ok(id_, expected, given=response.body) def test_get_methods_on_single_match(self): - id_, params = build_data(self.apikey, 'get_method', pattern='*comment_commit*') + id_, params = build_data(self.apikey, 'get_method', + pattern='*comment_commit*') response = api_call(self.app, params) expected = ['comment_commit', diff --git a/rhodecode/api/tests/test_get_pull_request.py b/rhodecode/api/tests/test_get_pull_request.py --- a/rhodecode/api/tests/test_get_pull_request.py +++ b/rhodecode/api/tests/test_get_pull_request.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -38,7 +38,6 @@ class TestGetPullRequest(object): pull_request = pr_util.create_pull_request(mergeable=True) id_, params = build_data( self.apikey, 'get_pull_request', - repoid=pull_request.target_repo.repo_name, pullrequestid=pull_request.pull_request_id) response = api_call(self.app, params) @@ -109,16 +108,17 @@ class TestGetPullRequest(object): 'reasons': reasons, 'review_status': st[0][1].status if st else 'not_reviewed', } - for reviewer, reasons, mandatory, st in + for obj, reviewer, reasons, mandatory, st in pull_request.reviewers_statuses() ] } assert_ok(id_, expected, response.body) - def test_api_get_pull_request_repo_error(self): + def test_api_get_pull_request_repo_error(self, pr_util): + pull_request = pr_util.create_pull_request() id_, params = build_data( self.apikey, 'get_pull_request', - repoid=666, pullrequestid=1) + repoid=666, pullrequestid=pull_request.pull_request_id) response = api_call(self.app, params) expected = 'repository `666` does not exist' @@ -126,9 +126,17 @@ class TestGetPullRequest(object): def test_api_get_pull_request_pull_request_error(self): id_, params = build_data( - self.apikey, 'get_pull_request', - repoid=1, pullrequestid=666) + self.apikey, 'get_pull_request', pullrequestid=666) response = api_call(self.app, params) expected = 'pull request `666` does not exist' assert_error(id_, expected, given=response.body) + + def test_api_get_pull_request_pull_request_error_just_pr_id(self): + id_, params = build_data( + self.apikey, 'get_pull_request', + pullrequestid=666) + response = api_call(self.app, params) + + expected = 'pull request `666` does not exist' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_pull_request_comments.py b/rhodecode/api/tests/test_get_pull_request_comments.py new file mode 100644 --- /dev/null +++ b/rhodecode/api/tests/test_get_pull_request_comments.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2018 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 . +# +# 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 +import urlobject + +from rhodecode.api.tests.utils import ( + build_data, api_call, assert_error, assert_ok) +from rhodecode.lib import helpers as h +from rhodecode.lib.utils2 import safe_unicode + +pytestmark = pytest.mark.backends("git", "hg") + + +@pytest.mark.usefixtures("testuser_api", "app") +class TestGetPullRequestComments(object): + + def test_api_get_pull_request_comments(self, pr_util, http_host_only_stub): + from rhodecode.model.pull_request import PullRequestModel + + pull_request = pr_util.create_pull_request(mergeable=True) + id_, params = build_data( + self.apikey, 'get_pull_request_comments', + pullrequestid=pull_request.pull_request_id) + + response = api_call(self.app, params) + + assert response.status == '200 OK' + resp_date = response.json['result'][0]['comment_created_on'] + resp_comment_id = response.json['result'][0]['comment_id'] + + expected = [ + {'comment_author': {'active': True, + 'full_name_or_username': 'RhodeCode Admin', + 'username': 'test_admin'}, + 'comment_created_on': resp_date, + 'comment_f_path': None, + 'comment_id': resp_comment_id, + 'comment_lineno': None, + 'comment_status': {'status': 'under_review', + 'status_lbl': 'Under Review'}, + 'comment_text': 'Auto status change to |new_status|\n\n.. |new_status| replace:: *"Under Review"*', + 'comment_type': 'note', + 'pull_request_version': None} + ] + assert_ok(id_, expected, response.body) + + def test_api_get_pull_request_comments_repo_error(self, pr_util): + pull_request = pr_util.create_pull_request() + id_, params = build_data( + self.apikey, 'get_pull_request_comments', + repoid=666, pullrequestid=pull_request.pull_request_id) + response = api_call(self.app, params) + + expected = 'repository `666` does not exist' + assert_error(id_, expected, given=response.body) + + def test_api_get_pull_request_comments_pull_request_error(self): + id_, params = build_data( + self.apikey, 'get_pull_request_comments', pullrequestid=666) + response = api_call(self.app, params) + + expected = 'pull request `666` does not exist' + assert_error(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_pull_requests.py b/rhodecode/api/tests/test_get_pull_requests.py --- a/rhodecode/api/tests/test_get_pull_requests.py +++ b/rhodecode/api/tests/test_get_pull_requests.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_repo.py b/rhodecode/api/tests/test_get_repo.py --- a/rhodecode/api/tests/test_get_repo.py +++ b/rhodecode/api/tests/test_get_repo.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -68,7 +68,6 @@ class TestGetRepo(object): followers.append(user.user.get_api_data( include_secrets=expect_secrets)) - ret['members'] = permissions ret['permissions'] = permissions ret['followers'] = followers @@ -106,7 +105,6 @@ class TestGetRepo(object): for user in repo.followers: followers.append(user.user.get_api_data()) - ret['members'] = permissions ret['permissions'] = permissions ret['followers'] = followers diff --git a/rhodecode/api/tests/test_get_repo_changeset.py b/rhodecode/api/tests/test_get_repo_changeset.py --- a/rhodecode/api/tests/test_get_repo_changeset.py +++ b/rhodecode/api/tests/test_get_repo_changeset.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_repo_group.py b/rhodecode/api/tests/test_get_repo_group.py --- a/rhodecode/api/tests/test_get_repo_group.py +++ b/rhodecode/api/tests/test_get_repo_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -41,7 +41,7 @@ class TestApiGetRepoGroup(object): permissions = expected_permissions(repo_group) - ret['members'] = permissions + ret['permissions'] = permissions expected = ret assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_repo_groups.py b/rhodecode/api/tests/test_get_repo_groups.py --- a/rhodecode/api/tests/test_get_repo_groups.py +++ b/rhodecode/api/tests/test_get_repo_groups.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_repo_nodes.py b/rhodecode/api/tests/test_get_repo_nodes.py --- a/rhodecode/api/tests/test_get_repo_nodes.py +++ b/rhodecode/api/tests/test_get_repo_nodes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_repo_refs.py b/rhodecode/api/tests/test_get_repo_refs.py --- a/rhodecode/api/tests/test_get_repo_refs.py +++ b/rhodecode/api/tests/test_get_repo_refs.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_repos.py b/rhodecode/api/tests/test_get_repos.py --- a/rhodecode/api/tests/test_get_repos.py +++ b/rhodecode/api/tests/test_get_repos.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_server_info.py b/rhodecode/api/tests/test_get_server_info.py --- a/rhodecode/api/tests/test_get_server_info.py +++ b/rhodecode/api/tests/test_get_server_info.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_user.py b/rhodecode/api/tests/test_get_user.py --- a/rhodecode/api/tests/test_get_user.py +++ b/rhodecode/api/tests/test_get_user.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -36,7 +36,9 @@ class TestGetUser(object): usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) ret = usr.get_api_data(include_secrets=True) - ret['permissions'] = AuthUser(usr.user_id).permissions + permissions = AuthUser(usr.user_id).permissions + ret['permissions'] = permissions + ret['permissions_summary'] = permissions expected = ret assert_ok(id_, expected, given=response.body) @@ -54,7 +56,9 @@ class TestGetUser(object): usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) ret = usr.get_api_data(include_secrets=True) - ret['permissions'] = AuthUser(usr.user_id).permissions + permissions = AuthUser(usr.user_id).permissions + ret['permissions'] = permissions + ret['permissions_summary'] = permissions expected = ret assert_ok(id_, expected, given=response.body) @@ -65,7 +69,9 @@ class TestGetUser(object): usr = UserModel().get_by_username(self.TEST_USER_LOGIN) ret = usr.get_api_data(include_secrets=True) - ret['permissions'] = AuthUser(usr.user_id).permissions + permissions = AuthUser(usr.user_id).permissions + ret['permissions'] = permissions + ret['permissions_summary'] = permissions expected = ret assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_user_group.py b/rhodecode/api/tests/test_get_user_group.py --- a/rhodecode/api/tests/test_get_user_group.py +++ b/rhodecode/api/tests/test_get_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -38,7 +38,8 @@ class TestGetUserGroups(object): permissions = expected_permissions(group) - ret['members'] = permissions + ret['permissions'] = permissions + ret['permissions_summary'] = response.json['result']['permissions_summary'] expected = ret assert_ok(id_, expected, given=response.body) @@ -54,7 +55,8 @@ class TestGetUserGroups(object): permissions = expected_permissions(group) - ret['members'] = permissions + ret['permissions'] = permissions + ret['permissions_summary'] = response.json['result']['permissions_summary'] expected = ret assert_ok(id_, expected, given=response.body) diff --git a/rhodecode/api/tests/test_get_user_groups.py b/rhodecode/api/tests/test_get_user_groups.py --- a/rhodecode/api/tests/test_get_user_groups.py +++ b/rhodecode/api/tests/test_get_user_groups.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_get_users.py b/rhodecode/api/tests/test_get_users.py --- a/rhodecode/api/tests/test_get_users.py +++ b/rhodecode/api/tests/test_get_users.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_grant_user_group_permission.py b/rhodecode/api/tests/test_grant_user_group_permission.py --- a/rhodecode/api/tests/test_grant_user_group_permission.py +++ b/rhodecode/api/tests/test_grant_user_group_permission.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_grant_user_group_permission_to_repo_group.py b/rhodecode/api/tests/test_grant_user_group_permission_to_repo_group.py --- a/rhodecode/api/tests/test_grant_user_group_permission_to_repo_group.py +++ b/rhodecode/api/tests/test_grant_user_group_permission_to_repo_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_grant_user_group_permission_to_user_group.py b/rhodecode/api/tests/test_grant_user_group_permission_to_user_group.py --- a/rhodecode/api/tests/test_grant_user_group_permission_to_user_group.py +++ b/rhodecode/api/tests/test_grant_user_group_permission_to_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_grant_user_permission.py b/rhodecode/api/tests/test_grant_user_permission.py --- a/rhodecode/api/tests/test_grant_user_permission.py +++ b/rhodecode/api/tests/test_grant_user_permission.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_grant_user_permission_to_repo_group.py b/rhodecode/api/tests/test_grant_user_permission_to_repo_group.py --- a/rhodecode/api/tests/test_grant_user_permission_to_repo_group.py +++ b/rhodecode/api/tests/test_grant_user_permission_to_repo_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_grant_user_permission_to_user_group.py b/rhodecode/api/tests/test_grant_user_permission_to_user_group.py --- a/rhodecode/api/tests/test_grant_user_permission_to_user_group.py +++ b/rhodecode/api/tests/test_grant_user_permission_to_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_invalidate_cache.py b/rhodecode/api/tests/test_invalidate_cache.py --- a/rhodecode/api/tests/test_invalidate_cache.py +++ b/rhodecode/api/tests/test_invalidate_cache.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_merge_pull_request.py b/rhodecode/api/tests/test_merge_pull_request.py --- a/rhodecode/api/tests/test_merge_pull_request.py +++ b/rhodecode/api/tests/test_merge_pull_request.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -112,10 +112,11 @@ class TestMergePullRequest(object): assert_error(id_, expected, given=response.body) @pytest.mark.backends("git", "hg") - def test_api_merge_pull_request_repo_error(self): + def test_api_merge_pull_request_repo_error(self, pr_util): + pull_request = pr_util.create_pull_request() id_, params = build_data( self.apikey, 'merge_pull_request', - repoid=666, pullrequestid=1) + repoid=666, pullrequestid=pull_request.pull_request_id) response = api_call(self.app, params) expected = 'repository `666` does not exist' diff --git a/rhodecode/api/tests/test_pull.py b/rhodecode/api/tests/test_pull.py --- a/rhodecode/api/tests/test_pull.py +++ b/rhodecode/api/tests/test_pull.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_remove_field_from_repo.py b/rhodecode/api/tests/test_remove_field_from_repo.py --- a/rhodecode/api/tests/test_remove_field_from_repo.py +++ b/rhodecode/api/tests/test_remove_field_from_repo.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_remove_user_from_user_group.py b/rhodecode/api/tests/test_remove_user_from_user_group.py --- a/rhodecode/api/tests/test_remove_user_from_user_group.py +++ b/rhodecode/api/tests/test_remove_user_from_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_repo_locking.py b/rhodecode/api/tests/test_repo_locking.py --- a/rhodecode/api/tests/test_repo_locking.py +++ b/rhodecode/api/tests/test_repo_locking.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_rescan_repos.py b/rhodecode/api/tests/test_rescan_repos.py --- a/rhodecode/api/tests/test_rescan_repos.py +++ b/rhodecode/api/tests/test_rescan_repos.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_revoke_user_group_permission.py b/rhodecode/api/tests/test_revoke_user_group_permission.py --- a/rhodecode/api/tests/test_revoke_user_group_permission.py +++ b/rhodecode/api/tests/test_revoke_user_group_permission.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_revoke_user_group_permission_from_repo_group.py b/rhodecode/api/tests/test_revoke_user_group_permission_from_repo_group.py --- a/rhodecode/api/tests/test_revoke_user_group_permission_from_repo_group.py +++ b/rhodecode/api/tests/test_revoke_user_group_permission_from_repo_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_revoke_user_group_permission_from_user_group.py b/rhodecode/api/tests/test_revoke_user_group_permission_from_user_group.py --- a/rhodecode/api/tests/test_revoke_user_group_permission_from_user_group.py +++ b/rhodecode/api/tests/test_revoke_user_group_permission_from_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_revoke_user_permission.py b/rhodecode/api/tests/test_revoke_user_permission.py --- a/rhodecode/api/tests/test_revoke_user_permission.py +++ b/rhodecode/api/tests/test_revoke_user_permission.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_revoke_user_permission_from_repo_group.py b/rhodecode/api/tests/test_revoke_user_permission_from_repo_group.py --- a/rhodecode/api/tests/test_revoke_user_permission_from_repo_group.py +++ b/rhodecode/api/tests/test_revoke_user_permission_from_repo_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_revoke_user_permission_from_user_group.py b/rhodecode/api/tests/test_revoke_user_permission_from_user_group.py --- a/rhodecode/api/tests/test_revoke_user_permission_from_user_group.py +++ b/rhodecode/api/tests/test_revoke_user_permission_from_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_update_pull_request.py b/rhodecode/api/tests/test_update_pull_request.py --- a/rhodecode/api/tests/test_update_pull_request.py +++ b/rhodecode/api/tests/test_update_pull_request.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -133,7 +133,7 @@ class TestUpdatePullRequest(object): removed = [a.username] pull_request = pr_util.create_pull_request( - reviewers=[(a.username, ['added via API'], False)]) + reviewers=[(a.username, ['added via API'], False, [])]) id_, params = build_data( self.apikey, 'update_pull_request', @@ -168,10 +168,11 @@ class TestUpdatePullRequest(object): @pytest.mark.backends("git", "hg") def test_api_update_repo_error(self, pr_util): + pull_request = pr_util.create_pull_request() id_, params = build_data( self.apikey, 'update_pull_request', repoid='fake', - pullrequestid='fake', + pullrequestid=pull_request.pull_request_id, reviewers=[{'username': 'bad_name'}]) response = api_call(self.app, params) diff --git a/rhodecode/api/tests/test_update_repo.py b/rhodecode/api/tests/test_update_repo.py --- a/rhodecode/api/tests/test_update_repo.py +++ b/rhodecode/api/tests/test_update_repo.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_update_repo_group.py b/rhodecode/api/tests/test_update_repo_group.py --- a/rhodecode/api/tests/test_update_repo_group.py +++ b/rhodecode/api/tests/test_update_repo_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_update_user.py b/rhodecode/api/tests/test_update_user.py --- a/rhodecode/api/tests/test_update_user.py +++ b/rhodecode/api/tests/test_update_user.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_update_user_group.py b/rhodecode/api/tests/test_update_user_group.py --- a/rhodecode/api/tests/test_update_user_group.py +++ b/rhodecode/api/tests/test_update_user_group.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/test_utils.py b/rhodecode/api/tests/test_utils.py --- a/rhodecode/api/tests/test_utils.py +++ b/rhodecode/api/tests/test_utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/tests/utils.py b/rhodecode/api/tests/utils.py --- a/rhodecode/api/tests/utils.py +++ b/rhodecode/api/tests/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/api/utils.py b/rhodecode/api/utils.py --- a/rhodecode/api/utils.py +++ b/rhodecode/api/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2014-2017 RhodeCode GmbH +# Copyright (C) 2014-2018 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 diff --git a/rhodecode/api/views/__init__.py b/rhodecode/api/views/__init__.py --- a/rhodecode/api/views/__init__.py +++ b/rhodecode/api/views/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2015-2017 RhodeCode GmbH +# Copyright (C) 2015-2018 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 diff --git a/rhodecode/api/views/deprecated_api.py b/rhodecode/api/views/deprecated_api.py --- a/rhodecode/api/views/deprecated_api.py +++ b/rhodecode/api/views/deprecated_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/api/views/gist_api.py b/rhodecode/api/views/gist_api.py --- a/rhodecode/api/views/gist_api.py +++ b/rhodecode/api/views/gist_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/api/views/pull_request_api.py b/rhodecode/api/views/pull_request_api.py --- a/rhodecode/api/views/pull_request_api.py +++ b/rhodecode/api/views/pull_request_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -43,14 +43,14 @@ log = logging.getLogger(__name__) @jsonrpc_method() -def get_pull_request(request, apiuser, repoid, pullrequestid): +def get_pull_request(request, apiuser, pullrequestid, repoid=Optional(None)): """ Get a pull request based on the given ID. :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: Repository name or repository ID from where the pull - request was opened. + :param repoid: Optional, repository name or repository ID from where + the pull request was opened. :type repoid: str or int :param pullrequestid: ID of the requested pull request. :type pullrequestid: int @@ -121,11 +121,17 @@ def get_pull_request(request, apiuser, r }, "error": null """ - get_repo_or_error(repoid) + pull_request = get_pull_request_or_error(pullrequestid) + if Optional.extract(repoid): + repo = get_repo_or_error(repoid) + else: + repo = pull_request.target_repo + if not PullRequestModel().check_user_read( pull_request, apiuser, api=True): - raise JSONRPCError('repository `%s` does not exist' % (repoid,)) + raise JSONRPCError('repository `%s` or pull request `%s` ' + 'does not exist' % (repoid, pullrequestid)) data = pull_request.get_api_data() return data @@ -137,7 +143,7 @@ def get_pull_requests(request, apiuser, :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: Repository name or repository ID. + :param repoid: Optional repository name or repository ID. :type repoid: str or int :param status: Only return pull requests with the specified status. Valid options are. @@ -229,7 +235,7 @@ def get_pull_requests(request, apiuser, @jsonrpc_method() def merge_pull_request( - request, apiuser, repoid, pullrequestid, + request, apiuser, pullrequestid, repoid=Optional(None), userid=Optional(OAttr('apiuser'))): """ Merge the pull request specified by `pullrequestid` into its target @@ -237,7 +243,7 @@ def merge_pull_request( :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: The Repository name or repository ID of the + :param repoid: Optional, repository name or repository ID of the target repository to which the |pr| is to be merged. :type repoid: str or int :param pullrequestid: ID of the pull request which shall be merged. @@ -263,7 +269,12 @@ def merge_pull_request( }, "error": null """ - repo = get_repo_or_error(repoid) + pull_request = get_pull_request_or_error(pullrequestid) + if Optional.extract(repoid): + repo = get_repo_or_error(repoid) + else: + repo = pull_request.target_repo + if not isinstance(userid, Optional): if (has_superadmin_permission(apiuser) or HasRepoPermissionAnyApi('repository.admin')( @@ -272,8 +283,6 @@ def merge_pull_request( else: raise JSONRPCError('userid is not the same as your user') - pull_request = get_pull_request_or_error(pullrequestid) - check = MergeCheck.validate( pull_request, user=apiuser, translator=request.translate) merge_possible = not check.failed @@ -311,9 +320,112 @@ def merge_pull_request( @jsonrpc_method() +def get_pull_request_comments( + request, apiuser, pullrequestid, repoid=Optional(None)): + """ + Get all comments of pull request specified with the `pullrequestid` + + :param apiuser: This is filled automatically from the |authtoken|. + :type apiuser: AuthUser + :param repoid: Optional repository name or repository ID. + :type repoid: str or int + :param pullrequestid: The pull request ID. + :type pullrequestid: int + + Example output: + + .. code-block:: bash + + id : + result : [ + { + "comment_author": { + "active": true, + "full_name_or_username": "Tom Gore", + "username": "admin" + }, + "comment_created_on": "2017-01-02T18:43:45.533", + "comment_f_path": null, + "comment_id": 25, + "comment_lineno": null, + "comment_status": { + "status": "under_review", + "status_lbl": "Under Review" + }, + "comment_text": "Example text", + "comment_type": null, + "pull_request_version": null + } + ], + error : null + """ + + pull_request = get_pull_request_or_error(pullrequestid) + if Optional.extract(repoid): + repo = get_repo_or_error(repoid) + else: + repo = pull_request.target_repo + + if not PullRequestModel().check_user_read( + pull_request, apiuser, api=True): + raise JSONRPCError('repository `%s` or pull request `%s` ' + 'does not exist' % (repoid, pullrequestid)) + + (pull_request_latest, + pull_request_at_ver, + pull_request_display_obj, + at_version) = PullRequestModel().get_pr_version( + pull_request.pull_request_id, version=None) + + versions = pull_request_display_obj.versions() + ver_map = { + ver.pull_request_version_id: cnt + for cnt, ver in enumerate(versions, 1) + } + + # GENERAL COMMENTS with versions # + q = CommentsModel()._all_general_comments_of_pull_request(pull_request) + q = q.order_by(ChangesetComment.comment_id.asc()) + general_comments = q.all() + + # INLINE COMMENTS with versions # + q = CommentsModel()._all_inline_comments_of_pull_request(pull_request) + q = q.order_by(ChangesetComment.comment_id.asc()) + inline_comments = q.all() + + data = [] + for comment in inline_comments + general_comments: + full_data = comment.get_api_data() + pr_version_id = None + if comment.pull_request_version_id: + pr_version_id = 'v{}'.format( + ver_map[comment.pull_request_version_id]) + + # sanitize some entries + + full_data['pull_request_version'] = pr_version_id + full_data['comment_author'] = { + 'username': full_data['comment_author'].username, + 'full_name_or_username': full_data['comment_author'].full_name_or_username, + 'active': full_data['comment_author'].active, + } + + if full_data['comment_status']: + full_data['comment_status'] = { + 'status': full_data['comment_status'][0].status, + 'status_lbl': full_data['comment_status'][0].status_lbl, + } + else: + full_data['comment_status'] = {} + + data.append(full_data) + return data + + +@jsonrpc_method() def comment_pull_request( - request, apiuser, repoid, pullrequestid, message=Optional(None), - commit_id=Optional(None), status=Optional(None), + request, apiuser, pullrequestid, repoid=Optional(None), + message=Optional(None), commit_id=Optional(None), status=Optional(None), comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE), resolves_comment_id=Optional(None), userid=Optional(OAttr('apiuser'))): @@ -324,7 +436,7 @@ def comment_pull_request( :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: The repository name or repository ID. + :param repoid: Optional repository name or repository ID. :type repoid: str or int :param pullrequestid: The pull request ID. :type pullrequestid: int @@ -356,7 +468,12 @@ def comment_pull_request( }, error : null """ - repo = get_repo_or_error(repoid) + pull_request = get_pull_request_or_error(pullrequestid) + if Optional.extract(repoid): + repo = get_repo_or_error(repoid) + else: + repo = pull_request.target_repo + if not isinstance(userid, Optional): if (has_superadmin_permission(apiuser) or HasRepoPermissionAnyApi('repository.admin')( @@ -365,7 +482,6 @@ def comment_pull_request( else: raise JSONRPCError('userid is not the same as your user') - pull_request = get_pull_request_or_error(pullrequestid) if not PullRequestModel().check_user_read( pull_request, apiuser, api=True): raise JSONRPCError('repository `%s` does not exist' % (repoid,)) @@ -573,15 +689,15 @@ def create_pull_request( @jsonrpc_method() def update_pull_request( - request, apiuser, repoid, pullrequestid, title=Optional(''), - description=Optional(''), reviewers=Optional(None), + request, apiuser, pullrequestid, repoid=Optional(None), + title=Optional(''), description=Optional(''), reviewers=Optional(None), update_commits=Optional(None)): """ Updates a pull request. :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser - :param repoid: The repository name or repository ID. + :param repoid: Optional repository name or repository ID. :type repoid: str or int :param pullrequestid: The pull request ID. :type pullrequestid: int @@ -626,8 +742,12 @@ def update_pull_request( error : null """ - repo = get_repo_or_error(repoid) pull_request = get_pull_request_or_error(pullrequestid) + if Optional.extract(repoid): + repo = get_repo_or_error(repoid) + else: + repo = pull_request.target_repo + if not PullRequestModel().check_user_update( pull_request, apiuser, api=True): raise JSONRPCError( @@ -705,7 +825,7 @@ def update_pull_request( @jsonrpc_method() def close_pull_request( - request, apiuser, repoid, pullrequestid, + request, apiuser, pullrequestid, repoid=Optional(None), userid=Optional(OAttr('apiuser')), message=Optional('')): """ Close the pull request specified by `pullrequestid`. @@ -738,7 +858,12 @@ def close_pull_request( """ _ = request.translate - repo = get_repo_or_error(repoid) + pull_request = get_pull_request_or_error(pullrequestid) + if Optional.extract(repoid): + repo = get_repo_or_error(repoid) + else: + repo = pull_request.target_repo + if not isinstance(userid, Optional): if (has_superadmin_permission(apiuser) or HasRepoPermissionAnyApi('repository.admin')( @@ -747,8 +872,6 @@ def close_pull_request( else: raise JSONRPCError('userid is not the same as your user') - pull_request = get_pull_request_or_error(pullrequestid) - if pull_request.is_closed(): raise JSONRPCError( 'pull request `%s` is already closed' % (pullrequestid,)) diff --git a/rhodecode/api/views/repo_api.py b/rhodecode/api/views/repo_api.py --- a/rhodecode/api/views/repo_api.py +++ b/rhodecode/api/views/repo_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -32,6 +32,7 @@ from rhodecode.api.utils import ( from rhodecode.lib import audit_logger from rhodecode.lib import repo_maintenance from rhodecode.lib.auth import HasPermissionAnyApi, HasUserGroupPermissionAnyApi +from rhodecode.lib.celerylib.utils import get_task_id from rhodecode.lib.utils2 import str2bool, time_to_datetime from rhodecode.lib.ext_json import json from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError @@ -126,26 +127,6 @@ def get_repo(request, apiuser, repoid, c "lock_reason": null, "locked_by": null, "locked_date": null, - "members": [ - { - "name": "super-admin-name", - "origin": "super-admin", - "permission": "repository.admin", - "type": "user" - }, - { - "name": "owner-name", - "origin": "owner", - "permission": "repository.admin", - "type": "user" - }, - { - "name": "user-group-name", - "origin": "permission", - "permission": "repository.write", - "type": "user_group" - } - ], "owner": "owner-name", "permissions": [ { @@ -213,7 +194,6 @@ def get_repo(request, apiuser, repoid, c if not cache: repo.update_commit_cache() data = repo.get_api_data(include_secrets=include_secrets) - data['members'] = permissions # TODO: this should be deprecated soon data['permissions'] = permissions data['followers'] = following_users return data @@ -340,11 +320,7 @@ def get_repo_changeset(request, apiuser, _cs_json = cs.__json__() _cs_json['diff'] = build_commit_data(cs, changes_details) if changes_details == 'full': - _cs_json['refs'] = { - 'branches': [cs.branch], - 'bookmarks': getattr(cs, 'bookmarks', []), - 'tags': cs.tags - } + _cs_json['refs'] = cs._get_refs() return _cs_json @@ -716,10 +692,7 @@ def create_repo( } task = RepoModel().create(form_data=data, cur_user=owner) - from celery.result import BaseAsyncResult - task_id = None - if isinstance(task, BaseAsyncResult): - task_id = task.task_id + task_id = get_task_id(task) # no commit, it's done in RepoModel, or async via celery return { 'msg': "Created new repository `%s`" % (schema_data['repo_name'],), @@ -915,7 +888,8 @@ def update_repo( repo_enable_downloads=enable_downloads if not isinstance(enable_downloads, Optional) else repo.enable_downloads) - ref_choices, _labels = ScmModel().get_repo_landing_revs(repo=repo) + ref_choices, _labels = ScmModel().get_repo_landing_revs( + request.translate, repo=repo) old_values = repo.get_api_data() schema = repo_schema.RepoSchema().bind( @@ -1108,10 +1082,8 @@ def fork_repo(request, apiuser, repoid, task = RepoModel().create_fork(data, cur_user=owner) # no commit, it's done in RepoModel, or async via celery - from celery.result import BaseAsyncResult - task_id = None - if isinstance(task, BaseAsyncResult): - task_id = task.task_id + task_id = get_task_id(task) + return { 'msg': 'Created fork of `%s` as `%s`' % ( repo.repo_name, schema_data['repo_name']), diff --git a/rhodecode/api/views/repo_group_api.py b/rhodecode/api/views/repo_group_api.py --- a/rhodecode/api/views/repo_group_api.py +++ b/rhodecode/api/views/repo_group_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -63,7 +63,7 @@ def get_repo_group(request, apiuser, rep "group_description": "repo group description", "group_id": 14, "group_name": "group name", - "members": [ + "permissions": [ { "name": "super-admin-username", "origin": "super-admin", @@ -119,7 +119,7 @@ def get_repo_group(request, apiuser, rep permissions.append(user_group_data) data = repo_group.get_api_data() - data["members"] = permissions # TODO: this should be named permissions + data["permissions"] = permissions return data @@ -221,7 +221,7 @@ def create_repo_group( repo_group = RepoGroupModel().create( owner=owner, group_name=validated_group_name, - group_description=schema_data['repo_group_name'], + group_description=schema_data['repo_group_description'], copy_permissions=schema_data['repo_group_copy_permissions']) Session().flush() diff --git a/rhodecode/api/views/server_api.py b/rhodecode/api/views/server_api.py --- a/rhodecode/api/views/server_api.py +++ b/rhodecode/api/views/server_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/api/views/testing_api.py b/rhodecode/api/views/testing_api.py --- a/rhodecode/api/views/testing_api.py +++ b/rhodecode/api/views/testing_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/api/views/user_api.py b/rhodecode/api/views/user_api.py --- a/rhodecode/api/views/user_api.py +++ b/rhodecode/api/views/user_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -79,7 +79,8 @@ def get_user(request, apiuser, userid=Op "last_login": "Timestamp", "last_activity": "Timestamp", "lastname": "surnae", - "permissions": { + "permissions": , + "permissions_summary": { "global": [ "hg.inherit_default_perms.true", "usergroup.read", @@ -97,7 +98,7 @@ def get_user(request, apiuser, userid=Op "repositories": { "username/example": "repository.write"}, "repositories_groups": { "user-group/repo": "group.none" }, "user_groups": { "user_group_name": "usergroup.read" } - }, + } "user_id": 32, "username": "username" } @@ -115,7 +116,9 @@ def get_user(request, apiuser, userid=Op user = get_user_or_error(userid) data = user.get_api_data(include_secrets=True) - data['permissions'] = AuthUser(user_id=user.user_id).permissions + permissions = AuthUser(user_id=user.user_id).permissions + data['permissions'] = permissions # TODO(marcink): should be deprecated + data['permissions_summary'] = permissions return data diff --git a/rhodecode/api/views/user_group_api.py b/rhodecode/api/views/user_group_api.py --- a/rhodecode/api/views/user_group_api.py +++ b/rhodecode/api/views/user_group_api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -61,7 +61,7 @@ def get_user_group(request, apiuser, use "active": true, "group_description": "group description", "group_name": "group name", - "members": [ + "permissions": [ { "name": "owner-name", "origin": "owner", @@ -82,6 +82,12 @@ def get_user_group(request, apiuser, use "type": "user_group" } ], + "permissions_summary": { + "repositories": { + "aa-root-level-repo-1": "repository.admin" + }, + "repositories_groups": {} + }, "owner": "owner name", "users": [], "users_group_id": 2 @@ -119,8 +125,9 @@ def get_user_group(request, apiuser, use permissions.append(user_group_data) data = user_group.get_api_data() - data['members'] = permissions - + data["permissions"] = permissions + data["permissions_summary"] = UserGroupModel().get_perms_summary( + user_group.users_group_id) return data diff --git a/rhodecode/apps/__init__.py b/rhodecode/apps/__init__.py --- a/rhodecode/apps/__init__.py +++ b/rhodecode/apps/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/_base/__init__.py b/rhodecode/apps/_base/__init__.py --- a/rhodecode/apps/_base/__init__.py +++ b/rhodecode/apps/_base/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -147,46 +147,26 @@ class BaseAppView(object): % repo_name) return msg - def _get_local_tmpl_context(self, include_app_defaults=False): + def _get_local_tmpl_context(self, include_app_defaults=True): c = TemplateArgs() c.auth_user = self.request.user # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user c.rhodecode_user = self.request.user if include_app_defaults: - # NOTE(marcink): after full pyramid migration include_app_defaults - # should be turned on by default from rhodecode.lib.base import attach_context_attributes attach_context_attributes(c, self.request, self.request.user.user_id) return c - def _register_global_c(self, tmpl_args): - """ - Registers attributes to pylons global `c` - """ - - # TODO(marcink): remove once pyramid migration is finished - from pylons import tmpl_context as c - try: - for k, v in tmpl_args.items(): - setattr(c, k, v) - except TypeError: - log.exception('Failed to register pylons C') - pass - - def _get_template_context(self, tmpl_args): - self._register_global_c(tmpl_args) + def _get_template_context(self, tmpl_args, **kwargs): local_tmpl_args = { 'defaults': {}, 'errors': {}, - # register a fake 'c' to be used in templates instead of global - # pylons c, after migration to pyramid we should rename it to 'c' - # make sure we replace usage of _c in templates too - '_c': tmpl_args + 'c': tmpl_args } - local_tmpl_args.update(tmpl_args) + local_tmpl_args.update(kwargs) return local_tmpl_args def load_default_context(self): @@ -196,7 +176,7 @@ class BaseAppView(object): def load_default_context(self): c = self._get_local_tmpl_context() c.custom_var = 'foobar' - self._register_global_c(c) + return c """ raise NotImplementedError('Needs implementation in view class') @@ -215,7 +195,7 @@ class RepoAppView(BaseAppView): 'Requirements are missing for repository %s: %s', self.db_repo_name, error.message) - def _get_local_tmpl_context(self, include_app_defaults=False): + def _get_local_tmpl_context(self, include_app_defaults=True): _ = self.request.translate c = super(RepoAppView, self)._get_local_tmpl_context( include_app_defaults=include_app_defaults) @@ -338,7 +318,7 @@ class BaseReferencesView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c def load_refs_context(self, ref_items, partials_template): diff --git a/rhodecode/apps/admin/__init__.py b/rhodecode/apps/admin/__init__.py --- a/rhodecode/apps/admin/__init__.py +++ b/rhodecode/apps/admin/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -19,9 +19,7 @@ # and proprietary license terms, please see https://rhodecode.com/licenses/ -from rhodecode.apps.admin.navigation import NavigationRegistry -from rhodecode.config.routing import ADMIN_PREFIX -from rhodecode.lib.utils2 import str2bool +from rhodecode.apps._base import ADMIN_PREFIX def admin_routes(config): @@ -72,8 +70,14 @@ def admin_routes(config): name='admin_settings_process_management', pattern='/settings/process_management') config.add_route( + name='admin_settings_process_management_data', + pattern='/settings/process_management/data') + config.add_route( name='admin_settings_process_management_signal', pattern='/settings/process_management/signal') + config.add_route( + name='admin_settings_process_management_master_signal', + pattern='/settings/process_management/master_signal') # default settings config.add_route( @@ -83,6 +87,88 @@ def admin_routes(config): name='admin_defaults_repositories_update', pattern='/defaults/repositories/update') + # admin settings + + config.add_route( + name='admin_settings', + pattern='/settings') + config.add_route( + name='admin_settings_update', + pattern='/settings/update') + + config.add_route( + name='admin_settings_global', + pattern='/settings/global') + config.add_route( + name='admin_settings_global_update', + pattern='/settings/global/update') + + config.add_route( + name='admin_settings_vcs', + pattern='/settings/vcs') + config.add_route( + name='admin_settings_vcs_update', + pattern='/settings/vcs/update') + config.add_route( + name='admin_settings_vcs_svn_pattern_delete', + pattern='/settings/vcs/svn_pattern_delete') + + config.add_route( + name='admin_settings_mapping', + pattern='/settings/mapping') + config.add_route( + name='admin_settings_mapping_update', + pattern='/settings/mapping/update') + + config.add_route( + name='admin_settings_visual', + pattern='/settings/visual') + config.add_route( + name='admin_settings_visual_update', + pattern='/settings/visual/update') + + + config.add_route( + name='admin_settings_issuetracker', + pattern='/settings/issue-tracker') + config.add_route( + name='admin_settings_issuetracker_update', + pattern='/settings/issue-tracker/update') + config.add_route( + name='admin_settings_issuetracker_test', + pattern='/settings/issue-tracker/test') + config.add_route( + name='admin_settings_issuetracker_delete', + pattern='/settings/issue-tracker/delete') + + config.add_route( + name='admin_settings_email', + pattern='/settings/email') + config.add_route( + name='admin_settings_email_update', + pattern='/settings/email/update') + + config.add_route( + name='admin_settings_hooks', + pattern='/settings/hooks') + config.add_route( + name='admin_settings_hooks_update', + pattern='/settings/hooks/update') + config.add_route( + name='admin_settings_hooks_delete', + pattern='/settings/hooks/delete') + + config.add_route( + name='admin_settings_search', + pattern='/settings/search') + + config.add_route( + name='admin_settings_labs', + pattern='/settings/labs') + config.add_route( + name='admin_settings_labs_update', + pattern='/settings/labs/update') + # global permissions config.add_route( @@ -237,7 +323,7 @@ def admin_routes(config): config.add_route( name='edit_user_ips_delete', pattern='/users/{user_id:\d+}/edit/ips/delete', - user_route_with_default=True) # enabled for default user too + user_route_with_default=True) # enabled for default user too # user perms config.add_route( @@ -310,12 +396,10 @@ def admin_routes(config): def includeme(config): - settings = config.get_settings() + from rhodecode.apps.admin.navigation import includeme as nav_includeme # Create admin navigation registry and add it to the pyramid registry. - labs_active = str2bool(settings.get('labs_settings_active', False)) - navigation_registry = NavigationRegistry(labs_active=labs_active) - config.registry.registerUtility(navigation_registry) + nav_includeme(config) # main admin routes config.add_route(name='admin_home', pattern=ADMIN_PREFIX) diff --git a/rhodecode/apps/admin/interfaces.py b/rhodecode/apps/admin/interfaces.py --- a/rhodecode/apps/admin/interfaces.py +++ b/rhodecode/apps/admin/interfaces.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/admin/navigation.py b/rhodecode/apps/admin/navigation.py --- a/rhodecode/apps/admin/navigation.py +++ b/rhodecode/apps/admin/navigation.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -25,13 +25,14 @@ import collections from zope.interface import implementer from rhodecode.apps.admin.interfaces import IAdminNavigationRegistry -from rhodecode.lib.utils import get_registry +from rhodecode.lib.utils2 import str2bool from rhodecode.translation import _ log = logging.getLogger(__name__) -NavListEntry = collections.namedtuple('NavListEntry', ['key', 'name', 'url']) +NavListEntry = collections.namedtuple( + 'NavListEntry', ['key', 'name', 'url', 'active_list']) class NavEntry(object): @@ -41,77 +42,69 @@ class NavEntry(object): :param key: Unique identifier used to store reference in an OrderedDict. :param name: Display name, usually a translation string. :param view_name: Name of the view, used generate the URL. - :param pyramid: Indicator to use pyramid for URL generation. This should - be removed as soon as we are fully migrated to pyramid. + :param active_list: list of urls that we select active for this element """ - def __init__(self, key, name, view_name, pyramid=False): + def __init__(self, key, name, view_name, active_list=None): self.key = key self.name = name self.view_name = view_name - self.pyramid = pyramid + self._active_list = active_list or [] def generate_url(self, request): - if self.pyramid: - if hasattr(request, 'route_path'): - return request.route_path(self.view_name) - else: - # TODO: johbo: Remove this after migrating to pyramid. - # We need the pyramid request here to generate URLs to pyramid - # views from within pylons views. - from pyramid.threadlocal import get_current_request - pyramid_request = get_current_request() - return pyramid_request.route_path(self.view_name) - else: - from pylons import url - return url(self.view_name) + return request.route_path(self.view_name) def get_localized_name(self, request): - if hasattr(request, 'translate'): - return request.translate(self.name) - else: - # TODO(marcink): Remove this after migrating to pyramid - from pyramid.threadlocal import get_current_request - pyramid_request = get_current_request() - return pyramid_request.translate(self.name) + return request.translate(self.name) + + @property + def active_list(self): + active_list = [self.key] + if self._active_list: + active_list = self._active_list + return active_list @implementer(IAdminNavigationRegistry) class NavigationRegistry(object): _base_entries = [ - NavEntry('global', _('Global'), 'admin_settings_global'), - NavEntry('vcs', _('VCS'), 'admin_settings_vcs'), - NavEntry('visual', _('Visual'), 'admin_settings_visual'), - NavEntry('mapping', _('Remap and Rescan'), 'admin_settings_mapping'), + NavEntry('global', _('Global'), + 'admin_settings_global'), + NavEntry('vcs', _('VCS'), + 'admin_settings_vcs'), + NavEntry('visual', _('Visual'), + 'admin_settings_visual'), + NavEntry('mapping', _('Remap and Rescan'), + 'admin_settings_mapping'), NavEntry('issuetracker', _('Issue Tracker'), 'admin_settings_issuetracker'), - NavEntry('email', _('Email'), 'admin_settings_email'), - NavEntry('hooks', _('Hooks'), 'admin_settings_hooks'), - NavEntry('search', _('Full Text Search'), 'admin_settings_search'), - + NavEntry('email', _('Email'), + 'admin_settings_email'), + NavEntry('hooks', _('Hooks'), + 'admin_settings_hooks'), + NavEntry('search', _('Full Text Search'), + 'admin_settings_search'), NavEntry('integrations', _('Integrations'), - 'global_integrations_home', pyramid=True), + 'global_integrations_home'), NavEntry('system', _('System Info'), - 'admin_settings_system', pyramid=True), + 'admin_settings_system'), NavEntry('process_management', _('Processes'), - 'admin_settings_process_management', pyramid=True), + 'admin_settings_process_management'), NavEntry('sessions', _('User Sessions'), - 'admin_settings_sessions', pyramid=True), + 'admin_settings_sessions'), NavEntry('open_source', _('Open Source Licenses'), - 'admin_settings_open_source', pyramid=True), + 'admin_settings_open_source'), - # TODO: marcink: we disable supervisor now until the supervisor stats - # page is fixed in the nix configuration - # NavEntry('supervisor', _('Supervisor'), 'admin_settings_supervisor'), ] - _labs_entry = NavEntry('labs', _('Labs'), 'admin_settings_labs') + _labs_entry = NavEntry('labs', _('Labs'), + 'admin_settings_labs') def __init__(self, labs_active=False): - self._registered_entries = collections.OrderedDict([ - (item.key, item) for item in self.__class__._base_entries - ]) + self._registered_entries = collections.OrderedDict() + for item in self.__class__._base_entries: + self._registered_entries[item.key] = item if labs_active: self.add_entry(self._labs_entry) @@ -121,16 +114,16 @@ class NavigationRegistry(object): def get_navlist(self, request): navlist = [NavListEntry(i.key, i.get_localized_name(request), - i.generate_url(request)) + i.generate_url(request), i.active_list) for i in self._registered_entries.values()] return navlist -def navigation_registry(request): +def navigation_registry(request, registry=None): """ Helper that returns the admin navigation registry. """ - pyramid_registry = get_registry(request) + pyramid_registry = registry or request.registry nav_registry = pyramid_registry.queryUtility(IAdminNavigationRegistry) return nav_registry @@ -140,3 +133,11 @@ def navigation_list(request): Helper that returns the admin navigation as list of NavListEntry objects. """ return navigation_registry(request).get_navlist(request) + + +def includeme(config): + # Create admin navigation registry and add it to the pyramid registry. + settings = config.get_settings() + labs_active = str2bool(settings.get('labs_settings_active', False)) + navigation_registry = NavigationRegistry(labs_active=labs_active) + config.registry.registerUtility(navigation_registry) \ No newline at end of file diff --git a/rhodecode/apps/admin/tests/test_admin_audit_logs.py b/rhodecode/apps/admin/tests/test_admin_audit_logs.py --- a/rhodecode/apps/admin/tests/test_admin_audit_logs.py +++ b/rhodecode/apps/admin/tests/test_admin_audit_logs.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -46,10 +46,11 @@ def route_path(name, params=None, **kwar return base_url -class TestAdminController(TestController): +@pytest.mark.usefixtures('app') +class TestAdminController(object): @pytest.fixture(scope='class', autouse=True) - def prepare(self, request, pylonsapp): + def prepare(self, request, baseapp): UserLog.query().delete() Session().commit() @@ -84,104 +85,87 @@ class TestAdminController(TestController UserLog.query().delete() Session().commit() - def test_index(self): - self.log_user() + def test_index(self, autologin_user): response = self.app.get(route_path('admin_audit_logs')) response.mustcontain('Admin audit logs') - def test_filter_all_entries(self): - self.log_user() + def test_filter_all_entries(self, autologin_user): response = self.app.get(route_path('admin_audit_logs')) all_count = UserLog.query().count() response.mustcontain('%s entries' % all_count) - def test_filter_journal_filter_exact_match_on_repository(self): - self.log_user() + def test_filter_journal_filter_exact_match_on_repository(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='repository:rhodecode'))) response.mustcontain('3 entries') - def test_filter_journal_filter_exact_match_on_repository_CamelCase(self): - self.log_user() + def test_filter_journal_filter_exact_match_on_repository_CamelCase(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='repository:RhodeCode'))) response.mustcontain('3 entries') - def test_filter_journal_filter_wildcard_on_repository(self): - self.log_user() + def test_filter_journal_filter_wildcard_on_repository(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='repository:*test*'))) response.mustcontain('862 entries') - def test_filter_journal_filter_prefix_on_repository(self): - self.log_user() + def test_filter_journal_filter_prefix_on_repository(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='repository:test*'))) response.mustcontain('257 entries') - def test_filter_journal_filter_prefix_on_repository_CamelCase(self): - self.log_user() + def test_filter_journal_filter_prefix_on_repository_CamelCase(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='repository:Test*'))) response.mustcontain('257 entries') - def test_filter_journal_filter_prefix_on_repository_and_user(self): - self.log_user() + def test_filter_journal_filter_prefix_on_repository_and_user(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='repository:test* AND username:demo'))) response.mustcontain('130 entries') - def test_filter_journal_filter_prefix_on_repository_or_target_repo(self): - self.log_user() + def test_filter_journal_filter_prefix_on_repository_or_target_repo(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='repository:test* OR repository:rhodecode'))) response.mustcontain('260 entries') # 257 + 3 - def test_filter_journal_filter_exact_match_on_username(self): - self.log_user() + def test_filter_journal_filter_exact_match_on_username(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='username:demo'))) response.mustcontain('1087 entries') - def test_filter_journal_filter_exact_match_on_username_camelCase(self): - self.log_user() + def test_filter_journal_filter_exact_match_on_username_camelCase(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='username:DemO'))) response.mustcontain('1087 entries') - def test_filter_journal_filter_wildcard_on_username(self): - self.log_user() + def test_filter_journal_filter_wildcard_on_username(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='username:*test*'))) entries_count = UserLog.query().filter(UserLog.username.ilike('%test%')).count() response.mustcontain('{} entries'.format(entries_count)) - def test_filter_journal_filter_prefix_on_username(self): - self.log_user() + def test_filter_journal_filter_prefix_on_username(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='username:demo*'))) response.mustcontain('1101 entries') - def test_filter_journal_filter_prefix_on_user_or_other_user(self): - self.log_user() + def test_filter_journal_filter_prefix_on_user_or_other_user(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='username:demo OR username:volcan'))) response.mustcontain('1095 entries') # 1087 + 8 - def test_filter_journal_filter_wildcard_on_action(self): - self.log_user() + def test_filter_journal_filter_wildcard_on_action(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='action:*pull_request*'))) response.mustcontain('187 entries') - def test_filter_journal_filter_on_date(self): - self.log_user() + def test_filter_journal_filter_on_date(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='date:20121010'))) response.mustcontain('47 entries') - def test_filter_journal_filter_on_date_2(self): - self.log_user() + def test_filter_journal_filter_on_date_2(self, autologin_user): response = self.app.get(route_path('admin_audit_logs', params=dict(filter='date:20121020'))) response.mustcontain('17 entries') diff --git a/rhodecode/tests/functional/test_admin_auth_settings.py b/rhodecode/apps/admin/tests/test_admin_auth_settings.py rename from rhodecode/tests/functional/test_admin_auth_settings.py rename to rhodecode/apps/admin/tests/test_admin_auth_settings.py --- a/rhodecode/tests/functional/test_admin_auth_settings.py +++ b/rhodecode/apps/admin/tests/test_admin_auth_settings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -32,7 +32,7 @@ def assert_auth_settings_updated(respons @pytest.mark.usefixtures("autologin_user", "app") -class TestAuthSettingsController(object): +class TestAuthSettingsView(object): def _enable_plugins(self, plugins_list, csrf_token, override=None, verify_response=False): diff --git a/rhodecode/apps/admin/tests/test_admin_defaults.py b/rhodecode/apps/admin/tests/test_admin_defaults.py --- a/rhodecode/apps/admin/tests/test_admin_defaults.py +++ b/rhodecode/apps/admin/tests/test_admin_defaults.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/admin/tests/test_admin_main_views.py b/rhodecode/apps/admin/tests/test_admin_main_views.py --- a/rhodecode/apps/admin/tests/test_admin_main_views.py +++ b/rhodecode/apps/admin/tests/test_admin_main_views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/admin/tests/test_admin_permissions.py b/rhodecode/apps/admin/tests/test_admin_permissions.py --- a/rhodecode/apps/admin/tests/test_admin_permissions.py +++ b/rhodecode/apps/admin/tests/test_admin_permissions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/admin/tests/test_admin_repos.py b/rhodecode/apps/admin/tests/test_admin_repos.py --- a/rhodecode/apps/admin/tests/test_admin_repos.py +++ b/rhodecode/apps/admin/tests/test_admin_repos.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/admin/tests/test_admin_repository_groups.py b/rhodecode/apps/admin/tests/test_admin_repository_groups.py --- a/rhodecode/apps/admin/tests/test_admin_repository_groups.py +++ b/rhodecode/apps/admin/tests/test_admin_repository_groups.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/tests/functional/test_admin_settings.py b/rhodecode/apps/admin/tests/test_admin_settings.py rename from rhodecode/tests/functional/test_admin_settings.py rename to rhodecode/apps/admin/tests/test_admin_settings.py --- a/rhodecode/tests/functional/test_admin_settings.py +++ b/rhodecode/apps/admin/tests/test_admin_settings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -22,17 +22,88 @@ import mock import pytest import rhodecode -from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.apps._base import ADMIN_PREFIX from rhodecode.lib.utils2 import md5 from rhodecode.model.db import RhodeCodeUi from rhodecode.model.meta import Session from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel -from rhodecode.tests import url, assert_session_flash +from rhodecode.tests import assert_session_flash from rhodecode.tests.utils import AssertResponse -UPDATE_DATA_QUALNAME = ( - 'rhodecode.apps.admin.views.system_info.AdminSystemInfoSettingsView.get_update_data') +UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.get_update_data' + + +def route_path(name, params=None, **kwargs): + import urllib + from rhodecode.apps._base import ADMIN_PREFIX + + base_url = { + + 'admin_settings': + ADMIN_PREFIX +'/settings', + 'admin_settings_update': + ADMIN_PREFIX + '/settings/update', + 'admin_settings_global': + ADMIN_PREFIX + '/settings/global', + 'admin_settings_global_update': + ADMIN_PREFIX + '/settings/global/update', + 'admin_settings_vcs': + ADMIN_PREFIX + '/settings/vcs', + 'admin_settings_vcs_update': + ADMIN_PREFIX + '/settings/vcs/update', + 'admin_settings_vcs_svn_pattern_delete': + ADMIN_PREFIX + '/settings/vcs/svn_pattern_delete', + 'admin_settings_mapping': + ADMIN_PREFIX + '/settings/mapping', + 'admin_settings_mapping_update': + ADMIN_PREFIX + '/settings/mapping/update', + 'admin_settings_visual': + ADMIN_PREFIX + '/settings/visual', + 'admin_settings_visual_update': + ADMIN_PREFIX + '/settings/visual/update', + 'admin_settings_issuetracker': + ADMIN_PREFIX + '/settings/issue-tracker', + 'admin_settings_issuetracker_update': + ADMIN_PREFIX + '/settings/issue-tracker/update', + 'admin_settings_issuetracker_test': + ADMIN_PREFIX + '/settings/issue-tracker/test', + 'admin_settings_issuetracker_delete': + ADMIN_PREFIX + '/settings/issue-tracker/delete', + 'admin_settings_email': + ADMIN_PREFIX + '/settings/email', + 'admin_settings_email_update': + ADMIN_PREFIX + '/settings/email/update', + 'admin_settings_hooks': + ADMIN_PREFIX + '/settings/hooks', + 'admin_settings_hooks_update': + ADMIN_PREFIX + '/settings/hooks/update', + 'admin_settings_hooks_delete': + ADMIN_PREFIX + '/settings/hooks/delete', + 'admin_settings_search': + ADMIN_PREFIX + '/settings/search', + 'admin_settings_labs': + ADMIN_PREFIX + '/settings/labs', + 'admin_settings_labs_update': + ADMIN_PREFIX + '/settings/labs/update', + + 'admin_settings_sessions': + ADMIN_PREFIX + '/settings/sessions', + 'admin_settings_sessions_cleanup': + ADMIN_PREFIX + '/settings/sessions/cleanup', + 'admin_settings_system': + ADMIN_PREFIX + '/settings/system', + 'admin_settings_system_update': + ADMIN_PREFIX + '/settings/system/updates', + 'admin_settings_open_source': + ADMIN_PREFIX + '/settings/open_source', + + + }[name].format(**kwargs) + + if params: + base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) + return base_url @pytest.mark.usefixtures('autologin_user', 'app') @@ -47,12 +118,12 @@ class TestAdminSettingsController(object 'admin_settings_hooks', 'admin_settings_search', ]) - def test_simple_get(self, urlname, app): - app.get(url(urlname)) + def test_simple_get(self, urlname): + self.app.get(route_path(urlname)) def test_create_custom_hook(self, csrf_token): response = self.app.post( - url('admin_settings_hooks'), + route_path('admin_settings_hooks_update'), params={ 'new_hook_ui_key': 'test_hooks_1', 'new_hook_ui_value': 'cd /tmp', @@ -64,7 +135,7 @@ class TestAdminSettingsController(object def test_create_custom_hook_delete(self, csrf_token): response = self.app.post( - url('admin_settings_hooks'), + route_path('admin_settings_hooks_update'), params={ 'new_hook_ui_key': 'test_hooks_2', 'new_hook_ui_value': 'cd /tmp2', @@ -78,9 +149,9 @@ class TestAdminSettingsController(object # delete self.app.post( - url('admin_settings_hooks'), + route_path('admin_settings_hooks_delete'), params={'hook_id': hook_id, 'csrf_token': csrf_token}) - response = self.app.get(url('admin_settings_hooks')) + response = self.app.get(route_path('admin_settings_hooks')) response.mustcontain(no=['test_hooks_2']) response.mustcontain(no=['cd /tmp2']) @@ -135,7 +206,6 @@ class TestAdminSettingsGlobal(object): def test_title_change(self, csrf_token): old_title = 'RhodeCode' - new_title = old_title + '_changed' for new_title in ['Changed', 'Żółwik', old_title]: response = self.post_and_verify_settings({ @@ -161,7 +231,8 @@ class TestAdminSettingsGlobal(object): 'rhodecode_personal_repo_group_pattern': '${username}', } params.update(settings) - response = self.app.post(url('admin_settings_global'), params=params) + response = self.app.post( + route_path('admin_settings_global_update'), params=params) assert_session_flash(response, 'Updated application settings') app_settings = SettingsModel().get_all_settings() @@ -175,8 +246,8 @@ class TestAdminSettingsGlobal(object): @pytest.mark.usefixtures('autologin_user', 'app') class TestAdminSettingsVcs(object): - def test_contains_svn_default_patterns(self, app): - response = app.get(url('admin_settings_vcs')) + def test_contains_svn_default_patterns(self): + response = self.app.get(route_path('admin_settings_vcs')) expected_patterns = [ '/trunk', '/branches/*', @@ -186,7 +257,7 @@ class TestAdminSettingsVcs(object): response.mustcontain(pattern) def test_add_new_svn_branch_and_tag_pattern( - self, app, backend_svn, form_defaults, disable_sql_cache, + self, backend_svn, form_defaults, disable_sql_cache, csrf_token): form_defaults.update({ 'new_svn_branch': '/exp/branches/*', @@ -194,8 +265,9 @@ class TestAdminSettingsVcs(object): 'csrf_token': csrf_token, }) - response = app.post( - url('admin_settings_vcs'), params=form_defaults, status=302) + response = self.app.post( + route_path('admin_settings_vcs_update'), + params=form_defaults, status=302) response = response.follow() # Expect to find the new values on the page @@ -208,12 +280,12 @@ class TestAdminSettingsVcs(object): assert 'important_tags/v0.5' in repo.tags def test_add_same_svn_value_twice_shows_an_error_message( - self, app, form_defaults, csrf_token, settings_util): + self, form_defaults, csrf_token, settings_util): settings_util.create_rhodecode_ui('vcs_svn_branch', '/test') settings_util.create_rhodecode_ui('vcs_svn_tag', '/test') - response = app.post( - url('admin_settings_vcs'), + response = self.app.post( + route_path('admin_settings_vcs_update'), params={ 'paths_root_path': form_defaults['paths_root_path'], 'new_svn_branch': '/test', @@ -230,14 +302,13 @@ class TestAdminSettingsVcs(object): 'vcs_svn_tag', ]) def test_delete_svn_patterns( - self, section, app, csrf_token, settings_util): + self, section, csrf_token, settings_util): setting = settings_util.create_rhodecode_ui( section, '/test_delete', cleanup=False) - app.post( - url('admin_settings_vcs'), + self.app.post( + route_path('admin_settings_vcs_svn_pattern_delete'), params={ - '_method': 'delete', 'delete_svn_pattern': setting.ui_id, 'csrf_token': csrf_token}, headers={'X-REQUESTED-WITH': 'XMLHttpRequest'}) @@ -246,25 +317,24 @@ class TestAdminSettingsVcs(object): 'vcs_svn_branch', 'vcs_svn_tag', ]) - def test_delete_svn_patterns_raises_400_when_no_xhr( - self, section, app, csrf_token, settings_util): + def test_delete_svn_patterns_raises_404_when_no_xhr( + self, section, csrf_token, settings_util): setting = settings_util.create_rhodecode_ui(section, '/test_delete') - app.post( - url('admin_settings_vcs'), + self.app.post( + route_path('admin_settings_vcs_svn_pattern_delete'), params={ - '_method': 'delete', 'delete_svn_pattern': setting.ui_id, 'csrf_token': csrf_token}, - status=400) + status=404) - def test_extensions_hgsubversion(self, app, form_defaults, csrf_token): + def test_extensions_hgsubversion(self, form_defaults, csrf_token): form_defaults.update({ 'csrf_token': csrf_token, 'extensions_hgsubversion': 'True', }) - response = app.post( - url('admin_settings_vcs'), + response = self.app.post( + route_path('admin_settings_vcs_update'), params=form_defaults, status=302) @@ -275,13 +345,13 @@ class TestAdminSettingsVcs(object): 'value="True" checked="checked" />') response.mustcontain(extensions_input) - def test_extensions_hgevolve(self, app, form_defaults, csrf_token): + def test_extensions_hgevolve(self, form_defaults, csrf_token): form_defaults.update({ 'csrf_token': csrf_token, 'extensions_evolve': 'True', }) - response = app.post( - url('admin_settings_vcs'), + response = self.app.post( + route_path('admin_settings_vcs_update'), params=form_defaults, status=302) @@ -292,20 +362,19 @@ class TestAdminSettingsVcs(object): 'value="True" checked="checked" />') response.mustcontain(extensions_input) - def test_has_a_section_for_pull_request_settings(self, app): - response = app.get(url('admin_settings_vcs')) + def test_has_a_section_for_pull_request_settings(self): + response = self.app.get(route_path('admin_settings_vcs')) response.mustcontain('Pull Request Settings') - def test_has_an_input_for_invalidation_of_inline_comments( - self, app): - response = app.get(url('admin_settings_vcs')) + def test_has_an_input_for_invalidation_of_inline_comments(self): + response = self.app.get(route_path('admin_settings_vcs')) assert_response = AssertResponse(response) assert_response.one_element_exists( '[name=rhodecode_use_outdated_comments]') @pytest.mark.parametrize('new_value', [True, False]) def test_allows_to_change_invalidation_of_inline_comments( - self, app, form_defaults, csrf_token, new_value): + self, form_defaults, csrf_token, new_value): setting_key = 'use_outdated_comments' setting = SettingsModel().create_or_update_setting( setting_key, not new_value, 'bool') @@ -316,8 +385,8 @@ class TestAdminSettingsVcs(object): 'csrf_token': csrf_token, 'rhodecode_use_outdated_comments': str(new_value), }) - response = app.post( - url('admin_settings_vcs'), + response = self.app.post( + route_path('admin_settings_vcs_update'), params=form_defaults, status=302) response = response.follow() @@ -326,7 +395,7 @@ class TestAdminSettingsVcs(object): @pytest.mark.parametrize('new_value', [True, False]) def test_allows_to_change_hg_rebase_merge_strategy( - self, app, form_defaults, csrf_token, new_value): + self, form_defaults, csrf_token, new_value): setting_key = 'hg_use_rebase_for_merging' form_defaults.update({ @@ -336,8 +405,8 @@ class TestAdminSettingsVcs(object): with mock.patch.dict( rhodecode.CONFIG, {'labs_settings_active': 'true'}): - app.post( - url('admin_settings_vcs'), + self.app.post( + route_path('admin_settings_vcs_update'), params=form_defaults, status=302) @@ -353,14 +422,13 @@ class TestAdminSettingsVcs(object): @pytest.fixture def form_defaults(self): - from rhodecode.controllers.admin.settings import SettingsController - controller = SettingsController() - return controller._form_defaults() + from rhodecode.apps.admin.views.settings import AdminSettingsView + return AdminSettingsView._form_defaults() # TODO: johbo: What we really want is to checkpoint before a test run and # reset the session afterwards. @pytest.fixture(scope='class', autouse=True) - def cleanup_settings(self, request, pylonsapp): + def cleanup_settings(self, request, baseapp): ui_id = RhodeCodeUi.ui_id original_ids = list( r.ui_id for r in RhodeCodeUi.query().values(ui_id)) @@ -374,14 +442,16 @@ class TestAdminSettingsVcs(object): @pytest.mark.usefixtures('autologin_user', 'app') class TestLabsSettings(object): def test_get_settings_page_disabled(self): - with mock.patch.dict(rhodecode.CONFIG, - {'labs_settings_active': 'false'}): - response = self.app.get(url('admin_settings_labs'), status=302) + with mock.patch.dict( + rhodecode.CONFIG, {'labs_settings_active': 'false'}): - assert response.location.endswith(url('admin_settings')) + response = self.app.get( + route_path('admin_settings_labs'), status=302) + + assert response.location.endswith(route_path('admin_settings')) def test_get_settings_page_enabled(self): - from rhodecode.controllers.admin import settings + from rhodecode.apps.admin.views import settings lab_settings = [ settings.LabSetting( key='rhodecode_bool', @@ -401,7 +471,7 @@ class TestLabsSettings(object): with mock.patch.dict(rhodecode.CONFIG, {'labs_settings_active': 'true'}): with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings): - response = self.app.get(url('admin_settings_labs')) + response = self.app.get(route_path('admin_settings_labs')) assert '' in response assert '' in response @@ -417,9 +487,6 @@ class TestLabsSettings(object): @pytest.mark.usefixtures('app') class TestOpenSourceLicenses(object): - def _get_url(self): - return ADMIN_PREFIX + '/settings/open_source' - def test_records_are_displayed(self, autologin_user): sample_licenses = { "python2.7-pytest-2.7.1": { @@ -433,7 +500,8 @@ class TestOpenSourceLicenses(object): 'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses', return_value=sample_licenses) with read_licenses_patch: - response = self.app.get(self._get_url(), status=200) + response = self.app.get( + route_path('admin_settings_open_source'), status=200) assert_response = AssertResponse(response) assert_response.element_contains( @@ -444,29 +512,25 @@ class TestOpenSourceLicenses(object): assert_response.element_contains('.panel-body', license) def test_records_can_be_read(self, autologin_user): - response = self.app.get(self._get_url(), status=200) + response = self.app.get( + route_path('admin_settings_open_source'), status=200) assert_response = AssertResponse(response) assert_response.element_contains( '.panel-heading', 'Licenses of Third Party Packages') def test_forbidden_when_normal_user(self, autologin_regular_user): - self.app.get(self._get_url(), status=404) + self.app.get( + route_path('admin_settings_open_source'), status=404) @pytest.mark.usefixtures('app') class TestUserSessions(object): - def _get_url(self, name='admin_settings_sessions'): - return { - 'admin_settings_sessions': ADMIN_PREFIX + '/settings/sessions', - 'admin_settings_sessions_cleanup': ADMIN_PREFIX + '/settings/sessions/cleanup' - }[name] - def test_forbidden_when_normal_user(self, autologin_regular_user): - self.app.get(self._get_url(), status=404) + self.app.get(route_path('admin_settings_sessions'), status=404) def test_show_sessions_page(self, autologin_user): - response = self.app.get(self._get_url(), status=200) + response = self.app.get(route_path('admin_settings_sessions'), status=200) response.mustcontain('file') def test_cleanup_old_sessions(self, autologin_user, csrf_token): @@ -476,24 +540,19 @@ class TestUserSessions(object): 'expire_days': '60' } response = self.app.post( - self._get_url('admin_settings_sessions_cleanup'), params=post_data, + route_path('admin_settings_sessions_cleanup'), params=post_data, status=302) assert_session_flash(response, 'Cleaned up old sessions') @pytest.mark.usefixtures('app') class TestAdminSystemInfo(object): - def _get_url(self, name='admin_settings_system'): - return { - 'admin_settings_system': ADMIN_PREFIX + '/settings/system', - 'admin_settings_system_update': ADMIN_PREFIX + '/settings/system/updates', - }[name] def test_forbidden_when_normal_user(self, autologin_regular_user): - self.app.get(self._get_url(), status=404) + self.app.get(route_path('admin_settings_system'), status=404) def test_system_info_page(self, autologin_user): - response = self.app.get(self._get_url()) + response = self.app.get(route_path('admin_settings_system')) response.mustcontain('RhodeCode Community Edition, version {}'.format( rhodecode.__version__)) @@ -511,7 +570,7 @@ class TestAdminSystemInfo(object): ] } with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data): - response = self.app.get(self._get_url('admin_settings_system_update')) + response = self.app.get(route_path('admin_settings_system_update')) response.mustcontain('A new version is available') def test_system_update_nothing_new(self, autologin_user): @@ -524,13 +583,13 @@ class TestAdminSystemInfo(object): ] } with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data): - response = self.app.get(self._get_url('admin_settings_system_update')) + response = self.app.get(route_path('admin_settings_system_update')) response.mustcontain( - 'You already have the latest stable version.') + 'This instance is already running the latest stable version') def test_system_update_bad_response(self, autologin_user): with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')): - response = self.app.get(self._get_url('admin_settings_system_update')) + response = self.app.get(route_path('admin_settings_system_update')) response.mustcontain( 'Bad data sent from update server') @@ -542,12 +601,12 @@ class TestAdminSettingsIssueTracker(obje PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY def test_issuetracker_index(self, autologin_user): - response = self.app.get(url('admin_settings_issuetracker')) + response = self.app.get(route_path('admin_settings_issuetracker')) assert response.status_code == 200 def test_add_empty_issuetracker_pattern( self, request, autologin_user, csrf_token): - post_url = url('admin_settings_issuetracker_save') + post_url = route_path('admin_settings_issuetracker_update') post_data = { 'csrf_token': csrf_token } @@ -557,14 +616,14 @@ class TestAdminSettingsIssueTracker(obje self, request, autologin_user, csrf_token): pattern = 'issuetracker_pat' another_pattern = pattern+'1' - post_url = url('admin_settings_issuetracker_save') + post_url = route_path('admin_settings_issuetracker_update') post_data = { 'new_pattern_pattern_0': pattern, - 'new_pattern_url_0': 'url', + 'new_pattern_url_0': 'http://url', 'new_pattern_prefix_0': 'prefix', 'new_pattern_description_0': 'description', 'new_pattern_pattern_1': another_pattern, - 'new_pattern_url_1': 'url1', + 'new_pattern_url_1': 'https://url1', 'new_pattern_prefix_1': 'prefix1', 'new_pattern_description_1': 'description1', 'csrf_token': csrf_token @@ -600,10 +659,10 @@ class TestAdminSettingsIssueTracker(obje SettingsModel().create_or_update_setting( self.SHORT_PATTERN_KEY+old_uid, old_pattern, 'unicode') - post_url = url('admin_settings_issuetracker_save') + post_url = route_path('admin_settings_issuetracker_update') post_data = { 'new_pattern_pattern_0': pattern, - 'new_pattern_url_0': 'url', + 'new_pattern_url_0': 'https://url', 'new_pattern_prefix_0': 'prefix', 'new_pattern_description_0': 'description', 'uid': old_uid, @@ -634,10 +693,10 @@ class TestAdminSettingsIssueTracker(obje settings_util.create_rhodecode_setting( desc_key, 'old description', 'unicode', cleanup=False) - post_url = url('admin_settings_issuetracker_save') + post_url = route_path('admin_settings_issuetracker_update') post_data = { 'new_pattern_pattern_0': pattern, - 'new_pattern_url_0': 'url', + 'new_pattern_url_0': 'https://url', 'new_pattern_prefix_0': 'prefix', 'new_pattern_description_0': new_description, 'uid': self.uid, @@ -659,7 +718,7 @@ class TestAdminSettingsIssueTracker(obje settings_util.create_rhodecode_setting( self.SHORT_PATTERN_KEY+uid, pattern, 'unicode', cleanup=False) - post_url = url('admin_issuetracker_delete') + post_url = route_path('admin_settings_issuetracker_delete') post_data = { '_method': 'delete', 'uid': uid, diff --git a/rhodecode/apps/admin/tests/test_admin_user_groups.py b/rhodecode/apps/admin/tests/test_admin_user_groups.py --- a/rhodecode/apps/admin/tests/test_admin_user_groups.py +++ b/rhodecode/apps/admin/tests/test_admin_user_groups.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/admin/tests/test_admin_users.py b/rhodecode/apps/admin/tests/test_admin_users.py --- a/rhodecode/apps/admin/tests/test_admin_users.py +++ b/rhodecode/apps/admin/tests/test_admin_users.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -23,7 +23,6 @@ from sqlalchemy.orm.exc import NoResultF from rhodecode.lib import auth from rhodecode.lib import helpers as h -from rhodecode.model import validators from rhodecode.model.db import User, UserApiKeys, UserEmailMap, Repository from rhodecode.model.meta import Session from rhodecode.model.user import UserModel @@ -386,8 +385,7 @@ class TestAdminUsersView(TestController) 'csrf_token': self.csrf_token, }) - msg = validators.ValidUsername( - False, {})._messages['system_invalid_username'] + msg = u'Username "%(username)s" is forbidden' msg = h.html_escape(msg % {'username': 'new_user'}) response.mustcontain('%s' % msg) response.mustcontain( diff --git a/rhodecode/apps/admin/tests/test_admin_users_ssh_keys.py b/rhodecode/apps/admin/tests/test_admin_users_ssh_keys.py --- a/rhodecode/apps/admin/tests/test_admin_users_ssh_keys.py +++ b/rhodecode/apps/admin/tests/test_admin_users_ssh_keys.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/admin/views/__init__.py b/rhodecode/apps/admin/views/__init__.py --- a/rhodecode/apps/admin/views/__init__.py +++ b/rhodecode/apps/admin/views/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/admin/views/audit_logs.py b/rhodecode/apps/admin/views/audit_logs.py --- a/rhodecode/apps/admin/views/audit_logs.py +++ b/rhodecode/apps/admin/views/audit_logs.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -36,7 +36,6 @@ log = logging.getLogger(__name__) class AdminAuditLogsView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) return c @LoginRequired() diff --git a/rhodecode/apps/admin/views/defaults.py b/rhodecode/apps/admin/views/defaults.py --- a/rhodecode/apps/admin/views/defaults.py +++ b/rhodecode/apps/admin/views/defaults.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -44,7 +44,7 @@ class AdminDefaultSettingsView(BaseAppVi def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() @@ -79,7 +79,7 @@ class AdminDefaultSettingsView(BaseAppVi _ = self.request.translate c = self.load_default_context() c.active = 'repositories' - form = DefaultsForm()() + form = DefaultsForm(self.request.translate)() try: form_result = form.to_python(dict(self.request.POST)) diff --git a/rhodecode/apps/admin/views/main_views.py b/rhodecode/apps/admin/views/main_views.py --- a/rhodecode/apps/admin/views/main_views.py +++ b/rhodecode/apps/admin/views/main_views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/admin/views/open_source_licenses.py b/rhodecode/apps/admin/views/open_source_licenses.py --- a/rhodecode/apps/admin/views/open_source_licenses.py +++ b/rhodecode/apps/admin/views/open_source_licenses.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -35,7 +35,7 @@ class OpenSourceLicensesAdminSettingsVie def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/admin/views/permissions.py b/rhodecode/apps/admin/views/permissions.py --- a/rhodecode/apps/admin/views/permissions.py +++ b/rhodecode/apps/admin/views/permissions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -53,8 +53,6 @@ log = logging.getLogger(__name__) class AdminPermissionsView(BaseAppView, DataGridAppView): def load_default_context(self): c = self._get_local_tmpl_context() - - self._register_global_c(c) PermissionModel().set_global_permission_choices( c, gettext_translator=self.request.translate) return c @@ -100,6 +98,7 @@ class AdminPermissionsView(BaseAppView, c.active = 'application' _form = ApplicationPermissionsForm( + self.request.translate, [x[0] for x in c.register_choices], [x[0] for x in c.password_reset_choices], [x[0] for x in c.extern_activate_choices])() @@ -180,6 +179,7 @@ class AdminPermissionsView(BaseAppView, c.active = 'objects' _form = ObjectPermissionsForm( + self.request.translate, [x[0] for x in c.repo_perms_choices], [x[0] for x in c.group_perms_choices], [x[0] for x in c.user_group_perms_choices])() @@ -251,6 +251,7 @@ class AdminPermissionsView(BaseAppView, c.active = 'global' _form = UserPermissionsForm( + self.request.translate, [x[0] for x in c.repo_create_choices], [x[0] for x in c.repo_create_on_write_choices], [x[0] for x in c.repo_group_create_choices], @@ -395,6 +396,7 @@ class AdminPermissionsView(BaseAppView, renderer='json_ext', xhr=True) def ssh_keys_data(self): _ = self.request.translate + self.load_default_context() column_map = { 'fingerprint': 'ssh_key_fingerprint', 'username': User.username diff --git a/rhodecode/apps/admin/views/process_management.py b/rhodecode/apps/admin/views/process_management.py --- a/rhodecode/apps/admin/views/process_management.py +++ b/rhodecode/apps/admin/views/process_management.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -21,6 +21,7 @@ import logging import psutil +import signal from pyramid.view import view_config from rhodecode.apps._base import BaseAppView @@ -35,7 +36,7 @@ log = logging.getLogger(__name__) class AdminProcessManagementView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() @@ -55,6 +56,18 @@ class AdminProcessManagementView(BaseApp @LoginRequired() @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings_process_management_data', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings_process_management_data.mako') + def process_management_data(self): + _ = self.request.translate + c = self.load_default_context() + c.gunicorn_processes = ( + p for p in psutil.process_iter() if 'gunicorn' in p.name()) + return self._get_template_context(c) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') @CSRFRequired() @view_config( route_name='admin_settings_process_management_signal', @@ -89,3 +102,32 @@ class AdminProcessManagementView(BaseApp p.kill() return {'result': result} + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_process_management_master_signal', + request_method='POST', renderer='json_ext') + def process_management_master_signal(self): + pid_data = self.request.json.get('pid_data', {}) + pid = safe_int(pid_data['pid']) + action = pid_data['action'] + if pid: + try: + proc = psutil.Process(pid) + except psutil.NoSuchProcess: + return {'result': 'failure_no_such_process'} + + children = proc.children(recursive=True) + if children: + # master process + if action == '+' and len(children) <= 20: + proc.send_signal(signal.SIGTTIN) + elif action == '-' and len(children) >= 2: + proc.send_signal(signal.SIGTTOU) + else: + return {'result': 'failure_wrong_action'} + return {'result': 'success'} + + return {'result': 'failure_not_master'} diff --git a/rhodecode/apps/admin/views/repo_groups.py b/rhodecode/apps/admin/views/repo_groups.py --- a/rhodecode/apps/admin/views/repo_groups.py +++ b/rhodecode/apps/admin/views/repo_groups.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -47,7 +47,7 @@ class AdminRepoGroupsView(BaseAppView, D def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c def _load_form_data(self, c): @@ -150,8 +150,9 @@ class AdminRepoGroupsView(BaseAppView, D # permissions for can create group based on parent_id are checked # here in the Form available_groups = map(lambda k: safe_unicode(k[0]), c.repo_groups) - repo_group_form = RepoGroupForm(available_groups=available_groups, - can_create_in_root=can_create)() + repo_group_form = RepoGroupForm( + self.request.translate, available_groups=available_groups, + can_create_in_root=can_create)() repo_group_name = self.request.POST.get('group_name') try: diff --git a/rhodecode/apps/admin/views/repositories.py b/rhodecode/apps/admin/views/repositories.py --- a/rhodecode/apps/admin/views/repositories.py +++ b/rhodecode/apps/admin/views/repositories.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -28,6 +28,7 @@ from pyramid.renderers import render from pyramid.response import Response from rhodecode.apps._base import BaseAppView, DataGridAppView +from rhodecode.lib.celerylib.utils import get_task_id from rhodecode.lib.ext_json import json from rhodecode.lib.auth import ( @@ -49,7 +50,7 @@ class AdminReposView(BaseAppView, DataGr def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c def _load_form_data(self, c): @@ -58,7 +59,7 @@ class AdminReposView(BaseAppView, DataGr c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups) c.landing_revs_choices, c.landing_revs = \ - ScmModel().get_repo_landing_revs() + ScmModel().get_repo_landing_revs(self.request.translate) c.personal_repo_group = self._rhodecode_user.personal_repo_group @LoginRequired() @@ -143,21 +144,19 @@ class AdminReposView(BaseAppView, DataGr c = self.load_default_context() form_result = {} + self._load_form_data(c) task_id = None - self._load_form_data(c) - try: # CanWriteToGroup validators checks permissions of this POST - form_result = RepoForm(repo_groups=c.repo_groups_choices, - landing_revs=c.landing_revs_choices)()\ - .to_python(dict(self.request.POST)) + form = RepoForm( + self.request.translate, repo_groups=c.repo_groups_choices, + landing_revs=c.landing_revs_choices)() + form_result = form.to_python(dict(self.request.POST)) # create is done sometimes async on celery, db transaction # management is handled there. task = RepoModel().create(form_result, self._rhodecode_user.user_id) - from celery.result import BaseAsyncResult - if isinstance(task, BaseAsyncResult): - task_id = task.task_id + task_id = get_task_id(task) except formencode.Invalid as errors: data = render('rhodecode:templates/admin/repos/repo_add.mako', self._get_template_context(c), self.request) diff --git a/rhodecode/apps/admin/views/sessions.py b/rhodecode/apps/admin/views/sessions.py --- a/rhodecode/apps/admin/views/sessions.py +++ b/rhodecode/apps/admin/views/sessions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -30,6 +30,7 @@ from rhodecode.lib.auth import ( from rhodecode.lib.utils2 import safe_int from rhodecode.lib import system_info from rhodecode.lib import user_sessions +from rhodecode.lib import helpers as h log = logging.getLogger(__name__) @@ -39,7 +40,7 @@ class AdminSessionSettingsView(BaseAppVi def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() @@ -88,14 +89,12 @@ class AdminSessionSettingsView(BaseAppVi try: session_model.clean_sessions( older_than_seconds=older_than_seconds) - self.request.session.flash( - _('Cleaned up old sessions'), queue='success') + h.flash(_('Cleaned up old sessions'), category='success') except user_sessions.CleanupCommand as msg: - self.request.session.flash(msg.message, queue='warning') + h.flash(msg.message, category='warning') except Exception as e: log.exception('Failed session cleanup') - self.request.session.flash( - _('Failed to cleanup up old sessions'), queue='error') + h.flash(_('Failed to cleanup up old sessions'), category='error') redirect_to = self.request.resource_path( self.context, route_name='admin_settings_sessions') diff --git a/rhodecode/apps/admin/views/settings.py b/rhodecode/apps/admin/views/settings.py new file mode 100644 --- /dev/null +++ b/rhodecode/apps/admin/views/settings.py @@ -0,0 +1,764 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2010-2018 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 . +# +# 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 +import collections + +import datetime +import formencode +import formencode.htmlfill + +import rhodecode +from pyramid.view import view_config +from pyramid.httpexceptions import HTTPFound, HTTPNotFound +from pyramid.renderers import render +from pyramid.response import Response + +from rhodecode.apps._base import BaseAppView +from rhodecode.apps.admin.navigation import navigation_list +from rhodecode.apps.svn_support.config_keys import generate_config +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import ( + LoginRequired, HasPermissionAllDecorator, CSRFRequired) +from rhodecode.lib.celerylib import tasks, run_task +from rhodecode.lib.utils import repo2db_mapper +from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict +from rhodecode.lib.index import searcher_from_config + +from rhodecode.model.db import RhodeCodeUi, Repository +from rhodecode.model.forms import (ApplicationSettingsForm, + ApplicationUiSettingsForm, ApplicationVisualisationForm, + LabsSettingsForm, IssueTrackerPatternsForm) +from rhodecode.model.repo_group import RepoGroupModel + +from rhodecode.model.scm import ScmModel +from rhodecode.model.notification import EmailNotificationModel +from rhodecode.model.meta import Session +from rhodecode.model.settings import ( + IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound, + SettingsModel) + + +log = logging.getLogger(__name__) + + +class AdminSettingsView(BaseAppView): + + def load_default_context(self): + c = self._get_local_tmpl_context() + c.labs_active = str2bool( + rhodecode.CONFIG.get('labs_settings_active', 'true')) + c.navlist = navigation_list(self.request) + + return c + + @classmethod + def _get_ui_settings(cls): + ret = RhodeCodeUi.query().all() + + if not ret: + raise Exception('Could not get application ui settings !') + settings = {} + for each in ret: + k = each.ui_key + v = each.ui_value + if k == '/': + k = 'root_path' + + if k in ['push_ssl', 'publish', 'enabled']: + v = str2bool(v) + + if k.find('.') != -1: + k = k.replace('.', '_') + + if each.ui_section in ['hooks', 'extensions']: + v = each.ui_active + + settings[each.ui_section + '_' + k] = v + return settings + + @classmethod + def _form_defaults(cls): + defaults = SettingsModel().get_all_settings() + defaults.update(cls._get_ui_settings()) + + defaults.update({ + 'new_svn_branch': '', + 'new_svn_tag': '', + }) + return defaults + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings_vcs', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_vcs(self): + c = self.load_default_context() + c.active = 'vcs' + model = VcsSettingsModel() + c.svn_branch_patterns = model.get_global_svn_branch_patterns() + c.svn_tag_patterns = model.get_global_svn_tag_patterns() + + settings = self.request.registry.settings + c.svn_proxy_generate_config = settings[generate_config] + + defaults = self._form_defaults() + + model.create_largeobjects_dirs_if_needed(defaults['paths_root_path']) + + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=defaults, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_vcs_update', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_vcs_update(self): + _ = self.request.translate + c = self.load_default_context() + c.active = 'vcs' + + model = VcsSettingsModel() + c.svn_branch_patterns = model.get_global_svn_branch_patterns() + c.svn_tag_patterns = model.get_global_svn_tag_patterns() + + settings = self.request.registry.settings + c.svn_proxy_generate_config = settings[generate_config] + + application_form = ApplicationUiSettingsForm(self.request.translate)() + + try: + form_result = application_form.to_python(dict(self.request.POST)) + except formencode.Invalid as errors: + h.flash( + _("Some form inputs contain invalid data."), + category='error') + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + try: + if c.visual.allow_repo_location_change: + model.update_global_path_setting( + form_result['paths_root_path']) + + model.update_global_ssl_setting(form_result['web_push_ssl']) + model.update_global_hook_settings(form_result) + + model.create_or_update_global_svn_settings(form_result) + model.create_or_update_global_hg_settings(form_result) + model.create_or_update_global_git_settings(form_result) + model.create_or_update_global_pr_settings(form_result) + except Exception: + log.exception("Exception while updating settings") + h.flash(_('Error occurred during updating ' + 'application settings'), category='error') + else: + Session().commit() + h.flash(_('Updated VCS settings'), category='success') + raise HTTPFound(h.route_path('admin_settings_vcs')) + + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_vcs_svn_pattern_delete', request_method='POST', + renderer='json_ext', xhr=True) + def settings_vcs_delete_svn_pattern(self): + delete_pattern_id = self.request.POST.get('delete_svn_pattern') + model = VcsSettingsModel() + try: + model.delete_global_svn_pattern(delete_pattern_id) + except SettingNotFound: + log.exception( + 'Failed to delete svn_pattern with id %s', delete_pattern_id) + raise HTTPNotFound() + + Session().commit() + return True + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings_mapping', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_mapping(self): + c = self.load_default_context() + c.active = 'mapping' + + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_mapping_update', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_mapping_update(self): + _ = self.request.translate + c = self.load_default_context() + c.active = 'mapping' + rm_obsolete = self.request.POST.get('destroy', False) + invalidate_cache = self.request.POST.get('invalidate', False) + log.debug( + 'rescanning repo location with destroy obsolete=%s', rm_obsolete) + + if invalidate_cache: + log.debug('invalidating all repositories cache') + for repo in Repository.get_all(): + ScmModel().mark_for_invalidation(repo.repo_name, delete=True) + + filesystem_repos = ScmModel().repo_scan() + added, removed = repo2db_mapper(filesystem_repos, rm_obsolete) + _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-' + h.flash(_('Repositories successfully ' + 'rescanned added: %s ; removed: %s') % + (_repr(added), _repr(removed)), + category='success') + raise HTTPFound(h.route_path('admin_settings_mapping')) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + @view_config( + route_name='admin_settings_global', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_global(self): + c = self.load_default_context() + c.active = 'global' + c.personal_repo_group_default_pattern = RepoGroupModel()\ + .get_personal_group_name_pattern() + + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_update', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + @view_config( + route_name='admin_settings_global_update', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_global_update(self): + _ = self.request.translate + c = self.load_default_context() + c.active = 'global' + c.personal_repo_group_default_pattern = RepoGroupModel()\ + .get_personal_group_name_pattern() + application_form = ApplicationSettingsForm(self.request.translate)() + try: + form_result = application_form.to_python(dict(self.request.POST)) + except formencode.Invalid as errors: + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + settings = [ + ('title', 'rhodecode_title', 'unicode'), + ('realm', 'rhodecode_realm', 'unicode'), + ('pre_code', 'rhodecode_pre_code', 'unicode'), + ('post_code', 'rhodecode_post_code', 'unicode'), + ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'), + ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'), + ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'), + ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'), + ] + try: + for setting, form_key, type_ in settings: + sett = SettingsModel().create_or_update_setting( + setting, form_result[form_key], type_) + Session().add(sett) + + Session().commit() + SettingsModel().invalidate_settings_cache() + h.flash(_('Updated application settings'), category='success') + except Exception: + log.exception("Exception while updating application settings") + h.flash( + _('Error occurred during updating application settings'), + category='error') + + raise HTTPFound(h.route_path('admin_settings_global')) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings_visual', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_visual(self): + c = self.load_default_context() + c.active = 'visual' + + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_visual_update', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_visual_update(self): + _ = self.request.translate + c = self.load_default_context() + c.active = 'visual' + application_form = ApplicationVisualisationForm(self.request.translate)() + try: + form_result = application_form.to_python(dict(self.request.POST)) + except formencode.Invalid as errors: + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + try: + settings = [ + ('show_public_icon', 'rhodecode_show_public_icon', 'bool'), + ('show_private_icon', 'rhodecode_show_private_icon', 'bool'), + ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'), + ('repository_fields', 'rhodecode_repository_fields', 'bool'), + ('dashboard_items', 'rhodecode_dashboard_items', 'int'), + ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'), + ('show_version', 'rhodecode_show_version', 'bool'), + ('use_gravatar', 'rhodecode_use_gravatar', 'bool'), + ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'), + ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'), + ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'), + ('clone_uri_ssh_tmpl', 'rhodecode_clone_uri_ssh_tmpl', 'unicode'), + ('support_url', 'rhodecode_support_url', 'unicode'), + ('show_revision_number', 'rhodecode_show_revision_number', 'bool'), + ('show_sha_length', 'rhodecode_show_sha_length', 'int'), + ] + for setting, form_key, type_ in settings: + sett = SettingsModel().create_or_update_setting( + setting, form_result[form_key], type_) + Session().add(sett) + + Session().commit() + SettingsModel().invalidate_settings_cache() + h.flash(_('Updated visualisation settings'), category='success') + except Exception: + log.exception("Exception updating visualization settings") + h.flash(_('Error occurred during updating ' + 'visualisation settings'), + category='error') + + raise HTTPFound(h.route_path('admin_settings_visual')) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings_issuetracker', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_issuetracker(self): + c = self.load_default_context() + c.active = 'issuetracker' + defaults = SettingsModel().get_all_settings() + + entry_key = 'rhodecode_issuetracker_pat_' + + c.issuetracker_entries = {} + for k, v in defaults.items(): + if k.startswith(entry_key): + uid = k[len(entry_key):] + c.issuetracker_entries[uid] = None + + for uid in c.issuetracker_entries: + c.issuetracker_entries[uid] = AttributeDict({ + 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid), + 'url': defaults.get('rhodecode_issuetracker_url_' + uid), + 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid), + 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid), + }) + + return self._get_template_context(c) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_issuetracker_test', request_method='POST', + renderer='string', xhr=True) + def settings_issuetracker_test(self): + return h.urlify_commit_message( + self.request.POST.get('test_text', ''), + 'repo_group/test_repo1') + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_issuetracker_update', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_issuetracker_update(self): + _ = self.request.translate + self.load_default_context() + settings_model = IssueTrackerSettingsModel() + + try: + form = IssueTrackerPatternsForm(self.request.translate)() + data = form.to_python(self.request.POST) + except formencode.Invalid as errors: + log.exception('Failed to add new pattern') + error = errors + h.flash(_('Invalid issue tracker pattern: {}'.format(error)), + category='error') + raise HTTPFound(h.route_path('admin_settings_issuetracker')) + + if data: + for uid in data.get('delete_patterns', []): + settings_model.delete_entries(uid) + + for pattern in data.get('patterns', []): + for setting, value, type_ in pattern: + sett = settings_model.create_or_update_setting( + setting, value, type_) + Session().add(sett) + + Session().commit() + + SettingsModel().invalidate_settings_cache() + h.flash(_('Updated issue tracker entries'), category='success') + raise HTTPFound(h.route_path('admin_settings_issuetracker')) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_issuetracker_delete', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_issuetracker_delete(self): + _ = self.request.translate + self.load_default_context() + uid = self.request.POST.get('uid') + try: + IssueTrackerSettingsModel().delete_entries(uid) + except Exception: + log.exception('Failed to delete issue tracker setting %s', uid) + raise HTTPNotFound() + h.flash(_('Removed issue tracker entry'), category='success') + raise HTTPFound(h.route_path('admin_settings_issuetracker')) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings_email', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_email(self): + c = self.load_default_context() + c.active = 'email' + c.rhodecode_ini = rhodecode.CONFIG + + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_email_update', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_email_update(self): + _ = self.request.translate + c = self.load_default_context() + c.active = 'email' + + test_email = self.request.POST.get('test_email') + + if not test_email: + h.flash(_('Please enter email address'), category='error') + raise HTTPFound(h.route_path('admin_settings_email')) + + email_kwargs = { + 'date': datetime.datetime.now(), + 'user': c.rhodecode_user, + 'rhodecode_version': c.rhodecode_version + } + + (subject, headers, email_body, + email_body_plaintext) = EmailNotificationModel().render_email( + EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs) + + recipients = [test_email] if test_email else None + + run_task(tasks.send_email, recipients, subject, + email_body_plaintext, email_body) + + h.flash(_('Send email task created'), category='success') + raise HTTPFound(h.route_path('admin_settings_email')) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings_hooks', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_hooks(self): + c = self.load_default_context() + c.active = 'hooks' + + model = SettingsModel() + c.hooks = model.get_builtin_hooks() + c.custom_hooks = model.get_custom_hooks() + + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_hooks_update', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + @view_config( + route_name='admin_settings_hooks_delete', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_hooks_update(self): + _ = self.request.translate + c = self.load_default_context() + c.active = 'hooks' + if c.visual.allow_custom_hooks_settings: + ui_key = self.request.POST.get('new_hook_ui_key') + ui_value = self.request.POST.get('new_hook_ui_value') + + hook_id = self.request.POST.get('hook_id') + new_hook = False + + model = SettingsModel() + try: + if ui_value and ui_key: + model.create_or_update_hook(ui_key, ui_value) + h.flash(_('Added new hook'), category='success') + new_hook = True + elif hook_id: + RhodeCodeUi.delete(hook_id) + Session().commit() + + # check for edits + update = False + _d = self.request.POST.dict_of_lists() + for k, v in zip(_d.get('hook_ui_key', []), + _d.get('hook_ui_value_new', [])): + model.create_or_update_hook(k, v) + update = True + + if update and not new_hook: + h.flash(_('Updated hooks'), category='success') + Session().commit() + except Exception: + log.exception("Exception during hook creation") + h.flash(_('Error occurred during hook creation'), + category='error') + + raise HTTPFound(h.route_path('admin_settings_hooks')) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings_search', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_search(self): + c = self.load_default_context() + c.active = 'search' + + searcher = searcher_from_config(self.request.registry.settings) + c.statistics = searcher.statistics(self.request.translate) + + return self._get_template_context(c) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( + route_name='admin_settings_labs', request_method='GET', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_labs(self): + c = self.load_default_context() + if not c.labs_active: + raise HTTPFound(h.route_path('admin_settings')) + + c.active = 'labs' + c.lab_settings = _LAB_SETTINGS + + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @CSRFRequired() + @view_config( + route_name='admin_settings_labs_update', request_method='POST', + renderer='rhodecode:templates/admin/settings/settings.mako') + def settings_labs_update(self): + _ = self.request.translate + c = self.load_default_context() + c.active = 'labs' + + application_form = LabsSettingsForm(self.request.translate)() + try: + form_result = application_form.to_python(dict(self.request.POST)) + except formencode.Invalid as errors: + h.flash( + _('Some form inputs contain invalid data.'), + category='error') + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=errors.value, + errors=errors.error_dict or {}, + prefix_error=False, + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + try: + session = Session() + for setting in _LAB_SETTINGS: + setting_name = setting.key[len('rhodecode_'):] + sett = SettingsModel().create_or_update_setting( + setting_name, form_result[setting.key], setting.type) + session.add(sett) + + except Exception: + log.exception('Exception while updating lab settings') + h.flash(_('Error occurred during updating labs settings'), + category='error') + else: + Session().commit() + SettingsModel().invalidate_settings_cache() + h.flash(_('Updated Labs settings'), category='success') + raise HTTPFound(h.route_path('admin_settings_labs')) + + data = render('rhodecode:templates/admin/settings/settings.mako', + self._get_template_context(c), self.request) + html = formencode.htmlfill.render( + data, + defaults=self._form_defaults(), + encoding="UTF-8", + force_defaults=False + ) + return Response(html) + + +# :param key: name of the setting including the 'rhodecode_' prefix +# :param type: the RhodeCodeSetting type to use. +# :param group: the i18ned group in which we should dispaly this setting +# :param label: the i18ned label we should display for this setting +# :param help: the i18ned help we should dispaly for this setting +LabSetting = collections.namedtuple( + 'LabSetting', ('key', 'type', 'group', 'label', 'help')) + + +# This list has to be kept in sync with the form +# rhodecode.model.forms.LabsSettingsForm. +_LAB_SETTINGS = [ + +] diff --git a/rhodecode/apps/admin/views/svn_config.py b/rhodecode/apps/admin/views/svn_config.py --- a/rhodecode/apps/admin/views/svn_config.py +++ b/rhodecode/apps/admin/views/svn_config.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/admin/views/system_info.py b/rhodecode/apps/admin/views/system_info.py --- a/rhodecode/apps/admin/views/system_info.py +++ b/rhodecode/apps/admin/views/system_info.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -20,7 +20,6 @@ import logging import urllib2 -import packaging.version from pyramid.view import view_config @@ -31,8 +30,7 @@ from rhodecode.lib import helpers as h from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator) from rhodecode.lib.utils2 import str2bool from rhodecode.lib import system_info -from rhodecode.lib.ext_json import json -from rhodecode.model.settings import SettingsModel +from rhodecode.model.update import UpdateModel log = logging.getLogger(__name__) @@ -40,26 +38,8 @@ log = logging.getLogger(__name__) class AdminSystemInfoSettingsView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) return c - @staticmethod - def get_update_data(update_url): - """Return the JSON update data.""" - ver = rhodecode.__version__ - log.debug('Checking for upgrade on `%s` server', update_url) - opener = urllib2.build_opener() - opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)] - response = opener.open(update_url) - response_data = response.read() - data = json.loads(response_data) - - return data - - def get_update_url(self): - settings = SettingsModel().get_all_settings() - return settings.get('rhodecode_update_url') - @LoginRequired() @HasPermissionAllDecorator('hg.admin') @view_config( @@ -77,7 +57,7 @@ class AdminSystemInfoSettingsView(BaseAp snapshot = str2bool(self.request.params.get('snapshot')) - c.rhodecode_update_url = self.get_update_url() + c.rhodecode_update_url = UpdateModel().get_update_url() server_info = system_info.get_system_info(self.request.environ) for key, val in server_info.items(): @@ -97,6 +77,14 @@ class AdminSystemInfoSettingsView(BaseAp update_info_msg = _('Note: please make sure this server can ' 'access `${url}` for the update link to work', mapping=dict(url=c.rhodecode_update_url)) + version = UpdateModel().get_stored_version() + is_outdated = UpdateModel().is_outdated( + rhodecode.__version__, version) + update_state = { + 'type': 'warning', + 'message': 'New version available: {}'.format(version) + } \ + if is_outdated else {} c.data_items = [ # update info (_('Update info'), h.literal( @@ -107,6 +95,7 @@ class AdminSystemInfoSettingsView(BaseAp # RhodeCode specific (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')), + (_('Latest version'), version, update_state), (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')), (_('RhodeCode Server ID'), val('server')['server_id'], state('server')), (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')), @@ -166,8 +155,7 @@ class AdminSystemInfoSettingsView(BaseAp c.data_items.pop(0) # remove server info self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako' else: - self.request.session.flash( - 'You are not allowed to do this', queue='warning') + h.flash('You are not allowed to do this', category='warning') return self._get_template_context(c) @LoginRequired() @@ -179,11 +167,11 @@ class AdminSystemInfoSettingsView(BaseAp _ = self.request.translate c = self.load_default_context() - update_url = self.get_update_url() + update_url = UpdateModel().get_update_url() _err = lambda s: '
{}
'.format(s) try: - data = self.get_update_data(update_url) + data = UpdateModel().get_update_data(update_url) except urllib2.URLError as e: log.exception("Exception contacting upgrade server") self.request.override_renderer = 'string' @@ -201,9 +189,9 @@ class AdminSystemInfoSettingsView(BaseAp c.cur_ver = rhodecode.__version__ c.should_upgrade = False - if (packaging.version.Version(c.latest_ver) > - packaging.version.Version(c.cur_ver)): + is_oudated = UpdateModel().is_outdated(c.cur_ver, c.latest_ver) + if is_oudated: c.should_upgrade = True c.important_notices = latest['general'] - + UpdateModel().store_version(latest['version']) return self._get_template_context(c) diff --git a/rhodecode/apps/admin/views/user_groups.py b/rhodecode/apps/admin/views/user_groups.py --- a/rhodecode/apps/admin/views/user_groups.py +++ b/rhodecode/apps/admin/views/user_groups.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -53,7 +53,6 @@ class AdminUserGroupsView(BaseAppView, D PermissionModel().set_global_permission_choices( c, gettext_translator=self.request.translate) - self._register_global_c(c) return c # permission check in data loading of @@ -74,6 +73,7 @@ class AdminUserGroupsView(BaseAppView, D route_name='user_groups_data', request_method='GET', renderer='json_ext', xhr=True) def user_groups_list_data(self): + self.load_default_context() column_map = { 'active': 'users_group_active', 'description': 'user_group_description', @@ -86,7 +86,7 @@ class AdminUserGroupsView(BaseAppView, D self.request, column_map=column_map) _render = self.request.get_partial_renderer( - 'data_table/_dt_elements.mako') + 'rhodecode:templates/data_table/_dt_elements.mako') def user_group_name(user_group_id, user_group_name): return _render("user_group_name", user_group_id, user_group_name) @@ -195,7 +195,7 @@ class AdminUserGroupsView(BaseAppView, D def user_groups_create(self): _ = self.request.translate c = self.load_default_context() - users_group_form = UserGroupForm()() + users_group_form = UserGroupForm(self.request.translate)() user_group_name = self.request.POST.get('users_group_name') try: diff --git a/rhodecode/apps/admin/views/users.py b/rhodecode/apps/admin/views/users.py --- a/rhodecode/apps/admin/views/users.py +++ b/rhodecode/apps/admin/views/users.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -44,7 +44,8 @@ from rhodecode.lib import helpers as h from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict from rhodecode.model.auth_token import AuthTokenModel from rhodecode.model.forms import ( - UserForm, UserIndividualPermissionsForm, UserPermissionsForm) + UserForm, UserIndividualPermissionsForm, UserPermissionsForm, + UserExtraEmailForm, UserExtraIpForm) from rhodecode.model.permission import PermissionModel from rhodecode.model.repo_group import RepoGroupModel from rhodecode.model.ssh_key import SshKeyModel @@ -62,7 +63,6 @@ class AdminUsersView(BaseAppView, DataGr def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) return c @LoginRequired() @@ -81,6 +81,7 @@ class AdminUsersView(BaseAppView, DataGr route_name='users_data', request_method='GET', renderer='json_ext', xhr=True) def users_list_data(self): + self.load_default_context() column_map = { 'first_name': 'name', 'last_name': 'lastname', @@ -90,7 +91,7 @@ class AdminUsersView(BaseAppView, DataGr self.request, column_map=column_map) _render = self.request.get_partial_renderer( - 'data_table/_dt_elements.mako') + 'rhodecode:templates/data_table/_dt_elements.mako') def user_actions(user_id, username): return _render("user_actions", user_id, username) @@ -190,7 +191,7 @@ class AdminUsersView(BaseAppView, DataGr c = self.load_default_context() c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name user_model = UserModel() - user_form = UserForm()() + user_form = UserForm(self.request.translate)() try: form_result = user_form.to_python(dict(self.request.POST)) user = user_model.create(form_result) @@ -258,7 +259,6 @@ class UsersView(UserAppView): PermissionModel().set_global_permission_choices( c, gettext_translator=req.translate) - self._register_global_c(c) return c @LoginRequired() @@ -279,7 +279,8 @@ class UsersView(UserAppView): c.extern_name = c.user.extern_name c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr) available_languages = [x[0] for x in c.allowed_languages] - _form = UserForm(edit=True, available_languages=available_languages, + _form = UserForm(self.request.translate, edit=True, + available_languages=available_languages, old_data={'user_id': user_id, 'email': c.user.email})() form_result = {} @@ -537,7 +538,7 @@ class UsersView(UserAppView): c.active = 'global_perms' try: # first stage that verifies the checkbox - _form = UserIndividualPermissionsForm() + _form = UserIndividualPermissionsForm(self.request.translate) form_result = _form.to_python(dict(self.request.POST)) inherit_perms = form_result['inherit_default_permissions'] c.user.inherit_default_permissions = inherit_perms @@ -546,6 +547,7 @@ class UsersView(UserAppView): if not inherit_perms: # only update the individual ones if we un check the flag _form = UserPermissionsForm( + self.request.translate, [x[0] for x in c.repo_create_choices], [x[0] for x in c.repo_create_on_write_choices], [x[0] for x in c.repo_group_create_choices], @@ -913,6 +915,11 @@ class UsersView(UserAppView): email = self.request.POST.get('new_email') user_data = c.user.get_api_data() try: + + form = UserExtraEmailForm(self.request.translate)() + data = form.to_python({'email': email}) + email = data['email'] + UserModel().add_extra_email(c.user.user_id, email) audit_logger.store_web( 'user.edit.email.add', @@ -1008,6 +1015,10 @@ class UsersView(UserAppView): user_data = c.user.get_api_data() for ip in ip_list: try: + form = UserExtraIpForm(self.request.translate)() + data = form.to_python({'ip': ip}) + ip = data['ip'] + user_model.add_extra_ip(c.user.user_id, ip, desc) audit_logger.store_web( 'user.edit.ip.add', diff --git a/rhodecode/apps/channelstream/__init__.py b/rhodecode/apps/channelstream/__init__.py --- a/rhodecode/apps/channelstream/__init__.py +++ b/rhodecode/apps/channelstream/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -20,9 +20,10 @@ import os +from pyramid.events import ApplicationCreated from pyramid.settings import asbool -from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.apps._base import ADMIN_PREFIX from rhodecode.lib.ext_json import json @@ -57,6 +58,14 @@ PLUGIN_DEFINITION = { } +def maybe_create_history_store(event): + # create plugin history location + settings = event.app.registry.settings + history_dir = settings.get('channelstream.history.location', '') + if history_dir and not os.path.exists(history_dir): + os.makedirs(history_dir, 0750) + + def includeme(config): settings = config.registry.settings PLUGIN_DEFINITION['config']['enabled'] = asbool( @@ -71,10 +80,7 @@ def includeme(config): PLUGIN_DEFINITION['name'], PLUGIN_DEFINITION['config'] ) - # create plugin history location - history_dir = PLUGIN_DEFINITION['config']['history.location'] - if history_dir and not os.path.exists(history_dir): - os.makedirs(history_dir, 0750) + config.add_subscriber(maybe_create_history_store, ApplicationCreated) config.add_route( name='channelstream_connect', diff --git a/rhodecode/apps/channelstream/views.py b/rhodecode/apps/channelstream/views.py --- a/rhodecode/apps/channelstream/views.py +++ b/rhodecode/apps/channelstream/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -24,6 +24,7 @@ import uuid from pyramid.view import view_config from pyramid.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPBadGateway +from rhodecode.apps._base import BaseAppView from rhodecode.lib.channelstream import ( channelstream_request, ChannelstreamConnectionException, @@ -34,28 +35,28 @@ from rhodecode.lib.channelstream import parse_channels_info, update_history_from_logs, STATE_PUBLIC_KEYS) + from rhodecode.lib.auth import NotAnonymous log = logging.getLogger(__name__) -class ChannelstreamView(object): - def __init__(self, context, request): - self.context = context - self.request = request +class ChannelstreamView(BaseAppView): - # Some of the decorators rely on this attribute to be present - # on the class of the decorated method. - self._rhodecode_user = request.user - registry = request.registry - self.channelstream_config = registry.rhodecode_plugins['channelstream'] + def load_default_context(self): + c = self._get_local_tmpl_context() + self.channelstream_config = \ + self.request.registry.rhodecode_plugins['channelstream'] if not self.channelstream_config.get('enabled'): log.error('Channelstream plugin is disabled') raise HTTPBadRequest() + return c + @NotAnonymous() - @view_config(route_name='channelstream_connect', renderer='json') + @view_config(route_name='channelstream_connect', renderer='json_ext') def connect(self): + self.load_default_context() """ handle authorization of users trying to connect """ try: json_body = self.request.json_body @@ -122,9 +123,10 @@ class ChannelstreamView(object): return connect_result @NotAnonymous() - @view_config(route_name='channelstream_subscribe', renderer='json') + @view_config(route_name='channelstream_subscribe', renderer='json_ext') def subscribe(self): """ can be used to subscribe specific connection to other channels """ + self.load_default_context() try: json_body = self.request.json_body except Exception: diff --git a/rhodecode/apps/debug_style/__init__.py b/rhodecode/apps/debug_style/__init__.py --- a/rhodecode/apps/debug_style/__init__.py +++ b/rhodecode/apps/debug_style/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/debug_style/views.py b/rhodecode/apps/debug_style/views.py --- a/rhodecode/apps/debug_style/views.py +++ b/rhodecode/apps/debug_style/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -31,7 +31,7 @@ log = logging.getLogger(__name__) class DebugStyleView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @view_config( diff --git a/rhodecode/apps/gist/__init__.py b/rhodecode/apps/gist/__init__.py --- a/rhodecode/apps/gist/__init__.py +++ b/rhodecode/apps/gist/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/gist/tests/__init__.py b/rhodecode/apps/gist/tests/__init__.py --- a/rhodecode/apps/gist/tests/__init__.py +++ b/rhodecode/apps/gist/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/gist/tests/test_admin_gists.py b/rhodecode/apps/gist/tests/test_admin_gists.py --- a/rhodecode/apps/gist/tests/test_admin_gists.py +++ b/rhodecode/apps/gist/tests/test_admin_gists.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/gist/views.py b/rhodecode/apps/gist/views.py --- a/rhodecode/apps/gist/views.py +++ b/rhodecode/apps/gist/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2013-2017 RhodeCode GmbH +# Copyright (C) 2013-2018 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 @@ -67,7 +67,7 @@ class GistView(BaseAppView): (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users")) ] - self._register_global_c(c) + return c @LoginRequired() @@ -114,7 +114,7 @@ class GistView(BaseAppView): c.active = 'public' _render = self.request.get_partial_renderer( - 'data_table/_dt_elements.mako') + 'rhodecode:templates/data_table/_dt_elements.mako') data = [] diff --git a/rhodecode/apps/home/__init__.py b/rhodecode/apps/home/__init__.py --- a/rhodecode/apps/home/__init__.py +++ b/rhodecode/apps/home/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/home/tests/__init__.py b/rhodecode/apps/home/tests/__init__.py --- a/rhodecode/apps/home/tests/__init__.py +++ b/rhodecode/apps/home/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/home/tests/test_get_goto_switched_data.py b/rhodecode/apps/home/tests/test_get_goto_switched_data.py --- a/rhodecode/apps/home/tests/test_get_goto_switched_data.py +++ b/rhodecode/apps/home/tests/test_get_goto_switched_data.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -66,7 +66,7 @@ class TestGotoSwitcherData(TestControlle ] @pytest.fixture(autouse=True, scope='class') - def prepare(self, request, pylonsapp): + def prepare(self, request, baseapp): for repo_and_group in self.required_repos_with_groups: # create structure of groups and return the last group diff --git a/rhodecode/apps/home/tests/test_get_repo_list_data.py b/rhodecode/apps/home/tests/test_get_repo_list_data.py --- a/rhodecode/apps/home/tests/test_get_repo_list_data.py +++ b/rhodecode/apps/home/tests/test_get_repo_list_data.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/home/tests/test_get_user_data.py b/rhodecode/apps/home/tests/test_get_user_data.py --- a/rhodecode/apps/home/tests/test_get_user_data.py +++ b/rhodecode/apps/home/tests/test_get_user_data.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/home/tests/test_get_user_group_data.py b/rhodecode/apps/home/tests/test_get_user_group_data.py --- a/rhodecode/apps/home/tests/test_get_user_group_data.py +++ b/rhodecode/apps/home/tests/test_get_user_group_data.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -19,7 +19,7 @@ # and proprietary license terms, please see https://rhodecode.com/licenses/ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/home/tests/test_home.py b/rhodecode/apps/home/tests/test_home.py --- a/rhodecode/apps/home/tests/test_home.py +++ b/rhodecode/apps/home/tests/test_home.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/home/views.py b/rhodecode/apps/home/views.py --- a/rhodecode/apps/home/views.py +++ b/rhodecode/apps/home/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -46,7 +46,7 @@ class HomeView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() c.user = c.auth_user.get_instance() - self._register_global_c(c) + return c @LoginRequired() @@ -54,6 +54,7 @@ class HomeView(BaseAppView): route_name='user_autocomplete_data', request_method='GET', renderer='json_ext', xhr=True) def user_autocomplete_data(self): + self.load_default_context() query = self.request.GET.get('query') active = str2bool(self.request.GET.get('active') or True) include_groups = str2bool(self.request.GET.get('user_groups')) @@ -87,6 +88,7 @@ class HomeView(BaseAppView): route_name='user_group_autocomplete_data', request_method='GET', renderer='json_ext', xhr=True) def user_group_autocomplete_data(self): + self.load_default_context() query = self.request.GET.get('query') active = str2bool(self.request.GET.get('active') or True) expand_groups = str2bool(self.request.GET.get('user_groups_expand')) @@ -202,6 +204,7 @@ class HomeView(BaseAppView): renderer='json_ext', xhr=True) def repo_list_data(self): _ = self.request.translate + self.load_default_context() query = self.request.GET.get('query') repo_type = self.request.GET.get('repo_type') diff --git a/rhodecode/apps/journal/__init__.py b/rhodecode/apps/journal/__init__.py --- a/rhodecode/apps/journal/__init__.py +++ b/rhodecode/apps/journal/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/journal/tests/__init__.py b/rhodecode/apps/journal/tests/__init__.py --- a/rhodecode/apps/journal/tests/__init__.py +++ b/rhodecode/apps/journal/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/journal/tests/test_journal.py b/rhodecode/apps/journal/tests/test_journal.py --- a/rhodecode/apps/journal/tests/test_journal.py +++ b/rhodecode/apps/journal/tests/test_journal.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/journal/views.py b/rhodecode/apps/journal/views.py --- a/rhodecode/apps/journal/views.py +++ b/rhodecode/apps/journal/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -47,7 +47,7 @@ class JournalView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context(include_app_defaults=True) - self._register_global_c(c) + self._load_defaults(c.rhodecode_name) # TODO(marcink): what is this, why we need a global register ? @@ -146,7 +146,8 @@ class JournalView(BaseAppView): user = AttributeDict({'short_contact': entry.username, 'email': '', 'full_contact': ''}) - action, action_extra, ico = h.action_parser(entry, feed=True) + action, action_extra, ico = h.action_parser( + self.request, entry, feed=True) title = "%s - %s %s" % (user.short_contact, action(), entry.repository.repo_name) desc = action_extra() @@ -191,7 +192,8 @@ class JournalView(BaseAppView): user = AttributeDict({'short_contact': entry.username, 'email': '', 'full_contact': ''}) - action, action_extra, ico = h.action_parser(entry, feed=True) + action, action_extra, ico = h.action_parser( + self.request, entry, feed=True) title = "%s - %s %s" % (user.short_contact, action(), entry.repository.repo_name) desc = action_extra() diff --git a/rhodecode/apps/login/__init__.py b/rhodecode/apps/login/__init__.py --- a/rhodecode/apps/login/__init__.py +++ b/rhodecode/apps/login/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -19,7 +19,7 @@ # and proprietary license terms, please see https://rhodecode.com/licenses/ -from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.apps._base import ADMIN_PREFIX def includeme(config): diff --git a/rhodecode/apps/login/tests/test_login.py b/rhodecode/apps/login/tests/test_login.py --- a/rhodecode/apps/login/tests/test_login.py +++ b/rhodecode/apps/login/tests/test_login.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -30,7 +30,6 @@ from rhodecode.tests.fixture import Fixt from rhodecode.lib.auth import check_password from rhodecode.lib import helpers as h from rhodecode.model.auth_token import AuthTokenModel -from rhodecode.model import validators from rhodecode.model.db import User, Notification, UserApiKeys from rhodecode.model.meta import Session @@ -89,32 +88,31 @@ class TestLoginController(object): def test_login_admin_ok(self): response = self.app.post(route_path('login'), {'username': 'test_admin', - 'password': 'test12'}) - assert response.status == '302 Found' + 'password': 'test12'}, status=302) + response = response.follow() session = response.get_session_from_response() username = session['rhodecode_user'].get('username') assert username == 'test_admin' - response = response.follow() response.mustcontain('/%s' % HG_REPO) def test_login_regular_ok(self): response = self.app.post(route_path('login'), {'username': 'test_regular', - 'password': 'test12'}) + 'password': 'test12'}, status=302) - assert response.status == '302 Found' + response = response.follow() session = response.get_session_from_response() username = session['rhodecode_user'].get('username') assert username == 'test_regular' - response = response.follow() + response.mustcontain('/%s' % HG_REPO) def test_login_ok_came_from(self): test_came_from = '/_admin/users?branch=stable' _url = '{}?came_from={}'.format(route_path('login'), test_came_from) response = self.app.post( - _url, {'username': 'test_admin', 'password': 'test12'}) - assert response.status == '302 Found' + _url, {'username': 'test_admin', 'password': 'test12'}, status=302) + assert 'branch=stable' in response.location response = response.follow() @@ -125,8 +123,8 @@ class TestLoginController(object): with fixture.anon_access(False): kwargs = {'branch': 'stable'} response = self.app.get( - h.route_path('repo_summary', repo_name=HG_REPO, _query=kwargs)) - assert response.status == '302 Found' + h.route_path('repo_summary', repo_name=HG_REPO, _query=kwargs), + status=302) response_query = urlparse.parse_qsl(response.location) assert 'branch=stable' in response_query[0][1] @@ -201,13 +199,12 @@ class TestLoginController(object): self.destroy_users.add(temp_user) response = self.app.post(route_path('login'), {'username': temp_user, - 'password': 'test123'}) + 'password': 'test123'}, status=302) - assert response.status == '302 Found' + response = response.follow() session = response.get_session_from_response() username = session['rhodecode_user'].get('username') assert username == temp_user - response = response.follow() response.mustcontain('/%s' % HG_REPO) # new password should be bcrypted, after log-in and transfer @@ -234,7 +231,7 @@ class TestLoginController(object): ) assertr = response.assert_response() - msg = validators.ValidUsername()._messages['username_exists'] + msg = 'Username "%(username)s" already exists' msg = msg % {'username': uname} assertr.element_contains('#username+.error-message', msg) @@ -252,7 +249,7 @@ class TestLoginController(object): ) assertr = response.assert_response() - msg = validators.UniqSystemEmail()()._messages['email_taken'] + msg = u'This e-mail address is already taken' assertr.element_contains('#email+.error-message', msg) def test_register_err_same_email_case_sensitive(self): @@ -268,7 +265,7 @@ class TestLoginController(object): } ) assertr = response.assert_response() - msg = validators.UniqSystemEmail()()._messages['email_taken'] + msg = u'This e-mail address is already taken' assertr.element_contains('#email+.error-message', msg) def test_register_err_wrong_data(self): @@ -322,7 +319,7 @@ class TestLoginController(object): ) assertr = response.assert_response() - msg = validators.ValidUsername()._messages['username_exists'] + msg = u'Username "%(username)s" already exists' msg = msg % {'username': usr} assertr.element_contains('#username+.error-message', msg) @@ -339,7 +336,7 @@ class TestLoginController(object): } ) - msg = validators.ValidPassword()._messages['invalid_password'] + msg = u'Invalid characters (non-ascii) in password' response.mustcontain(msg) def test_register_password_mismatch(self): @@ -354,7 +351,7 @@ class TestLoginController(object): 'lastname': 'test' } ) - msg = validators.ValidPasswordsMatch()._messages['password_mismatch'] + msg = u'Passwords do not match' response.mustcontain(msg) def test_register_ok(self): @@ -364,6 +361,11 @@ class TestLoginController(object): name = 'testname' lastname = 'testlastname' + # this initializes a session + response = self.app.get(route_path('register')) + response.mustcontain('Create an Account') + + response = self.app.post( route_path('register'), { @@ -374,9 +376,10 @@ class TestLoginController(object): 'firstname': name, 'lastname': lastname, 'admin': True - } - ) # This should be overriden - assert response.status == '302 Found' + }, + status=302 + ) # This should be overridden + assert_session_flash( response, 'You have successfully registered with RhodeCode') @@ -392,6 +395,9 @@ class TestLoginController(object): def test_forgot_password_wrong_mail(self): bad_email = 'marcin@wrongmail.org' + # this initializes a session + self.app.get(route_path('reset_password')) + response = self.app.post( route_path('reset_password'), {'email': bad_email, } ) @@ -399,8 +405,8 @@ class TestLoginController(object): 'If such email exists, a password reset link was sent to it.') def test_forgot_password(self, user_util): - response = self.app.get(route_path('reset_password')) - assert response.status == '200 OK' + # this initializes a session + self.app.get(route_path('reset_password')) user = user_util.create_user() user_id = user.user_id @@ -413,8 +419,7 @@ class TestLoginController(object): # BAD KEY confirm_url = '{}?key={}'.format(route_path('reset_password_confirmation'), 'badkey') - response = self.app.get(confirm_url) - assert response.status == '302 Found' + response = self.app.get(confirm_url, status=302) assert response.location.endswith(route_path('reset_password')) assert_session_flash(response, 'Given reset token is invalid') diff --git a/rhodecode/apps/login/tests/test_password_reset.py b/rhodecode/apps/login/tests/test_password_reset.py --- a/rhodecode/apps/login/tests/test_password_reset.py +++ b/rhodecode/apps/login/tests/test_password_reset.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/login/tests/test_register_captcha.py b/rhodecode/apps/login/tests/test_register_captcha.py --- a/rhodecode/apps/login/tests/test_register_captcha.py +++ b/rhodecode/apps/login/tests/test_register_captcha.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -22,10 +22,10 @@ import mock import pytest +from rhodecode.apps._base import ADMIN_PREFIX from rhodecode.apps.login.views import LoginView, CaptchaData -from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.model.settings import SettingsModel from rhodecode.lib.utils2 import AttributeDict -from rhodecode.model.settings import SettingsModel from rhodecode.tests.utils import AssertResponse @@ -58,7 +58,7 @@ class TestRegisterCaptcha(object): ('privkey', '', CaptchaData(True, 'privkey', '')), ('privkey', 'pubkey', CaptchaData(True, 'privkey', 'pubkey')), ]) - def test_get_captcha_data(self, private_key, public_key, expected, db, + def test_get_captcha_data(self, private_key, public_key, expected, request_stub, user_util): request_stub.user = user_util.create_user().AuthUser() request_stub.matched_route = AttributeDict({'name': 'login'}) diff --git a/rhodecode/apps/login/views.py b/rhodecode/apps/login/views.py --- a/rhodecode/apps/login/views.py +++ b/rhodecode/apps/login/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -32,7 +32,7 @@ from recaptcha.client.captcha import sub from rhodecode.apps._base import BaseAppView from rhodecode.authentication.base import authenticate, HTTP_TYPE -from rhodecode.events import UserRegistered +from rhodecode.events import UserRegistered, trigger from rhodecode.lib import helpers as h from rhodecode.lib import audit_logger from rhodecode.lib.auth import ( @@ -113,7 +113,7 @@ class LoginView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() c.came_from = get_came_from(self.request) - self._register_global_c(c) + return c def _get_captcha_data(self): @@ -147,7 +147,7 @@ class LoginView(BaseAppView): raise HTTPFound(c.came_from, headers=headers) except UserCreationError as e: log.error(e) - self.session.flash(e, queue='error') + h.flash(e, category='error') return self._get_template_context(c) @@ -157,7 +157,7 @@ class LoginView(BaseAppView): def login_post(self): c = self.load_default_context() - login_form = LoginForm()() + login_form = LoginForm(self.request.translate)() try: self.session.invalidate() @@ -182,11 +182,10 @@ class LoginView(BaseAppView): defaults = errors.value # remove password from filling in form again defaults.pop('password', None) - render_ctx = self._get_template_context(c) - render_ctx.update({ + render_ctx = { 'errors': errors.error_dict, 'defaults': defaults, - }) + } audit_user = audit_logger.UserWrap( username=self.request.POST.get('username'), @@ -195,14 +194,14 @@ class LoginView(BaseAppView): audit_logger.store_web( 'user.login.failure', action_data=action_data, user=audit_user, commit=True) - return render_ctx + return self._get_template_context(c, **render_ctx) except UserCreationError as e: # headers auth or other auth functions that create users on # the fly can throw this exception signaling that there's issue # with user creation, explanation should be provided in # Exception itself - self.session.flash(e, queue='error') + h.flash(e, category='error') return self._get_template_context(c) @CSRFRequired() @@ -251,11 +250,12 @@ class LoginView(BaseAppView): route_name='register', request_method='POST', renderer='rhodecode:templates/register.mako') def register_post(self): + self.load_default_context() captcha = self._get_captcha_data() auto_active = 'hg.register.auto_activate' in User.get_default_user()\ .AuthUser().permissions['global'] - register_form = RegisterForm()() + register_form = RegisterForm(self.request.translate)() try: form_result = register_form.to_python(self.request.POST) @@ -275,11 +275,18 @@ class LoginView(BaseAppView): error_dict=error_dict) new_user = UserModel().create_registration(form_result) + + action_data = {'data': new_user.get_api_data(), + 'user_agent': self.request.user_agent} + audit_logger.store_web( + 'user.register', action_data=action_data, + user=new_user) + event = UserRegistered(user=new_user, session=self.session) - self.request.registry.notify(event) - self.session.flash( + trigger(event) + h.flash( _('You have successfully registered with RhodeCode'), - queue='success') + category='success') Session().commit() redirect_ro = self.request.route_path('login') @@ -296,16 +303,17 @@ class LoginView(BaseAppView): # the fly can throw this exception signaling that there's issue # with user creation, explanation should be provided in # Exception itself - self.session.flash(e, queue='error') + h.flash(e, category='error') return self.register() @view_config( route_name='reset_password', request_method=('GET', 'POST'), renderer='rhodecode:templates/password_reset.mako') def password_reset(self): + c = self.load_default_context() captcha = self._get_captcha_data() - render_ctx = { + template_context = { 'captcha_active': captcha.active, 'captcha_public_key': captcha.public_key, 'defaults': {}, @@ -320,11 +328,11 @@ class LoginView(BaseAppView): if h.HasPermissionAny('hg.password_reset.disabled')(): _email = self.request.POST.get('email', '') log.error('Failed attempt to reset password for `%s`.', _email) - self.session.flash(_('Password reset has been disabled.'), - queue='error') + h.flash(_('Password reset has been disabled.'), + category='error') return HTTPFound(self.request.route_path('reset_password')) - password_reset_form = PasswordResetForm()() + password_reset_form = PasswordResetForm(self.request.translate)() try: form_result = password_reset_form.to_python( self.request.POST) @@ -362,7 +370,7 @@ class LoginView(BaseAppView): UserModel().reset_password_link( form_result, password_reset_url) # Display success message and redirect. - self.session.flash(msg, queue='success') + h.flash(msg, category='success') action_data = {'email': user_email, 'user_agent': self.request.user_agent} @@ -372,30 +380,30 @@ class LoginView(BaseAppView): return HTTPFound(self.request.route_path('reset_password')) except formencode.Invalid as errors: - render_ctx.update({ + template_context.update({ 'defaults': errors.value, 'errors': errors.error_dict, }) if not self.request.POST.get('email'): # case of empty email, we want to report that - return render_ctx + return self._get_template_context(c, **template_context) if 'recaptcha_field' in errors.error_dict: # case of failed captcha - return render_ctx + return self._get_template_context(c, **template_context) log.debug('faking response on invalid password reset') # make this take 2s, to prevent brute forcing. time.sleep(2) - self.session.flash(msg, queue='success') + h.flash(msg, category='success') return HTTPFound(self.request.route_path('reset_password')) - return render_ctx + return self._get_template_context(c, **template_context) @view_config(route_name='reset_password_confirmation', request_method='GET') def password_reset_confirmation(self): - + self.load_default_context() if self.request.GET and self.request.GET.get('key'): # make this take 2s, to prevent brute forcing. time.sleep(2) @@ -408,18 +416,18 @@ class LoginView(BaseAppView): log.debug('Got token with role:%s expected is %s', getattr(token, 'role', 'EMPTY_TOKEN'), UserApiKeys.ROLE_PASSWORD_RESET) - self.session.flash( - _('Given reset token is invalid'), queue='error') + h.flash( + _('Given reset token is invalid'), category='error') return HTTPFound(self.request.route_path('reset_password')) try: owner = token.user data = {'email': owner.email, 'token': token.api_key} UserModel().reset_password(data) - self.session.flash( + h.flash( _('Your password reset was successful, ' 'a new password has been sent to your email'), - queue='success') + category='success') except Exception as e: log.error(e) return HTTPFound(self.request.route_path('reset_password')) diff --git a/rhodecode/apps/my_account/__init__.py b/rhodecode/apps/my_account/__init__.py --- a/rhodecode/apps/my_account/__init__.py +++ b/rhodecode/apps/my_account/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -70,6 +70,11 @@ def includeme(config): name='my_account_ssh_keys_delete', pattern=ADMIN_PREFIX + '/my_account/ssh_keys/delete') + # my account user group membership + config.add_route( + name='my_account_user_group_membership', + pattern=ADMIN_PREFIX + '/my_account/user_group_membership') + # my account emails config.add_route( name='my_account_emails', diff --git a/rhodecode/apps/my_account/tests/__init__.py b/rhodecode/apps/my_account/tests/__init__.py --- a/rhodecode/apps/my_account/tests/__init__.py +++ b/rhodecode/apps/my_account/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py b/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py --- a/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py +++ b/rhodecode/apps/my_account/tests/test_my_account_auth_tokens.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/my_account/tests/test_my_account_edit.py b/rhodecode/apps/my_account/tests/test_my_account_edit.py --- a/rhodecode/apps/my_account/tests/test_my_account_edit.py +++ b/rhodecode/apps/my_account/tests/test_my_account_edit.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -19,7 +19,7 @@ # and proprietary license terms, please see https://rhodecode.com/licenses/ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -198,8 +198,6 @@ class TestMyAccountEdit(TestController): params=params) response.mustcontain('An email address must contain a single @') - from rhodecode.model import validators - msg = validators.ValidUsername( - edit=False, old_data={})._messages['username_exists'] + msg = u'Username "%(username)s" already exists' msg = h.html_escape(msg % {'username': 'test_admin'}) response.mustcontain(u"%s" % msg) diff --git a/rhodecode/apps/my_account/tests/test_my_account_emails.py b/rhodecode/apps/my_account/tests/test_my_account_emails.py --- a/rhodecode/apps/my_account/tests/test_my_account_emails.py +++ b/rhodecode/apps/my_account/tests/test_my_account_emails.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/my_account/tests/test_my_account_notifications.py b/rhodecode/apps/my_account/tests/test_my_account_notifications.py --- a/rhodecode/apps/my_account/tests/test_my_account_notifications.py +++ b/rhodecode/apps/my_account/tests/test_my_account_notifications.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/my_account/tests/test_my_account_password.py b/rhodecode/apps/my_account/tests/test_my_account_password.py --- a/rhodecode/apps/my_account/tests/test_my_account_password.py +++ b/rhodecode/apps/my_account/tests/test_my_account_password.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/my_account/tests/test_my_account_profile.py b/rhodecode/apps/my_account/tests/test_my_account_profile.py --- a/rhodecode/apps/my_account/tests/test_my_account_profile.py +++ b/rhodecode/apps/my_account/tests/test_my_account_profile.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/my_account/tests/test_my_account_simple_views.py b/rhodecode/apps/my_account/tests/test_my_account_simple_views.py --- a/rhodecode/apps/my_account/tests/test_my_account_simple_views.py +++ b/rhodecode/apps/my_account/tests/test_my_account_simple_views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/my_account/tests/test_my_account_ssh_keys.py b/rhodecode/apps/my_account/tests/test_my_account_ssh_keys.py --- a/rhodecode/apps/my_account/tests/test_my_account_ssh_keys.py +++ b/rhodecode/apps/my_account/tests/test_my_account_ssh_keys.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/my_account/views/__init__.py b/rhodecode/apps/my_account/views/__init__.py --- a/rhodecode/apps/my_account/views/__init__.py +++ b/rhodecode/apps/my_account/views/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/apps/my_account/views/my_account.py b/rhodecode/apps/my_account/views/my_account.py --- a/rhodecode/apps/my_account/views/my_account.py +++ b/rhodecode/apps/my_account/views/my_account.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -42,12 +42,13 @@ from rhodecode.model.comment import Comm from rhodecode.model.db import ( Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload, PullRequest) -from rhodecode.model.forms import UserForm +from rhodecode.model.forms import UserForm, UserExtraEmailForm from rhodecode.model.meta import Session from rhodecode.model.pull_request import PullRequestModel from rhodecode.model.scm import RepoList from rhodecode.model.user import UserModel from rhodecode.model.repo import RepoModel +from rhodecode.model.user_group import UserGroupModel from rhodecode.model.validation_schema.schemas import user_schema log = logging.getLogger(__name__) @@ -64,7 +65,7 @@ class MyAccountView(BaseAppView, DataGri c = self._get_local_tmpl_context() c.user = c.auth_user.get_instance() c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS - self._register_global_c(c) + return c @LoginRequired() @@ -245,6 +246,10 @@ class MyAccountView(BaseAppView, DataGri email = self.request.POST.get('new_email') try: + form = UserExtraEmailForm(self.request.translate)() + data = form.to_python({'email': email}) + email = data['email'] + UserModel().add_extra_email(c.user.user_id, email) audit_logger.store_web( 'user.edit.email.add', action_data={ @@ -442,7 +447,7 @@ class MyAccountView(BaseAppView, DataGri c.extern_type = c.user.extern_type c.extern_name = c.user.extern_name - _form = UserForm(edit=True, + _form = UserForm(self.request.translate, edit=True, old_data={'user_id': self._rhodecode_user.user_id, 'email': self._rhodecode_user.email})() form_result = {} @@ -492,7 +497,7 @@ class MyAccountView(BaseAppView, DataGri draw, start, limit = self._extract_chunk(self.request) search_q, order_by, order_dir = self._extract_ordering(self.request) _render = self.request.get_partial_renderer( - 'data_table/_dt_elements.mako') + 'rhodecode:templates/data_table/_dt_elements.mako') pull_requests = PullRequestModel().get_im_participating_in( user_id=self._rhodecode_user.user_id, @@ -568,6 +573,7 @@ class MyAccountView(BaseAppView, DataGri route_name='my_account_pullrequests_data', request_method='GET', renderer='json_ext') def my_account_pullrequests_data(self): + self.load_default_context() req_get = self.request.GET closed = str2bool(req_get.get('closed')) @@ -578,3 +584,16 @@ class MyAccountView(BaseAppView, DataGri data = self._get_pull_requests_list(statuses=statuses) return data + @LoginRequired() + @NotAnonymous() + @view_config( + route_name='my_account_user_group_membership', + request_method='GET', + renderer='rhodecode:templates/admin/my_account/my_account.mako') + def my_account_user_group_membership(self): + c = self.load_default_context() + c.active = 'user_group_membership' + groups = [UserGroupModel.get_user_groups_as_dict(group.users_group) + for group in self._rhodecode_db_user.group_member] + c.user_groups = json.dumps(groups) + return self._get_template_context(c) diff --git a/rhodecode/apps/my_account/views/my_account_notifications.py b/rhodecode/apps/my_account/views/my_account_notifications.py --- a/rhodecode/apps/my_account/views/my_account_notifications.py +++ b/rhodecode/apps/my_account/views/my_account_notifications.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -43,7 +43,7 @@ class MyAccountNotificationsView(BaseApp def load_default_context(self): c = self._get_local_tmpl_context() c.user = c.auth_user.get_instance() - self._register_global_c(c) + return c def _has_permissions(self, notification): diff --git a/rhodecode/apps/my_account/views/my_account_ssh_keys.py b/rhodecode/apps/my_account/views/my_account_ssh_keys.py --- a/rhodecode/apps/my_account/views/my_account_ssh_keys.py +++ b/rhodecode/apps/my_account/views/my_account_ssh_keys.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -44,7 +44,7 @@ class MyAccountSshKeysView(BaseAppView, c.ssh_enabled = self.request.registry.settings.get( 'ssh.generate_authorized_keyfile') - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/ops/__init__.py b/rhodecode/apps/ops/__init__.py --- a/rhodecode/apps/ops/__init__.py +++ b/rhodecode/apps/ops/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -18,7 +18,7 @@ # RhodeCode Enterprise Edition, including its added features, Support services, # and proprietary license terms, please see https://rhodecode.com/licenses/ -from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.apps._base import ADMIN_PREFIX def admin_routes(config): @@ -36,7 +36,7 @@ def admin_routes(config): def includeme(config): config.include(admin_routes, route_prefix=ADMIN_PREFIX + '/ops') - # make OLD entries from pylons work + # make OLD entries from <4.10.0 work config.add_route( name='ops_ping_legacy', pattern=ADMIN_PREFIX + '/ping') config.add_route( diff --git a/rhodecode/apps/ops/views.py b/rhodecode/apps/ops/views.py --- a/rhodecode/apps/ops/views.py +++ b/rhodecode/apps/ops/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -35,7 +35,7 @@ class OpsView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() c.user = c.auth_user.get_instance() - self._register_global_c(c) + return c @view_config( diff --git a/rhodecode/apps/repo_group/__init__.py b/rhodecode/apps/repo_group/__init__.py --- a/rhodecode/apps/repo_group/__init__.py +++ b/rhodecode/apps/repo_group/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/repo_group/tests/__init__.py b/rhodecode/apps/repo_group/tests/__init__.py --- a/rhodecode/apps/repo_group/tests/__init__.py +++ b/rhodecode/apps/repo_group/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repo_group/tests/test_repo_groups_advanced.py b/rhodecode/apps/repo_group/tests/test_repo_groups_advanced.py --- a/rhodecode/apps/repo_group/tests/test_repo_groups_advanced.py +++ b/rhodecode/apps/repo_group/tests/test_repo_groups_advanced.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repo_group/tests/test_repo_groups_permissions.py b/rhodecode/apps/repo_group/tests/test_repo_groups_permissions.py --- a/rhodecode/apps/repo_group/tests/test_repo_groups_permissions.py +++ b/rhodecode/apps/repo_group/tests/test_repo_groups_permissions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repo_group/tests/test_repo_groups_settings.py b/rhodecode/apps/repo_group/tests/test_repo_groups_settings.py --- a/rhodecode/apps/repo_group/tests/test_repo_groups_settings.py +++ b/rhodecode/apps/repo_group/tests/test_repo_groups_settings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repo_group/views/__init__.py b/rhodecode/apps/repo_group/views/__init__.py --- a/rhodecode/apps/repo_group/views/__init__.py +++ b/rhodecode/apps/repo_group/views/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/repo_group/views/repo_group_advanced.py b/rhodecode/apps/repo_group/views/repo_group_advanced.py --- a/rhodecode/apps/repo_group/views/repo_group_advanced.py +++ b/rhodecode/apps/repo_group/views/repo_group_advanced.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -37,7 +37,7 @@ log = logging.getLogger(__name__) class RepoGroupSettingsView(RepoGroupAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/repo_group/views/repo_group_permissions.py b/rhodecode/apps/repo_group/views/repo_group_permissions.py --- a/rhodecode/apps/repo_group/views/repo_group_permissions.py +++ b/rhodecode/apps/repo_group/views/repo_group_permissions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -38,7 +38,7 @@ log = logging.getLogger(__name__) class RepoGroupPermissionsView(RepoGroupAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() @@ -65,7 +65,7 @@ class RepoGroupPermissionsView(RepoGroup c.repo_group = self.db_repo_group valid_recursive_choices = ['none', 'repos', 'groups', 'all'] - form = RepoGroupPermsForm(valid_recursive_choices)()\ + form = RepoGroupPermsForm(self.request.translate, valid_recursive_choices)()\ .to_python(self.request.POST) if not c.rhodecode_user.is_admin: diff --git a/rhodecode/apps/repo_group/views/repo_group_settings.py b/rhodecode/apps/repo_group/views/repo_group_settings.py --- a/rhodecode/apps/repo_group/views/repo_group_settings.py +++ b/rhodecode/apps/repo_group/views/repo_group_settings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -73,7 +73,7 @@ class RepoGroupSettingsView(RepoGroupApp c.repo_groups_choices.append(parent_group.group_id) c.repo_groups.append(RepoGroup._generate_choice(parent_group)) - self._register_global_c(c) + return c def _can_create_repo_group(self, parent_group_id=None): diff --git a/rhodecode/apps/repository/__init__.py b/rhodecode/apps/repository/__init__.py --- a/rhodecode/apps/repository/__init__.py +++ b/rhodecode/apps/repository/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/repository/tests/__init__.py b/rhodecode/apps/repository/tests/__init__.py --- a/rhodecode/apps/repository/tests/__init__.py +++ b/rhodecode/apps/repository/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_pull_requests_list.py b/rhodecode/apps/repository/tests/test_pull_requests_list.py --- a/rhodecode/apps/repository/tests/test_pull_requests_list.py +++ b/rhodecode/apps/repository/tests/test_pull_requests_list.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_bookmarks.py b/rhodecode/apps/repository/tests/test_repo_bookmarks.py --- a/rhodecode/apps/repository/tests/test_repo_bookmarks.py +++ b/rhodecode/apps/repository/tests/test_repo_bookmarks.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_branches.py b/rhodecode/apps/repository/tests/test_repo_branches.py --- a/rhodecode/apps/repository/tests/test_repo_branches.py +++ b/rhodecode/apps/repository/tests/test_repo_branches.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_changelog.py b/rhodecode/apps/repository/tests/test_repo_changelog.py --- a/rhodecode/apps/repository/tests/test_repo_changelog.py +++ b/rhodecode/apps/repository/tests/test_repo_changelog.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_commit_comments.py b/rhodecode/apps/repository/tests/test_repo_commit_comments.py --- a/rhodecode/apps/repository/tests/test_repo_commit_comments.py +++ b/rhodecode/apps/repository/tests/test_repo_commit_comments.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -47,7 +47,7 @@ def route_path(name, params=None, **kwar class TestRepoCommitCommentsView(TestController): @pytest.fixture(autouse=True) - def prepare(self, request, pylonsapp): + def prepare(self, request, baseapp): for x in ChangesetComment.query().all(): Session().delete(x) Session().commit() diff --git a/rhodecode/apps/repository/tests/test_repo_commits.py b/rhodecode/apps/repository/tests/test_repo_commits.py --- a/rhodecode/apps/repository/tests/test_repo_commits.py +++ b/rhodecode/apps/repository/tests/test_repo_commits.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_compare.py b/rhodecode/apps/repository/tests/test_repo_compare.py --- a/rhodecode/apps/repository/tests/test_repo_compare.py +++ b/rhodecode/apps/repository/tests/test_repo_compare.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_compare_local.py b/rhodecode/apps/repository/tests/test_repo_compare_local.py --- a/rhodecode/apps/repository/tests/test_repo_compare_local.py +++ b/rhodecode/apps/repository/tests/test_repo_compare_local.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py b/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py --- a/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py +++ b/rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_feed.py b/rhodecode/apps/repository/tests/test_repo_feed.py --- a/rhodecode/apps/repository/tests/test_repo_feed.py +++ b/rhodecode/apps/repository/tests/test_repo_feed.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_files.py b/rhodecode/apps/repository/tests/test_repo_files.py --- a/rhodecode/apps/repository/tests/test_repo_files.py +++ b/rhodecode/apps/repository/tests/test_repo_files.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -48,6 +48,7 @@ def route_path(name, params=None, **kwar import urllib base_url = { + 'repo_summary': '/{repo_name}', 'repo_archivefile': '/{repo_name}/archive/{fname}', 'repo_files_diff': '/{repo_name}/diff/{f_path}', 'repo_files_diff_2way_redirect': '/{repo_name}/diff-2way/{f_path}', @@ -999,8 +1000,11 @@ class TestFilesViewOtherCases(object): .format(repo_file_add_url)) def test_access_empty_repo_redirect_to_summary_with_alert_no_write_perms( - self, backend_stub, user_util): + self, backend_stub, autologin_regular_user): repo = backend_stub.create_repo() + # init session for anon user + route_path('repo_summary', repo_name=repo.repo_name) + repo_file_add_url = route_path( 'repo_files_add_file', repo_name=repo.repo_name, diff --git a/rhodecode/apps/repository/tests/test_repo_forks.py b/rhodecode/apps/repository/tests/test_repo_forks.py --- a/rhodecode/apps/repository/tests/test_repo_forks.py +++ b/rhodecode/apps/repository/tests/test_repo_forks.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_issue_tracker.py b/rhodecode/apps/repository/tests/test_repo_issue_tracker.py --- a/rhodecode/apps/repository/tests/test_repo_issue_tracker.py +++ b/rhodecode/apps/repository/tests/test_repo_issue_tracker.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -58,11 +58,11 @@ class TestRepoIssueTracker(object): 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name) post_data = { 'new_pattern_pattern_0': pattern, - 'new_pattern_url_0': 'url', + 'new_pattern_url_0': 'http://url', 'new_pattern_prefix_0': 'prefix', 'new_pattern_description_0': 'description', 'new_pattern_pattern_1': another_pattern, - 'new_pattern_url_1': 'url1', + 'new_pattern_url_1': '/url1', 'new_pattern_prefix_1': 'prefix1', 'new_pattern_description_1': 'description1', 'csrf_token': csrf_token @@ -84,7 +84,7 @@ class TestRepoIssueTracker(object): extra_environ=xhr_header, params=data) assert response.body == \ - 'example of prefix replacement' + 'example of prefix replacement' @request.addfinalizer def cleanup(): @@ -106,7 +106,7 @@ class TestRepoIssueTracker(object): 'edit_repo_issuetracker_update', repo_name=backend.repo.repo_name) post_data = { 'new_pattern_pattern_0': pattern, - 'new_pattern_url_0': 'url', + 'new_pattern_url_0': '/url', 'new_pattern_prefix_0': 'prefix', 'new_pattern_description_0': 'description', 'uid': old_uid, diff --git a/rhodecode/apps/repository/tests/test_repo_pullrequests.py b/rhodecode/apps/repository/tests/test_repo_pullrequests.py --- a/rhodecode/apps/repository/tests/test_repo_pullrequests.py +++ b/rhodecode/apps/repository/tests/test_repo_pullrequests.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -199,18 +199,17 @@ class TestPullrequestsView(object): def test_edit_title_description_closed(self, pr_util, csrf_token): pull_request = pr_util.create_pull_request() pull_request_id = pull_request.pull_request_id + repo_name = pull_request.target_repo.repo_name pr_util.close() response = self.app.post( route_path('pullrequest_update', - repo_name=pull_request.target_repo.repo_name, - pull_request_id=pull_request_id), + repo_name=repo_name, pull_request_id=pull_request_id), params={ 'edit_pull_request': 'true', 'title': 'New title', 'description': 'New description', - 'csrf_token': csrf_token}) - + 'csrf_token': csrf_token}, status=200) assert_session_flash( response, u'Cannot update closed pull requests.', category='error') @@ -300,7 +299,7 @@ class TestPullrequestsView(object): pull_request = pr_util.create_pull_request() pull_request_id = pull_request.pull_request_id PullRequestModel().update_reviewers( - pull_request_id, [(1, ['reason'], False), (2, ['reason2'], False)], + pull_request_id, [(1, ['reason'], False, []), (2, ['reason2'], False, [])], pull_request.author) author = pull_request.user_id repo = pull_request.target_repo.repo_id @@ -377,6 +376,8 @@ class TestPullrequestsView(object): ('__start__', 'reasons:sequence'), ('reason', 'Some reason'), ('__end__', 'reasons:sequence'), + ('__start__', 'rules:sequence'), + ('__end__', 'rules:sequence'), ('mandatory', 'False'), ('__end__', 'reviewer:mapping'), ('__end__', 'review_members:sequence'), @@ -434,6 +435,8 @@ class TestPullrequestsView(object): ('__start__', 'reasons:sequence'), ('reason', 'Some reason'), ('__end__', 'reasons:sequence'), + ('__start__', 'rules:sequence'), + ('__end__', 'rules:sequence'), ('mandatory', 'False'), ('__end__', 'reviewer:mapping'), ('__end__', 'review_members:sequence'), @@ -461,7 +464,7 @@ class TestPullrequestsView(object): # Change reviewers and check that a notification was made PullRequestModel().update_reviewers( - pull_request.pull_request_id, [(1, [], False)], + pull_request.pull_request_id, [(1, [], False, [])], pull_request.author) assert len(notifications.all()) == 2 @@ -498,6 +501,8 @@ class TestPullrequestsView(object): ('__start__', 'reasons:sequence'), ('reason', 'Some reason'), ('__end__', 'reasons:sequence'), + ('__start__', 'rules:sequence'), + ('__end__', 'rules:sequence'), ('mandatory', 'False'), ('__end__', 'reviewer:mapping'), ('__end__', 'review_members:sequence'), diff --git a/rhodecode/apps/repository/tests/test_repo_settings.py b/rhodecode/apps/repository/tests/test_repo_settings.py --- a/rhodecode/apps/repository/tests/test_repo_settings.py +++ b/rhodecode/apps/repository/tests/test_repo_settings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_settings_advanced.py b/rhodecode/apps/repository/tests/test_repo_settings_advanced.py --- a/rhodecode/apps/repository/tests/test_repo_settings_advanced.py +++ b/rhodecode/apps/repository/tests/test_repo_settings_advanced.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_summary.py b/rhodecode/apps/repository/tests/test_repo_summary.py --- a/rhodecode/apps/repository/tests/test_repo_summary.py +++ b/rhodecode/apps/repository/tests/test_repo_summary.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -56,6 +56,16 @@ def route_path(name, params=None, **kwar return base_url +def assert_clone_url(response, server, repo, disabled=False): + + response.mustcontain( + ''.format( + server=server, repo=repo, disabled='disabled ' if disabled else ' ') + ) + + @pytest.mark.usefixtures('app') class TestSummaryView(object): def test_index(self, autologin_user, backend, http_host_only_stub): @@ -76,12 +86,8 @@ class TestSummaryView(object): ) # clone url... - response.mustcontain( - 'id="clone_url" readonly="readonly"' - ' value="http://test_admin@%s/%s"' % (http_host_only_stub, repo_name, )) - response.mustcontain( - 'id="clone_url_id" readonly="readonly"' - ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, )) + assert_clone_url(response, http_host_only_stub, repo_name) + assert_clone_url(response, http_host_only_stub, '_{}'.format(repo_id)) def test_index_svn_without_proxy( self, autologin_user, backend_svn, http_host_only_stub): @@ -89,12 +95,9 @@ class TestSummaryView(object): repo_name = backend_svn.repo_name response = self.app.get(route_path('repo_summary', repo_name=repo_name)) # clone url... - response.mustcontain( - 'id="clone_url" disabled' - ' value="http://test_admin@%s/%s"' % (http_host_only_stub, repo_name, )) - response.mustcontain( - 'id="clone_url_id" disabled' - ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, )) + + assert_clone_url(response, http_host_only_stub, repo_name, disabled=True) + assert_clone_url(response, http_host_only_stub, '_{}'.format(repo_id), disabled=True) def test_index_with_trailing_slash( self, autologin_user, backend, http_host_only_stub): @@ -108,12 +111,8 @@ class TestSummaryView(object): status=200) # clone url... - response.mustcontain( - 'id="clone_url" readonly="readonly"' - ' value="http://test_admin@%s/%s"' % (http_host_only_stub, repo_name, )) - response.mustcontain( - 'id="clone_url_id" readonly="readonly"' - ' value="http://test_admin@%s/_%s"' % (http_host_only_stub, repo_id, )) + assert_clone_url(response, http_host_only_stub, repo_name) + assert_clone_url(response, http_host_only_stub, '_{}'.format(repo_id)) def test_index_by_id(self, autologin_user, backend): repo_id = backend.repo.repo_id diff --git a/rhodecode/apps/repository/tests/test_repo_tags.py b/rhodecode/apps/repository/tests/test_repo_tags.py --- a/rhodecode/apps/repository/tests/test_repo_tags.py +++ b/rhodecode/apps/repository/tests/test_repo_tags.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_repo_vcs_settings.py b/rhodecode/apps/repository/tests/test_repo_vcs_settings.py --- a/rhodecode/apps/repository/tests/test_repo_vcs_settings.py +++ b/rhodecode/apps/repository/tests/test_repo_vcs_settings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/tests/test_vcs_settings.py b/rhodecode/apps/repository/tests/test_vcs_settings.py --- a/rhodecode/apps/repository/tests/test_vcs_settings.py +++ b/rhodecode/apps/repository/tests/test_vcs_settings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/repository/utils.py b/rhodecode/apps/repository/utils.py --- a/rhodecode/apps/repository/utils.py +++ b/rhodecode/apps/repository/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -22,7 +22,7 @@ from rhodecode.lib import helpers as h from rhodecode.lib.utils2 import safe_int -def reviewer_as_json(user, reasons=None, mandatory=False): +def reviewer_as_json(user, reasons=None, mandatory=False, rules=None, user_group=None): """ Returns json struct of a reviewer for frontend @@ -34,10 +34,13 @@ def reviewer_as_json(user, reasons=None, return { 'user_id': user.user_id, 'reasons': reasons or [], + 'rules': rules or [], 'mandatory': mandatory, + 'user_group': user_group, 'username': user.username, 'first_name': user.first_name, 'last_name': user.last_name, + 'user_link': h.link_to_user(user), 'gravatar_link': h.gravatar_url(user.email, 14), } @@ -68,7 +71,7 @@ def validate_default_reviewers(review_me reviewer_by_id = {} for r in review_members: reviewer_user_id = safe_int(r['user_id']) - entry = (reviewer_user_id, r['reasons'], r['mandatory']) + entry = (reviewer_user_id, r['reasons'], r['mandatory'], r['rules']) reviewer_by_id[reviewer_user_id] = entry reviewers.append(entry) diff --git a/rhodecode/apps/repository/views/__init__.py b/rhodecode/apps/repository/views/__init__.py --- a/rhodecode/apps/repository/views/__init__.py +++ b/rhodecode/apps/repository/views/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/apps/repository/views/repo_audit_logs.py b/rhodecode/apps/repository/views/repo_audit_logs.py --- a/rhodecode/apps/repository/views/repo_audit_logs.py +++ b/rhodecode/apps/repository/views/repo_audit_logs.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2017-2017 RhodeCode GmbH +# Copyright (C) 2017-2018 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 @@ -34,7 +34,7 @@ class AuditLogsView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/repository/views/repo_bookmarks.py b/rhodecode/apps/repository/views/repo_bookmarks.py --- a/rhodecode/apps/repository/views/repo_bookmarks.py +++ b/rhodecode/apps/repository/views/repo_bookmarks.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/apps/repository/views/repo_branches.py b/rhodecode/apps/repository/views/repo_branches.py --- a/rhodecode/apps/repository/views/repo_branches.py +++ b/rhodecode/apps/repository/views/repo_branches.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/apps/repository/views/repo_caches.py b/rhodecode/apps/repository/views/repo_caches.py --- a/rhodecode/apps/repository/views/repo_caches.py +++ b/rhodecode/apps/repository/views/repo_caches.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -37,7 +37,7 @@ class RepoCachesView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/repository/views/repo_changelog.py b/rhodecode/apps/repository/views/repo_changelog.py --- a/rhodecode/apps/repository/views/repo_changelog.py +++ b/rhodecode/apps/repository/views/repo_changelog.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -159,7 +159,7 @@ class RepoChangelogView(RepoAppView): c = self._get_local_tmpl_context(include_app_defaults=True) c.rhodecode_repo = self.rhodecode_vcs_repo - self._register_global_c(c) + return c def _get_preload_attrs(self): diff --git a/rhodecode/apps/repository/views/repo_checks.py b/rhodecode/apps/repository/views/repo_checks.py --- a/rhodecode/apps/repository/views/repo_checks.py +++ b/rhodecode/apps/repository/views/repo_checks.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -34,7 +34,7 @@ log = logging.getLogger(__name__) class RepoChecksView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @NotAnonymous() @@ -78,10 +78,15 @@ class RepoChecksView(BaseAppView): if task_id and task_id not in ['None']: import rhodecode - from celery.result import AsyncResult + from rhodecode.lib.celerylib.loader import celery_app, exceptions if rhodecode.CELERY_ENABLED: - task = AsyncResult(task_id) - if task.failed(): + log.debug('celery: checking result for task:%s', task_id) + task = celery_app.AsyncResult(task_id) + try: + task.get(timeout=10) + except exceptions.TimeoutError: + task = None + if task and task.failed(): msg = self._log_creation_exception(task.result, repo_name) h.flash(msg, category='error') raise HTTPFound(h.route_path('home'), code=501) diff --git a/rhodecode/apps/repository/views/repo_commits.py b/rhodecode/apps/repository/views/repo_commits.py --- a/rhodecode/apps/repository/views/repo_commits.py +++ b/rhodecode/apps/repository/views/repo_commits.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -150,7 +150,6 @@ class RepoCommitsView(RepoAppView): c = self._get_local_tmpl_context(include_app_defaults=True) c.rhodecode_repo = self.rhodecode_vcs_repo - self._register_global_c(c) return c def _commit(self, commit_id_range, method): diff --git a/rhodecode/apps/repository/views/repo_compare.py b/rhodecode/apps/repository/views/repo_compare.py --- a/rhodecode/apps/repository/views/repo_compare.py +++ b/rhodecode/apps/repository/views/repo_compare.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -47,7 +47,7 @@ class RepoCompareView(RepoAppView): c.rhodecode_repo = self.rhodecode_vcs_repo - self._register_global_c(c) + return c def _get_commit_or_redirect( diff --git a/rhodecode/apps/repository/views/repo_feed.py b/rhodecode/apps/repository/views/repo_feed.py --- a/rhodecode/apps/repository/views/repo_feed.py +++ b/rhodecode/apps/repository/views/repo_feed.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2017-2017 RhodeCode GmbH +# Copyright (C) 2017-2018 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 @@ -42,7 +42,7 @@ class RepoFeedView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + self._load_defaults() return c @@ -81,21 +81,22 @@ class RepoFeedView(RepoAppView): _parsed = diff_processor.prepare(inline_diff=False) limited_diff = isinstance(_parsed, LimitedDiffContainer) - return _parsed, limited_diff + return diff_processor, _parsed, limited_diff def _get_title(self, commit): return h.shorter(commit.message, 160) def _get_description(self, commit): _renderer = self.request.get_partial_renderer( - 'feed/atom_feed_entry.mako') - parsed_diff, limited_diff = self._changes(commit) + 'rhodecode:templates/feed/atom_feed_entry.mako') + diff_processor, parsed_diff, limited_diff = self._changes(commit) return _renderer( 'body', commit=commit, parsed_diff=parsed_diff, limited_diff=limited_diff, feed_include_diff=self.feed_include_diff, + diff_processor=diff_processor, ) def _set_timezone(self, date, tzinfo=pytz.utc): diff --git a/rhodecode/apps/repository/views/repo_files.py b/rhodecode/apps/repository/views/repo_files.py --- a/rhodecode/apps/repository/views/repo_files.py +++ b/rhodecode/apps/repository/views/repo_files.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -83,7 +83,7 @@ class RepoFilesView(RepoAppView): c.rhodecode_repo = self.rhodecode_vcs_repo - self._register_global_c(c) + return c def _ensure_not_locked(self): diff --git a/rhodecode/apps/repository/views/repo_forks.py b/rhodecode/apps/repository/views/repo_forks.py --- a/rhodecode/apps/repository/views/repo_forks.py +++ b/rhodecode/apps/repository/views/repo_forks.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -33,6 +33,7 @@ from rhodecode.lib.auth import ( LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired) import rhodecode.lib.helpers as h +from rhodecode.lib.celerylib.utils import get_task_id from rhodecode.model.db import coalesce, or_, Repository, RepoGroup from rhodecode.model.repo import RepoModel from rhodecode.model.forms import RepoForkForm @@ -53,11 +54,11 @@ class RepoForksView(RepoAppView, DataGri perm_set=['group.write', 'group.admin']) c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups) - choices, c.landing_revs = ScmModel().get_repo_landing_revs() + choices, c.landing_revs = ScmModel().get_repo_landing_revs( + self.request.translate) c.landing_revs_choices = choices c.personal_repo_group = c.rhodecode_user.personal_repo_group - self._register_global_c(c) return c @LoginRequired() @@ -78,6 +79,7 @@ class RepoForksView(RepoAppView, DataGri renderer='json_ext', xhr=True) def repo_forks_data(self): _ = self.request.translate + self.load_default_context() column_map = { 'fork_name': 'repo_name', 'fork_date': 'created_on', @@ -209,7 +211,7 @@ class RepoForksView(RepoAppView, DataGri _ = self.request.translate c = self.load_default_context() - _form = RepoForkForm(old_data={'repo_type': self.db_repo.repo_type}, + _form = RepoForkForm(self.request.translate, old_data={'repo_type': self.db_repo.repo_type}, repo_groups=c.repo_groups_choices, landing_revs=c.landing_revs_choices)() post_data = dict(self.request.POST) @@ -225,9 +227,8 @@ class RepoForksView(RepoAppView, DataGri # management is handled there. task = RepoModel().create_fork( form_result, c.rhodecode_user.user_id) - from celery.result import BaseAsyncResult - if isinstance(task, BaseAsyncResult): - task_id = task.task_id + + task_id = get_task_id(task) except formencode.Invalid as errors: c.rhodecode_db_repo = self.db_repo diff --git a/rhodecode/apps/repository/views/repo_maintainance.py b/rhodecode/apps/repository/views/repo_maintainance.py --- a/rhodecode/apps/repository/views/repo_maintainance.py +++ b/rhodecode/apps/repository/views/repo_maintainance.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -33,7 +33,7 @@ class RepoMaintenanceView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/repository/views/repo_permissions.py b/rhodecode/apps/repository/views/repo_permissions.py --- a/rhodecode/apps/repository/views/repo_permissions.py +++ b/rhodecode/apps/repository/views/repo_permissions.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -40,7 +40,7 @@ class RepoSettingsPermissionsView(RepoAp def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() @@ -68,7 +68,7 @@ class RepoSettingsPermissionsView(RepoAp # default user permissions, prevents submission of FAKE post data # into the form for private repos data['repo_private'] = self.db_repo.private - form = RepoPermsForm()().to_python(data) + form = RepoPermsForm(self.request.translate)().to_python(data) changes = RepoModel().update_permissions( self.db_repo_name, form['perm_additions'], form['perm_updates'], form['perm_deletions']) diff --git a/rhodecode/apps/repository/views/repo_pull_requests.py b/rhodecode/apps/repository/views/repo_pull_requests.py --- a/rhodecode/apps/repository/views/repo_pull_requests.py +++ b/rhodecode/apps/repository/views/repo_pull_requests.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -60,7 +60,7 @@ class RepoPullRequestsView(RepoAppView, c = self._get_local_tmpl_context(include_app_defaults=True) c.REVIEW_STATUS_APPROVED = ChangesetStatus.STATUS_APPROVED c.REVIEW_STATUS_REJECTED = ChangesetStatus.STATUS_REJECTED - self._register_global_c(c) + return c def _get_pull_requests_list( @@ -69,7 +69,7 @@ class RepoPullRequestsView(RepoAppView, draw, start, limit = self._extract_chunk(self.request) search_q, order_by, order_dir = self._extract_ordering(self.request) _render = self.request.get_partial_renderer( - 'data_table/_dt_elements.mako') + 'rhodecode:templates/data_table/_dt_elements.mako') # pagination @@ -173,6 +173,7 @@ class RepoPullRequestsView(RepoAppView, route_name='pullrequest_show_all_data', request_method='GET', renderer='json_ext', xhr=True) def pull_request_list_data(self): + self.load_default_context() # additional filters req_get = self.request.GET @@ -200,29 +201,6 @@ class RepoPullRequestsView(RepoAppView, return data - def _get_pr_version(self, pull_request_id, version=None): - at_version = None - - if version and version == 'latest': - pull_request_ver = PullRequest.get(pull_request_id) - pull_request_obj = pull_request_ver - _org_pull_request_obj = pull_request_obj - at_version = 'latest' - elif version: - pull_request_ver = PullRequestVersion.get_or_404(version) - pull_request_obj = pull_request_ver - _org_pull_request_obj = pull_request_ver.pull_request - at_version = pull_request_ver.pull_request_version_id - else: - _org_pull_request_obj = pull_request_obj = PullRequest.get_or_404( - pull_request_id) - - pull_request_display_obj = PullRequest.get_pr_display_object( - pull_request_obj, _org_pull_request_obj) - - return _org_pull_request_obj, pull_request_obj, \ - pull_request_display_obj, at_version - def _get_diffset(self, source_repo_name, source_repo, source_ref_id, target_ref_id, target_commit, source_commit, diff_limit, fulldiff, @@ -277,7 +255,7 @@ class RepoPullRequestsView(RepoAppView, (pull_request_latest, pull_request_at_ver, pull_request_display_obj, - at_version) = self._get_pr_version( + at_version) = PullRequestModel().get_pr_version( pull_request_id, version=version) pr_closed = pull_request_latest.is_closed() @@ -299,7 +277,7 @@ class RepoPullRequestsView(RepoAppView, (prev_pull_request_latest, prev_pull_request_at_ver, prev_pull_request_display_obj, - prev_at_version) = self._get_pr_version( + prev_at_version) = PullRequestModel().get_pr_version( pull_request_id, version=from_version) c.from_version = prev_at_version @@ -630,7 +608,8 @@ class RepoPullRequestsView(RepoAppView, try: source_repo_data = PullRequestModel().generate_repo_data( source_repo, commit_id=commit_id, - branch=branch_ref, bookmark=bookmark_ref, translator=self.request.translate) + branch=branch_ref, bookmark=bookmark_ref, + translator=self.request.translate) except CommitDoesNotExistError as e: log.exception(e) h.flash(_('Commit does not exist'), 'error') @@ -649,8 +628,9 @@ class RepoPullRequestsView(RepoAppView, default_target_repo, translator=self.request.translate) selected_source_ref = source_repo_data['refs']['selected_ref'] - - title_source_ref = selected_source_ref.split(':', 2)[1] + title_source_ref = '' + if selected_source_ref: + title_source_ref = selected_source_ref.split(':', 2)[1] c.default_title = PullRequestModel().generate_pullrequest_title( source=source_repo.repo_name, source_ref=title_source_ref, @@ -675,6 +655,7 @@ class RepoPullRequestsView(RepoAppView, route_name='pullrequest_repo_refs', request_method='GET', renderer='json_ext', xhr=True) def pull_request_repo_refs(self): + self.load_default_context() target_repo_name = self.request.matchdict['target_repo_name'] repo = Repository.get_by_repo_name(target_repo_name) if not repo: @@ -752,16 +733,19 @@ class RepoPullRequestsView(RepoAppView, def pull_request_create(self): _ = self.request.translate self.assure_not_empty_repo() + self.load_default_context() controls = peppercorn.parse(self.request.POST.items()) try: - _form = PullRequestForm(self.db_repo.repo_id)().to_python(controls) + form = PullRequestForm( + self.request.translate, self.db_repo.repo_id)() + _form = form.to_python(controls) except formencode.Invalid as errors: if errors.error_dict.get('revisions'): msg = 'Revisions: %s' % errors.error_dict['revisions'] elif errors.error_dict.get('pullrequest_title'): - msg = _('Pull request requires a title with min. 3 chars') + msg = errors.error_dict.get('pullrequest_title') else: msg = _('Error creating pull request: {}').format(errors) log.exception(msg) @@ -882,6 +866,15 @@ class RepoPullRequestsView(RepoAppView, def pull_request_update(self): pull_request = PullRequest.get_or_404( self.request.matchdict['pull_request_id']) + _ = self.request.translate + + self.load_default_context() + + if pull_request.is_closed(): + log.debug('update: forbidden because pull request is closed') + msg = _(u'Cannot update closed pull requests.') + h.flash(msg, category='error') + return True # only owner or admin can update it allowed_to_update = PullRequestModel().check_user_update( @@ -981,6 +974,7 @@ class RepoPullRequestsView(RepoAppView, pull_request = PullRequest.get_or_404( self.request.matchdict['pull_request_id']) + self.load_default_context() check = MergeCheck.validate(pull_request, self._rhodecode_db_user, translator=self.request.translate) merge_possible = not check.failed @@ -1053,6 +1047,7 @@ class RepoPullRequestsView(RepoAppView, pull_request = PullRequest.get_or_404( self.request.matchdict['pull_request_id']) + self.load_default_context() pr_closed = pull_request.is_closed() allowed_to_delete = PullRequestModel().check_user_delete( @@ -1166,6 +1161,10 @@ class RepoPullRequestsView(RepoAppView, ) Session().flush() + # this is somehow required to get access to some relationship + # loaded on comment + Session().refresh(comment) + events.trigger( events.PullRequestCommentEvent(pull_request, comment)) diff --git a/rhodecode/apps/repository/views/repo_review_rules.py b/rhodecode/apps/repository/views/repo_review_rules.py --- a/rhodecode/apps/repository/views/repo_review_rules.py +++ b/rhodecode/apps/repository/views/repo_review_rules.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -32,8 +32,6 @@ log = logging.getLogger(__name__) class RepoReviewRulesView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - - self._register_global_c(c) return c @LoginRequired() @@ -54,6 +52,7 @@ class RepoReviewRulesView(RepoAppView): route_name='repo_default_reviewers_data', request_method='GET', renderer='json_ext') def repo_default_reviewers_data(self): + self.load_default_context() review_data = get_default_reviewers_data( self.db_repo.user, None, None, None, None) return review_data diff --git a/rhodecode/apps/repository/views/repo_settings.py b/rhodecode/apps/repository/views/repo_settings.py --- a/rhodecode/apps/repository/views/repo_settings.py +++ b/rhodecode/apps/repository/views/repo_settings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -62,16 +62,17 @@ class RepoSettingsView(RepoAppView): # we might be in missing requirement state, so we load things # without touching scm_instance() c.landing_revs_choices, c.landing_revs = \ - ScmModel().get_repo_landing_revs() + ScmModel().get_repo_landing_revs(self.request.translate) else: c.landing_revs_choices, c.landing_revs = \ - ScmModel().get_repo_landing_revs(self.db_repo) + ScmModel().get_repo_landing_revs( + self.request.translate, self.db_repo) c.personal_repo_group = c.auth_user.personal_repo_group c.repo_fields = RepositoryField.query()\ .filter(RepositoryField.repository == self.db_repo).all() - self._register_global_c(c) + return c def _get_schema(self, c, old_values=None): diff --git a/rhodecode/apps/repository/views/repo_settings_advanced.py b/rhodecode/apps/repository/views/repo_settings_advanced.py --- a/rhodecode/apps/repository/views/repo_settings_advanced.py +++ b/rhodecode/apps/repository/views/repo_settings_advanced.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -44,7 +44,7 @@ class RepoSettingsView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/repository/views/repo_settings_fields.py b/rhodecode/apps/repository/views/repo_settings_fields.py --- a/rhodecode/apps/repository/views/repo_settings_fields.py +++ b/rhodecode/apps/repository/views/repo_settings_fields.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2017-2017 RhodeCode GmbH +# Copyright (C) 2017-2018 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 @@ -43,7 +43,7 @@ class RepoSettingsFieldsView(RepoAppView def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() @@ -70,7 +70,8 @@ class RepoSettingsFieldsView(RepoAppView _ = self.request.translate try: - form_result = RepoFieldForm()().to_python(dict(self.request.POST)) + form = RepoFieldForm(self.request.translate)() + form_result = form.to_python(dict(self.request.POST)) RepoModel().add_repo_field( self.db_repo_name, form_result['new_field_key'], diff --git a/rhodecode/apps/repository/views/repo_settings_issue_trackers.py b/rhodecode/apps/repository/views/repo_settings_issue_trackers.py --- a/rhodecode/apps/repository/views/repo_settings_issue_trackers.py +++ b/rhodecode/apps/repository/views/repo_settings_issue_trackers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2017-2017 RhodeCode GmbH +# Copyright (C) 2017-2018 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 @@ -22,6 +22,7 @@ import logging from pyramid.httpexceptions import HTTPFound from pyramid.view import view_config +import formencode from rhodecode.apps._base import RepoAppView from rhodecode.lib import audit_logger @@ -39,7 +40,7 @@ class RepoSettingsIssueTrackersView(Repo def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() @@ -116,7 +117,17 @@ class RepoSettingsIssueTrackersView(Repo repo_settings.inherit_global_settings = inherited Session().commit() - form = IssueTrackerPatternsForm()().to_python(self.request.POST) + try: + form = IssueTrackerPatternsForm(self.request.translate)().to_python(self.request.POST) + except formencode.Invalid as errors: + log.exception('Failed to add new pattern') + error = errors + h.flash(_('Invalid issue tracker pattern: {}'.format(error)), + category='error') + raise HTTPFound( + h.route_path('edit_repo_issuetracker', + repo_name=self.db_repo_name)) + if form: self._update_patterns(form, repo_settings) diff --git a/rhodecode/apps/repository/views/repo_settings_remote.py b/rhodecode/apps/repository/views/repo_settings_remote.py --- a/rhodecode/apps/repository/views/repo_settings_remote.py +++ b/rhodecode/apps/repository/views/repo_settings_remote.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2017-2017 RhodeCode GmbH +# Copyright (C) 2017-2018 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 @@ -36,7 +36,7 @@ class RepoSettingsRemoteView(RepoAppView def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/repository/views/repo_settings_vcs.py b/rhodecode/apps/repository/views/repo_settings_vcs.py --- a/rhodecode/apps/repository/views/repo_settings_vcs.py +++ b/rhodecode/apps/repository/views/repo_settings_vcs.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2017-2017 RhodeCode GmbH +# Copyright (C) 2017-2018 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 @@ -43,7 +43,7 @@ class RepoSettingsVcsView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c def _vcs_form_defaults(self, repo_name): @@ -117,7 +117,7 @@ class RepoSettingsVcsView(RepoAppView): defaults = self._vcs_form_defaults(self.db_repo_name) c.inherit_global_settings = defaults['inherit_global_settings'] - application_form = RepoVcsSettingsForm(self.db_repo_name)() + application_form = RepoVcsSettingsForm(self.request.translate, self.db_repo_name)() try: form_result = application_form.to_python(dict(self.request.POST)) except formencode.Invalid as errors: diff --git a/rhodecode/apps/repository/views/repo_strip.py b/rhodecode/apps/repository/views/repo_strip.py --- a/rhodecode/apps/repository/views/repo_strip.py +++ b/rhodecode/apps/repository/views/repo_strip.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2017-2017 RhodeCode GmbH +# Copyright (C) 2017-2018 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 @@ -35,7 +35,7 @@ class StripView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/repository/views/repo_summary.py b/rhodecode/apps/repository/views/repo_summary.py --- a/rhodecode/apps/repository/views/repo_summary.py +++ b/rhodecode/apps/repository/views/repo_summary.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -48,12 +48,9 @@ class RepoSummaryView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context(include_app_defaults=True) - c.rhodecode_repo = None if not c.repository_requirements_missing: c.rhodecode_repo = self.rhodecode_vcs_repo - - self._register_global_c(c) return c def _get_readme_data(self, db_repo, default_renderer): @@ -174,18 +171,22 @@ class RepoSummaryView(RepoAppView): if self._rhodecode_user.username != User.DEFAULT_USER: username = safe_str(self._rhodecode_user.username) - _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl + _def_clone_uri = _def_clone_uri_id = c.clone_uri_tmpl + _def_clone_uri_ssh = c.clone_uri_ssh_tmpl + if '{repo}' in _def_clone_uri: - _def_clone_uri_by_id = _def_clone_uri.replace( + _def_clone_uri_id = _def_clone_uri.replace( '{repo}', '_{repoid}') elif '{repoid}' in _def_clone_uri: - _def_clone_uri_by_id = _def_clone_uri.replace( + _def_clone_uri_id = _def_clone_uri.replace( '_{repoid}', '{repo}') c.clone_repo_url = self.db_repo.clone_url( user=username, uri_tmpl=_def_clone_uri) c.clone_repo_url_id = self.db_repo.clone_url( - user=username, uri_tmpl=_def_clone_uri_by_id) + user=username, uri_tmpl=_def_clone_uri_id) + c.clone_repo_url_ssh = self.db_repo.clone_url( + uri_tmpl=_def_clone_uri_ssh, ssh=True) # If enabled, get statistics data diff --git a/rhodecode/apps/repository/views/repo_tags.py b/rhodecode/apps/repository/views/repo_tags.py --- a/rhodecode/apps/repository/views/repo_tags.py +++ b/rhodecode/apps/repository/views/repo_tags.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 diff --git a/rhodecode/apps/search/__init__.py b/rhodecode/apps/search/__init__.py --- a/rhodecode/apps/search/__init__.py +++ b/rhodecode/apps/search/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/search/tests/test_search.py b/rhodecode/apps/search/tests/test_search.py --- a/rhodecode/apps/search/tests/test_search.py +++ b/rhodecode/apps/search/tests/test_search.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -25,7 +25,7 @@ import pytest from whoosh import query from rhodecode.tests import ( - TestController, SkipTest, HG_REPO, + TestController, HG_REPO, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) from rhodecode.tests.utils import AssertResponse @@ -51,7 +51,7 @@ class TestSearchController(TestControlle def test_search_files_empty_search(self): if os.path.isdir(self.index_location): - raise SkipTest('skipped due to existing index') + pytest.skip('skipped due to existing index') else: self.log_user() response = self.app.get(route_path('search'), diff --git a/rhodecode/apps/search/views.py b/rhodecode/apps/search/views.py --- a/rhodecode/apps/search/views.py +++ b/rhodecode/apps/search/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2011-2017 RhodeCode GmbH +# Copyright (C) 2011-2018 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 @@ -103,7 +103,7 @@ def search(request, tmpl_context, repo_n class SearchView(BaseAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() @@ -119,7 +119,7 @@ class SearchView(BaseAppView): class SearchRepoView(RepoAppView): def load_default_context(self): c = self._get_local_tmpl_context() - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/apps/ssh_support/__init__.py b/rhodecode/apps/ssh_support/__init__.py --- a/rhodecode/apps/ssh_support/__init__.py +++ b/rhodecode/apps/ssh_support/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/config_keys.py b/rhodecode/apps/ssh_support/config_keys.py --- a/rhodecode/apps/ssh_support/config_keys.py +++ b/rhodecode/apps/ssh_support/config_keys.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/events.py b/rhodecode/apps/ssh_support/events.py --- a/rhodecode/apps/ssh_support/events.py +++ b/rhodecode/apps/ssh_support/events.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/lib/__init__.py b/rhodecode/apps/ssh_support/lib/__init__.py --- a/rhodecode/apps/ssh_support/lib/__init__.py +++ b/rhodecode/apps/ssh_support/lib/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/lib/backends/__init__.py b/rhodecode/apps/ssh_support/lib/backends/__init__.py --- a/rhodecode/apps/ssh_support/lib/backends/__init__.py +++ b/rhodecode/apps/ssh_support/lib/backends/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -22,7 +22,7 @@ import os import re import logging import datetime -import ConfigParser +from pyramid.compat import configparser from rhodecode.model.db import Session, User, UserSshKeys from rhodecode.model.scm import ScmModel @@ -51,7 +51,7 @@ class SshWrapper(object): self.server_impl = None def parse_config(self, config_path): - parser = ConfigParser.ConfigParser() + parser = configparser.ConfigParser() parser.read(config_path) return parser diff --git a/rhodecode/apps/ssh_support/lib/backends/base.py b/rhodecode/apps/ssh_support/lib/backends/base.py --- a/rhodecode/apps/ssh_support/lib/backends/base.py +++ b/rhodecode/apps/ssh_support/lib/backends/base.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -93,6 +93,7 @@ class VcsServer(object): scm_data = { 'ip': os.environ['SSH_CLIENT'].split()[0], 'username': self.user.username, + 'user_id': self.user.user_id, 'action': action, 'repository': self.repo_name, 'scm': self.backend, diff --git a/rhodecode/apps/ssh_support/lib/backends/git.py b/rhodecode/apps/ssh_support/lib/backends/git.py --- a/rhodecode/apps/ssh_support/lib/backends/git.py +++ b/rhodecode/apps/ssh_support/lib/backends/git.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/lib/backends/hg.py b/rhodecode/apps/ssh_support/lib/backends/hg.py --- a/rhodecode/apps/ssh_support/lib/backends/hg.py +++ b/rhodecode/apps/ssh_support/lib/backends/hg.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/lib/backends/svn.py b/rhodecode/apps/ssh_support/lib/backends/svn.py --- a/rhodecode/apps/ssh_support/lib/backends/svn.py +++ b/rhodecode/apps/ssh_support/lib/backends/svn.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/lib/ssh_wrapper.py b/rhodecode/apps/ssh_support/lib/ssh_wrapper.py --- a/rhodecode/apps/ssh_support/lib/ssh_wrapper.py +++ b/rhodecode/apps/ssh_support/lib/ssh_wrapper.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/subscribers.py b/rhodecode/apps/ssh_support/subscribers.py --- a/rhodecode/apps/ssh_support/subscribers.py +++ b/rhodecode/apps/ssh_support/subscribers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/tests/__init__.py b/rhodecode/apps/ssh_support/tests/__init__.py --- a/rhodecode/apps/ssh_support/tests/__init__.py +++ b/rhodecode/apps/ssh_support/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/tests/conftest.py b/rhodecode/apps/ssh_support/tests/conftest.py --- a/rhodecode/apps/ssh_support/tests/conftest.py +++ b/rhodecode/apps/ssh_support/tests/conftest.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -20,7 +20,7 @@ import os import pytest -import ConfigParser +from pyramid.compat import configparser from rhodecode.apps.ssh_support.lib.ssh_wrapper import SshWrapper from rhodecode.lib.utils2 import AttributeDict @@ -28,7 +28,7 @@ from rhodecode.lib.utils2 import Attribu @pytest.fixture def dummy_conf_file(tmpdir): - conf = ConfigParser.ConfigParser() + conf = configparser.ConfigParser() conf.add_section('app:main') conf.set('app:main', 'ssh.executable.hg', '/usr/bin/hg') conf.set('app:main', 'ssh.executable.git', '/usr/bin/git') diff --git a/rhodecode/apps/ssh_support/tests/test_server_git.py b/rhodecode/apps/ssh_support/tests/test_server_git.py --- a/rhodecode/apps/ssh_support/tests/test_server_git.py +++ b/rhodecode/apps/ssh_support/tests/test_server_git.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -127,6 +127,7 @@ class TestGitServer(object): expected_data = { 'username': git_server.user.username, + 'user_id': git_server.user.user_id, 'scm': 'git', 'repository': git_server.repo_name, 'make_lock': None, diff --git a/rhodecode/apps/ssh_support/tests/test_server_hg.py b/rhodecode/apps/ssh_support/tests/test_server_hg.py --- a/rhodecode/apps/ssh_support/tests/test_server_hg.py +++ b/rhodecode/apps/ssh_support/tests/test_server_hg.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/tests/test_server_svn.py b/rhodecode/apps/ssh_support/tests/test_server_svn.py --- a/rhodecode/apps/ssh_support/tests/test_server_svn.py +++ b/rhodecode/apps/ssh_support/tests/test_server_svn.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/tests/test_ssh_authorized_keys_gen.py b/rhodecode/apps/ssh_support/tests/test_ssh_authorized_keys_gen.py --- a/rhodecode/apps/ssh_support/tests/test_ssh_authorized_keys_gen.py +++ b/rhodecode/apps/ssh_support/tests/test_ssh_authorized_keys_gen.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/tests/test_ssh_wrapper.py b/rhodecode/apps/ssh_support/tests/test_ssh_wrapper.py --- a/rhodecode/apps/ssh_support/tests/test_ssh_wrapper.py +++ b/rhodecode/apps/ssh_support/tests/test_ssh_wrapper.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/ssh_support/utils.py b/rhodecode/apps/ssh_support/utils.py --- a/rhodecode/apps/ssh_support/utils.py +++ b/rhodecode/apps/ssh_support/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/svn_support/__init__.py b/rhodecode/apps/svn_support/__init__.py --- a/rhodecode/apps/svn_support/__init__.py +++ b/rhodecode/apps/svn_support/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/svn_support/config_keys.py b/rhodecode/apps/svn_support/config_keys.py --- a/rhodecode/apps/svn_support/config_keys.py +++ b/rhodecode/apps/svn_support/config_keys.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/svn_support/events.py b/rhodecode/apps/svn_support/events.py --- a/rhodecode/apps/svn_support/events.py +++ b/rhodecode/apps/svn_support/events.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/svn_support/subscribers.py b/rhodecode/apps/svn_support/subscribers.py --- a/rhodecode/apps/svn_support/subscribers.py +++ b/rhodecode/apps/svn_support/subscribers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/svn_support/tests/test_mod_dav_svn_config.py b/rhodecode/apps/svn_support/tests/test_mod_dav_svn_config.py --- a/rhodecode/apps/svn_support/tests/test_mod_dav_svn_config.py +++ b/rhodecode/apps/svn_support/tests/test_mod_dav_svn_config.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -23,19 +23,14 @@ import os import mock import pytest -from pyramid import testing - from rhodecode.apps.svn_support import utils +@pytest.mark.usefixtures('config_stub') class TestModDavSvnConfig(object): @classmethod def setup_class(cls): - # Make mako renderer available in tests. - config = testing.setUp() - config.include('pyramid_mako') - cls.location_root = u'/location/root/çµäö' cls.parent_path_root = u'/parent/path/çµäö' cls.realm = u'Dummy Realm (äöüçµ)' diff --git a/rhodecode/apps/svn_support/utils.py b/rhodecode/apps/svn_support/utils.py --- a/rhodecode/apps/svn_support/utils.py +++ b/rhodecode/apps/svn_support/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/user_group/__init__.py b/rhodecode/apps/user_group/__init__.py --- a/rhodecode/apps/user_group/__init__.py +++ b/rhodecode/apps/user_group/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -20,7 +20,7 @@ from rhodecode.apps.admin.navigation import NavigationRegistry -from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.apps._base import ADMIN_PREFIX from rhodecode.lib.utils2 import str2bool diff --git a/rhodecode/apps/user_group/tests/__init__.py b/rhodecode/apps/user_group/tests/__init__.py --- a/rhodecode/apps/user_group/tests/__init__.py +++ b/rhodecode/apps/user_group/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/user_group/tests/test_user_groups.py b/rhodecode/apps/user_group/tests/test_user_groups.py --- a/rhodecode/apps/user_group/tests/test_user_groups.py +++ b/rhodecode/apps/user_group/tests/test_user_groups.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/user_group/views/__init__.py b/rhodecode/apps/user_group/views/__init__.py --- a/rhodecode/apps/user_group/views/__init__.py +++ b/rhodecode/apps/user_group/views/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -40,8 +40,7 @@ from rhodecode.lib.auth import ( LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired) from rhodecode.lib import helpers as h, audit_logger from rhodecode.lib.utils2 import str2bool -from rhodecode.model.db import ( - joinedload, User, UserGroupRepoToPerm, UserGroupRepoGroupToPerm) +from rhodecode.model.db import User from rhodecode.model.meta import Session from rhodecode.model.user_group import UserGroupModel @@ -56,35 +55,8 @@ class UserGroupsView(UserGroupAppView): PermissionModel().set_global_permission_choices( c, gettext_translator=self.request.translate) - self._register_global_c(c) return c - def _get_perms_summary(self, user_group_id): - permissions = { - 'repositories': {}, - 'repositories_groups': {}, - } - ugroup_repo_perms = UserGroupRepoToPerm.query()\ - .options(joinedload(UserGroupRepoToPerm.permission))\ - .options(joinedload(UserGroupRepoToPerm.repository))\ - .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\ - .all() - - for gr in ugroup_repo_perms: - permissions['repositories'][gr.repository.repo_name] \ - = gr.permission.permission_name - - ugroup_group_perms = UserGroupRepoGroupToPerm.query()\ - .options(joinedload(UserGroupRepoGroupToPerm.permission))\ - .options(joinedload(UserGroupRepoGroupToPerm.group))\ - .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\ - .all() - - for gr in ugroup_group_perms: - permissions['repositories_groups'][gr.group.group_name] \ - = gr.permission.permission_name - return permissions - @LoginRequired() @HasUserGroupPermissionAnyDecorator('usergroup.admin') @view_config( @@ -94,6 +66,7 @@ class UserGroupsView(UserGroupAppView): """ Return members of given user group """ + self.load_default_context() user_group = self.db_user_group group_members_obj = sorted((x.user for x in user_group.members), key=lambda u: u.username.lower()) @@ -126,7 +99,8 @@ class UserGroupsView(UserGroupAppView): c = self.load_default_context() c.user_group = self.db_user_group c.active = 'perms_summary' - c.permissions = self._get_perms_summary(c.user_group.users_group_id) + c.permissions = UserGroupModel().get_perms_summary( + c.user_group.users_group_id) return self._get_template_context(c) @LoginRequired() @@ -137,7 +111,7 @@ class UserGroupsView(UserGroupAppView): def user_group_perms_summary_json(self): self.load_default_context() user_group = self.db_user_group - return self._get_perms_summary(user_group.users_group_id) + return UserGroupModel().get_perms_summary(user_group.users_group_id) def _revoke_perms_on_yourself(self, form_result): _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), @@ -173,7 +147,8 @@ class UserGroupsView(UserGroupAppView): c.active = 'settings' users_group_form = UserGroupForm( - edit=True, old_data=c.user_group.get_dict(), allow_disabled=True)() + self.request.translate, edit=True, + old_data=c.user_group.get_dict(), allow_disabled=True)() old_values = c.user_group.get_api_data() user_group_name = self.request.POST.get('users_group_name') @@ -346,7 +321,7 @@ class UserGroupsView(UserGroupAppView): user_group_id = user_group.users_group_id c = self.load_default_context() c.user_group = user_group - form = UserGroupPermsForm()().to_python(self.request.POST) + form = UserGroupPermsForm(self.request.translate)().to_python(self.request.POST) if not self._rhodecode_user.is_admin: if self._revoke_perms_on_yourself(form): @@ -426,7 +401,7 @@ class UserGroupsView(UserGroupAppView): try: # first stage that verifies the checkbox - _form = UserIndividualPermissionsForm() + _form = UserIndividualPermissionsForm(self.request.translate) form_result = _form.to_python(dict(self.request.POST)) inherit_perms = form_result['inherit_default_permissions'] user_group.inherit_default_permissions = inherit_perms @@ -435,6 +410,7 @@ class UserGroupsView(UserGroupAppView): if not inherit_perms: # only update the individual ones if we un check the flag _form = UserPermissionsForm( + self.request.translate, [x[0] for x in c.repo_create_choices], [x[0] for x in c.repo_create_on_write_choices], [x[0] for x in c.repo_group_create_choices], diff --git a/rhodecode/apps/user_profile/__init__.py b/rhodecode/apps/user_profile/__init__.py --- a/rhodecode/apps/user_profile/__init__.py +++ b/rhodecode/apps/user_profile/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/user_profile/tests/__init__.py b/rhodecode/apps/user_profile/tests/__init__.py --- a/rhodecode/apps/user_profile/tests/__init__.py +++ b/rhodecode/apps/user_profile/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/apps/user_profile/tests/test_users.py b/rhodecode/apps/user_profile/tests/test_users.py --- a/rhodecode/apps/user_profile/tests/test_users.py +++ b/rhodecode/apps/user_profile/tests/test_users.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/apps/user_profile/views.py b/rhodecode/apps/user_profile/views.py --- a/rhodecode/apps/user_profile/views.py +++ b/rhodecode/apps/user_profile/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/authentication/__init__.py b/rhodecode/authentication/__init__.py --- a/rhodecode/authentication/__init__.py +++ b/rhodecode/authentication/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -27,7 +27,7 @@ from pyramid.authentication import Sessi from rhodecode.authentication.registry import AuthenticationPluginRegistry from rhodecode.authentication.routes import root_factory from rhodecode.authentication.routes import AuthnRootResource -from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.apps._base import ADMIN_PREFIX from rhodecode.model.settings import SettingsModel diff --git a/rhodecode/authentication/base.py b/rhodecode/authentication/base.py --- a/rhodecode/authentication/base.py +++ b/rhodecode/authentication/base.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -77,7 +77,6 @@ class hybrid_property(object): self.fdel(instance) - class LazyFormencode(object): def __init__(self, formencode_obj, *args, **kwargs): self.formencode_obj = formencode_obj @@ -106,6 +105,8 @@ class RhodeCodeAuthPluginBase(object): "lastname": "last name", "email": "email address", "groups": '["list", "of", "groups"]', + "user_group_sync": + 'True|False defines if returned user groups should be synced', "extern_name": "name in external source of record", "extern_type": "type of external source of record", "admin": 'True|False defines if user should be RhodeCode super admin', @@ -114,6 +115,7 @@ class RhodeCodeAuthPluginBase(object): "active_from_extern": "True|False\None, active state from the external auth, " "None means use definition from RhodeCode extern_type active value" + } # set on authenticate() method and via set_auth_type func. auth_type = None @@ -252,29 +254,6 @@ class RhodeCodeAuthPluginBase(object): del settings_copy[k] return settings_copy - @property - def validators(self): - """ - Exposes RhodeCode validators modules - """ - # this is a hack to overcome issues with pylons threadlocals and - # translator object _() not being registered properly. - class LazyCaller(object): - def __init__(self, name): - self.validator_name = name - - def __call__(self, *args, **kwargs): - from rhodecode.model import validators as v - obj = getattr(v, self.validator_name) - # log.debug('Initializing lazy formencode object: %s', obj) - return LazyFormencode(obj, *args, **kwargs) - - class ProxyGet(object): - def __getattribute__(self, name): - return LazyCaller(name) - - return ProxyGet() - @hybrid_property def name(self): """ @@ -435,8 +414,9 @@ class RhodeCodeAuthPluginBase(object): new_hash = auth.get('_hash_migrate') if new_hash: self._migrate_hash_to_bcrypt(username, passwd, new_hash) + if 'user_group_sync' not in auth: + auth['user_group_sync'] = False return self._validate_auth_return(auth) - return auth def _migrate_hash_to_bcrypt(self, username, password, new_hash): @@ -561,16 +541,19 @@ class RhodeCodeExternalAuthPlugin(RhodeC # enforce user is just in given groups, all of them has to be ones # created from plugins. We store this info in _group_data JSON # field - try: - groups = auth['groups'] or [] - log.debug( - 'Performing user_group sync based on set `%s` ' - 'returned by this plugin', groups) - UserGroupModel().enforce_groups(user, groups, self.name) - except Exception: - # for any reason group syncing fails, we should - # proceed with login - log.error(traceback.format_exc()) + + if auth['user_group_sync']: + try: + groups = auth['groups'] or [] + log.debug( + 'Performing user_group sync based on set `%s` ' + 'returned by `%s` plugin', groups, self.name) + UserGroupModel().enforce_groups(user, groups, self.name) + except Exception: + # for any reason group syncing fails, we should + # proceed with login + log.error(traceback.format_exc()) + Session().commit() return auth @@ -694,7 +677,7 @@ def authenticate(username, password, env environ=environ or {}) if plugin_cache_active: - log.debug('Trying to fetch cached auth by %s', _password_hash[:6]) + log.debug('Trying to fetch cached auth by `...%s`', _password_hash[:6]) plugin_user = cache_manager.get( _password_hash, createfunc=auth_func) else: diff --git a/rhodecode/authentication/interface.py b/rhodecode/authentication/interface.py --- a/rhodecode/authentication/interface.py +++ b/rhodecode/authentication/interface.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 diff --git a/rhodecode/authentication/plugins/auth_crowd.py b/rhodecode/authentication/plugins/auth_crowd.py --- a/rhodecode/authentication/plugins/auth_crowd.py +++ b/rhodecode/authentication/plugins/auth_crowd.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -267,6 +267,7 @@ class RhodeCodeAuthPlugin(RhodeCodeExter 'firstname': crowd_user["first-name"] or firstname, 'lastname': crowd_user["last-name"] or lastname, 'groups': crowd_user["groups"], + 'user_group_sync': True, 'email': crowd_user["email"] or email, 'admin': admin, 'active': active, diff --git a/rhodecode/authentication/plugins/auth_headers.py b/rhodecode/authentication/plugins/auth_headers.py --- a/rhodecode/authentication/plugins/auth_headers.py +++ b/rhodecode/authentication/plugins/auth_headers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -212,6 +212,7 @@ class RhodeCodeAuthPlugin(RhodeCodeExter 'firstname': safe_unicode(firstname or username), 'lastname': safe_unicode(lastname or ''), 'groups': [], + 'user_group_sync': False, 'email': email or '', 'admin': admin or False, 'active': active, diff --git a/rhodecode/authentication/plugins/auth_jasig_cas.py b/rhodecode/authentication/plugins/auth_jasig_cas.py --- a/rhodecode/authentication/plugins/auth_jasig_cas.py +++ b/rhodecode/authentication/plugins/auth_jasig_cas.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -154,6 +154,7 @@ class RhodeCodeAuthPlugin(RhodeCodeExter 'firstname': safe_unicode(firstname or username), 'lastname': safe_unicode(lastname or ''), 'groups': [], + 'user_group_sync': False, 'email': email or '', 'admin': admin or False, 'active': active, diff --git a/rhodecode/authentication/plugins/auth_ldap.py b/rhodecode/authentication/plugins/auth_ldap.py --- a/rhodecode/authentication/plugins/auth_ldap.py +++ b/rhodecode/authentication/plugins/auth_ldap.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -460,6 +460,7 @@ class RhodeCodeAuthPlugin(RhodeCodeExter 'lastname': safe_unicode( get_ldap_attr('attr_lastname') or lastname), 'groups': groups, + 'user_group_sync': False, 'email': get_ldap_attr('attr_email') or email, 'admin': admin, 'active': active, diff --git a/rhodecode/authentication/plugins/auth_pam.py b/rhodecode/authentication/plugins/auth_pam.py --- a/rhodecode/authentication/plugins/auth_pam.py +++ b/rhodecode/authentication/plugins/auth_pam.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -136,6 +136,7 @@ class RhodeCodeAuthPlugin(RhodeCodeExter 'lastname': lastname, 'groups': [g.gr_name for g in grp.getgrall() if username in g.gr_mem], + 'user_group_sync': True, 'email': email, 'admin': admin, 'active': active, diff --git a/rhodecode/authentication/plugins/auth_rhodecode.py b/rhodecode/authentication/plugins/auth_rhodecode.py --- a/rhodecode/authentication/plugins/auth_rhodecode.py +++ b/rhodecode/authentication/plugins/auth_rhodecode.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -100,6 +100,7 @@ class RhodeCodeAuthPlugin(RhodeCodeAuthP "firstname": userobj.firstname, "lastname": userobj.lastname, "groups": [], + 'user_group_sync': False, "email": userobj.email, "admin": userobj.admin, "active": userobj.active, diff --git a/rhodecode/authentication/plugins/auth_token.py b/rhodecode/authentication/plugins/auth_token.py --- a/rhodecode/authentication/plugins/auth_token.py +++ b/rhodecode/authentication/plugins/auth_token.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -111,6 +111,7 @@ class RhodeCodeAuthPlugin(RhodeCodeAuthP "firstname": userobj.firstname, "lastname": userobj.lastname, "groups": [], + 'user_group_sync': False, "email": userobj.email, "admin": userobj.admin, "active": userobj.active, diff --git a/rhodecode/authentication/registry.py b/rhodecode/authentication/registry.py --- a/rhodecode/authentication/registry.py +++ b/rhodecode/authentication/registry.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 diff --git a/rhodecode/authentication/routes.py b/rhodecode/authentication/routes.py --- a/rhodecode/authentication/routes.py +++ b/rhodecode/authentication/routes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 diff --git a/rhodecode/authentication/schema.py b/rhodecode/authentication/schema.py --- a/rhodecode/authentication/schema.py +++ b/rhodecode/authentication/schema.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 diff --git a/rhodecode/authentication/tests/conftest.py b/rhodecode/authentication/tests/conftest.py --- a/rhodecode/authentication/tests/conftest.py +++ b/rhodecode/authentication/tests/conftest.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -22,7 +22,7 @@ import pytest -class EnabledAuthPlugin(): +class EnabledAuthPlugin(object): """ Context manager that updates the 'auth_plugins' setting in DB to enable a plugin. Previous setting is restored on exit. The rhodecode auth plugin diff --git a/rhodecode/authentication/tests/functional/test_settings.py b/rhodecode/authentication/tests/functional/test_settings.py --- a/rhodecode/authentication/tests/functional/test_settings.py +++ b/rhodecode/authentication/tests/functional/test_settings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -23,7 +23,7 @@ import pytest from rhodecode.authentication.tests.conftest import ( EnabledAuthPlugin, DisabledAuthPlugin) -from rhodecode.config.routing import ADMIN_PREFIX +from rhodecode.apps._base import ADMIN_PREFIX @pytest.mark.usefixtures('autologin_user', 'app') diff --git a/rhodecode/authentication/views.py b/rhodecode/authentication/views.py --- a/rhodecode/authentication/views.py +++ b/rhodecode/authentication/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -26,25 +26,25 @@ from pyramid.httpexceptions import HTTPF from pyramid.renderers import render from pyramid.response import Response +from rhodecode.apps._base import BaseAppView from rhodecode.authentication.base import ( get_auth_cache_manager, get_perms_cache_manager, get_authn_registry) -from rhodecode.lib import auth -from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator +from rhodecode.lib import helpers as h +from rhodecode.lib.auth import ( + LoginRequired, HasPermissionAllDecorator, CSRFRequired) from rhodecode.model.forms import AuthSettingsForm from rhodecode.model.meta import Session from rhodecode.model.settings import SettingsModel -from rhodecode.translation import _ log = logging.getLogger(__name__) -class AuthnPluginViewBase(object): +class AuthnPluginViewBase(BaseAppView): - def __init__(self, context, request): - self.request = request - self.context = context - self.plugin = context.plugin - self._rhodecode_user = request.user + def load_default_context(self): + c = self._get_local_tmpl_context() + self.plugin = self.context.plugin + return c @LoginRequired() @HasPermissionAllDecorator('hg.admin') @@ -52,6 +52,7 @@ class AuthnPluginViewBase(object): """ View that displays the plugin settings as a form. """ + c = self.load_default_context() defaults = defaults or {} errors = errors or {} schema = self.plugin.get_settings_schema() @@ -70,15 +71,17 @@ class AuthnPluginViewBase(object): 'resource': self.context, } - return template_context + return self._get_template_context(c, **template_context) @LoginRequired() @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() + @CSRFRequired() def settings_post(self): """ View that validates and stores the plugin settings. """ + _ = self.request.translate + self.load_default_context() schema = self.plugin.get_settings_schema() data = self.request.params @@ -86,10 +89,10 @@ class AuthnPluginViewBase(object): valid_data = schema.deserialize(data) except colander.Invalid as e: # Display error message and display form again. - self.request.session.flash( + h.flash( _('Errors exist when saving plugin settings. ' 'Please check the form inputs.'), - queue='error') + category='error') defaults = {key: data[key] for key in data if key in schema} return self.settings_get(errors=e.asdict(), defaults=defaults) @@ -99,31 +102,22 @@ class AuthnPluginViewBase(object): Session().commit() # Display success message and redirect. - self.request.session.flash( - _('Auth settings updated successfully.'), - queue='success') + h.flash(_('Auth settings updated successfully.'), category='success') redirect_to = self.request.resource_path( self.context, route_name='auth_home') return HTTPFound(redirect_to) -# TODO: Ongoing migration in these views. -# - Maybe we should also use a colander schema for these views. -class AuthSettingsView(object): - def __init__(self, context, request): - self.context = context - self.request = request - - # TODO: Move this into a utility function. It is needed in all view - # classes during migration. Maybe a mixin? - - # Some of the decorators rely on this attribute to be present on the - # class of the decorated method. - self._rhodecode_user = request.user +class AuthSettingsView(BaseAppView): + def load_default_context(self): + c = self._get_local_tmpl_context() + return c @LoginRequired() @HasPermissionAllDecorator('hg.admin') def index(self, defaults=None, errors=None, prefix_error=False): + c = self.load_default_context() + defaults = defaults or {} authn_registry = get_authn_registry(self.request.registry) enabled_plugins = SettingsModel().get_auth_plugins() @@ -135,8 +129,8 @@ class AuthSettingsView(object): 'enabled_plugins': enabled_plugins, } html = render('rhodecode:templates/admin/auth/auth_settings.mako', - template_context, - request=self.request) + self._get_template_context(c, **template_context), + self.request) # Create form default values and fill the form. form_defaults = { @@ -155,11 +149,12 @@ class AuthSettingsView(object): @LoginRequired() @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() + @CSRFRequired() def auth_settings(self): + _ = self.request.translate try: - form = AuthSettingsForm()() - form_result = form.to_python(self.request.params) + form = AuthSettingsForm(self.request.translate)() + form_result = form.to_python(self.request.POST) plugins = ','.join(form_result['auth_plugins']) setting = SettingsModel().create_or_update_setting( 'auth_plugins', plugins) @@ -172,24 +167,19 @@ class AuthSettingsView(object): cache_manager = get_perms_cache_manager() cache_manager.clear() - self.request.session.flash( - _('Auth settings updated successfully.'), - queue='success') + h.flash(_('Auth settings updated successfully.'), category='success') except formencode.Invalid as errors: e = errors.error_dict or {} - self.request.session.flash( - _('Errors exist when saving plugin setting. ' - 'Please check the form inputs.'), - queue='error') + h.flash(_('Errors exist when saving plugin setting. ' + 'Please check the form inputs.'), category='error') return self.index( defaults=errors.value, errors=e, prefix_error=False) except Exception: log.exception('Exception in auth_settings') - self.request.session.flash( - _('Error occurred during update of auth settings.'), - queue='error') + h.flash(_('Error occurred during update of auth settings.'), + category='error') redirect_to = self.request.resource_path( self.context, route_name='auth_home') diff --git a/rhodecode/config/__init__.py b/rhodecode/config/__init__.py --- a/rhodecode/config/__init__.py +++ b/rhodecode/config/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/config/conf.py b/rhodecode/config/conf.py --- a/rhodecode/config/conf.py +++ b/rhodecode/config/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2013-2017 RhodeCode GmbH +# Copyright (C) 2013-2018 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 diff --git a/rhodecode/config/environment.py b/rhodecode/config/environment.py --- a/rhodecode/config/environment.py +++ b/rhodecode/config/environment.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -18,121 +18,19 @@ # RhodeCode Enterprise Edition, including its added features, Support services, # and proprietary license terms, please see https://rhodecode.com/licenses/ -""" -Pylons environment configuration -""" import os import logging import rhodecode -import platform -import re -import io - -from mako.lookup import TemplateLookup -from pylons.configuration import PylonsConfig -from pylons.error import handle_mako_error -from pyramid.settings import asbool - -# ------------------------------------------------------------------------------ -# CELERY magic until refactor - issue #4163 - import order matters here: -from rhodecode.lib import celerypylons # this must be first, celerypylons - # sets config settings upon import - -import rhodecode.integrations # any modules using celery task - # decorators should be added afterwards: -# ------------------------------------------------------------------------------ - -from rhodecode.lib import app_globals -from rhodecode.config import utils -from rhodecode.config.routing import make_map -from rhodecode.config.jsroutes import generate_jsroutes_content - -from rhodecode.lib import helpers -from rhodecode.lib.auth import set_available_permissions -from rhodecode.lib.utils import ( - repo2db_mapper, make_db_config, set_rhodecode_config, - load_rcextensions) -from rhodecode.lib.utils2 import str2bool, aslist -from rhodecode.lib.vcs import connect_vcs, start_vcs_server -from rhodecode.model.scm import ScmModel - -log = logging.getLogger(__name__) - -def load_environment(global_conf, app_conf, initial=False, - test_env=None, test_index=None): - """ - Configure the Pylons environment via the ``pylons.config`` - object - """ - config = PylonsConfig() - # Pylons paths - root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - paths = { - 'root': root, - 'controllers': os.path.join(root, 'controllers'), - 'static_files': os.path.join(root, 'public'), - 'templates': [os.path.join(root, 'templates')], - } - - # Initialize config with the basic options - config.init_app(global_conf, app_conf, package='rhodecode', paths=paths) - - # store some globals into rhodecode - rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery')) - rhodecode.CELERY_EAGER = str2bool( - config['app_conf'].get('celery.always.eager')) - - config['routes.map'] = make_map(config) - - config['pylons.app_globals'] = app_globals.Globals(config) - config['pylons.h'] = helpers - rhodecode.CONFIG = config - - load_rcextensions(root_path=config['here']) - - # Setup cache object as early as possible - import pylons - pylons.cache._push_object(config['pylons.app_globals'].cache) +from rhodecode.config import utils - # Create the Mako TemplateLookup, with the default auto-escaping - config['pylons.app_globals'].mako_lookup = TemplateLookup( - directories=paths['templates'], - error_handler=handle_mako_error, - module_directory=os.path.join(app_conf['cache_dir'], 'templates'), - input_encoding='utf-8', default_filters=['escape'], - imports=['from webhelpers.html import escape']) - - # sets the c attribute access when don't existing attribute are accessed - config['pylons.strict_tmpl_context'] = True - - # configure channelstream - config['channelstream_config'] = { - 'enabled': asbool(config.get('channelstream.enabled', False)), - 'server': config.get('channelstream.server'), - 'secret': config.get('channelstream.secret') - } +from rhodecode.lib.utils import load_rcextensions +from rhodecode.lib.utils2 import str2bool +from rhodecode.lib.vcs import connect_vcs - db_cfg = make_db_config(clear_session=True) - - repos_path = list(db_cfg.items('paths'))[0][1] - config['base_path'] = repos_path - - # store db config also in main global CONFIG - set_rhodecode_config(config) - - # configure instance id - utils.set_instance_id(config) - - # CONFIGURATION OPTIONS HERE (note: all config options will override - # any Pylons config options) - - # store config reference into our module to skip import magic of pylons - rhodecode.CONFIG.update(config) - - return config +log = logging.getLogger(__name__) def load_pyramid_environment(global_config, settings): @@ -140,10 +38,13 @@ def load_pyramid_environment(global_conf settings_merged = global_config.copy() settings_merged.update(settings) - # Store the settings to make them available to other modules. - rhodecode.PYRAMID_SETTINGS = settings_merged - # NOTE(marcink): needs to be enabled after full port to pyramid - # rhodecode.CONFIG = config + # TODO(marcink): probably not required anymore + # configure channelstream, + settings_merged['channelstream_config'] = { + 'enabled': str2bool(settings_merged.get('channelstream.enabled', False)), + 'server': settings_merged.get('channelstream.server'), + 'secret': settings_merged.get('channelstream.secret') + } # If this is a test run we prepare the test environment like # creating a test database, test search index and test repositories. @@ -157,6 +58,8 @@ def load_pyramid_environment(global_conf # Initialize the database connection. utils.initialize_database(settings_merged) + load_rcextensions(root_path=settings_merged['here']) + # Limit backends to `vcs.backends` from configuration for alias in rhodecode.BACKENDS.keys(): if alias not in settings['vcs.backends']: @@ -166,17 +69,13 @@ def load_pyramid_environment(global_conf # initialize vcs client and optionally run the server if enabled vcs_server_uri = settings['vcs.server'] vcs_server_enabled = settings['vcs.server.enable'] - start_server = ( - settings['vcs.start_server'] and - not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0'))) - - if vcs_server_enabled and start_server: - log.info("Starting vcsserver") - start_vcs_server(server_and_port=vcs_server_uri, - protocol=utils.get_vcs_server_protocol(settings), - log_level=settings['vcs.server.log_level']) utils.configure_vcs(settings) + # Store the settings to make them available to other modules. + + rhodecode.PYRAMID_SETTINGS = settings_merged + rhodecode.CONFIG = settings_merged + if vcs_server_enabled: connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings)) diff --git a/rhodecode/config/hook_templates/git_post_receive.py.tmpl b/rhodecode/config/hook_templates/git_post_receive.py.tmpl --- a/rhodecode/config/hook_templates/git_post_receive.py.tmpl +++ b/rhodecode/config/hook_templates/git_post_receive.py.tmpl @@ -16,7 +16,7 @@ RC_HOOK_VER = '_TMPL_' def main(): if hooks is None: - # exit with success if we cannot import rhodecode.lib.hooks !! + # exit with success if we cannot import vcsserver.hooks !! # this allows simply push to this repo even without rhodecode sys.exit(0) diff --git a/rhodecode/config/hook_templates/git_pre_receive.py.tmpl b/rhodecode/config/hook_templates/git_pre_receive.py.tmpl --- a/rhodecode/config/hook_templates/git_pre_receive.py.tmpl +++ b/rhodecode/config/hook_templates/git_pre_receive.py.tmpl @@ -16,7 +16,7 @@ RC_HOOK_VER = '_TMPL_' def main(): if hooks is None: - # exit with success if we cannot import rhodecode.lib.hooks !! + # exit with success if we cannot import vcsserver.hooks !! # this allows simply push to this repo even without rhodecode sys.exit(0) diff --git a/rhodecode/config/jsroutes.py b/rhodecode/config/jsroutes.py --- a/rhodecode/config/jsroutes.py +++ b/rhodecode/config/jsroutes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/config/licenses.json b/rhodecode/config/licenses.json --- a/rhodecode/config/licenses.json +++ b/rhodecode/config/licenses.json @@ -43,10 +43,7 @@ }, "python2.7-Pygments-2.2.0": { "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" - }, - "python2.7-Pylons-1.0.2.rhodecode-patch1": { - "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" - }, + }, "python2.7-Routes-1.13": { "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" }, @@ -77,13 +74,7 @@ }, "python2.7-alembic-0.8.4": { "MIT License": "http://spdx.org/licenses/MIT" - }, - "python2.7-amqplib-1.0.2": { - "GNU Lesser General Public License v3.0 only": "http://spdx.org/licenses/LGPL-3.0" - }, - "python2.7-anyjson-0.3.3": { - "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" - }, + }, "python2.7-appenlight-client-0.6.14": { "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" }, @@ -195,7 +186,7 @@ "python2.7-jupyter-core-4.3.0": { "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" }, - "python2.7-kombu-1.5.1": { + "python2.7-kombu-4.1.0": { "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause" }, "python2.7-mistune-0.7.4": { @@ -327,7 +318,7 @@ "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0", "Zope Public License 2.0": "http://spdx.org/licenses/ZPL-2.0" }, - "python2.7-setuptools-scm-1.15.0": { + "python2.7-setuptools-scm-1.15.6": { "MIT License": "http://spdx.org/licenses/MIT" }, "python2.7-simplegeneric-0.8.1": { diff --git a/rhodecode/config/middleware.py b/rhodecode/config/middleware.py --- a/rhodecode/config/middleware.py +++ b/rhodecode/config/middleware.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -18,41 +18,31 @@ # RhodeCode Enterprise Edition, including its added features, Support services, # and proprietary license terms, please see https://rhodecode.com/licenses/ -""" -Pylons middleware initialization -""" import logging import traceback -from collections import OrderedDict +import collections -from paste.registry import RegistryManager from paste.gzipper import make_gzip_middleware -from pylons.wsgiapp import PylonsApp +from pyramid.wsgi import wsgiapp from pyramid.authorization import ACLAuthorizationPolicy from pyramid.config import Configurator from pyramid.settings import asbool, aslist -from pyramid.wsgi import wsgiapp from pyramid.httpexceptions import ( - HTTPException, HTTPError, HTTPInternalServerError, HTTPFound) + HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound) from pyramid.events import ApplicationCreated from pyramid.renderers import render_to_response -from routes.middleware import RoutesMiddleware -import rhodecode from rhodecode.model import meta from rhodecode.config import patches from rhodecode.config import utils as config_utils -from rhodecode.config.routing import STATIC_FILE_PREFIX -from rhodecode.config.environment import ( - load_environment, load_pyramid_environment) +from rhodecode.config.environment import load_pyramid_environment +from rhodecode.lib.middleware.vcs import VCSMiddleware from rhodecode.lib.vcs import VCSCommunicationError from rhodecode.lib.exceptions import VCSServerUnavailable from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled -from rhodecode.lib.middleware.error_handling import ( - PylonsErrorHandlingMiddleware) from rhodecode.lib.middleware.https_fixup import HttpsFixup -from rhodecode.lib.middleware.vcs import VCSMiddleware +from rhodecode.lib.celerylib.loader import configure_celery from rhodecode.lib.plugins.utils import register_rhodecode_plugin from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict from rhodecode.subscribers import ( @@ -63,157 +53,67 @@ from rhodecode.subscribers import ( log = logging.getLogger(__name__) -# this is used to avoid avoid the route lookup overhead in routesmiddleware -# for certain routes which won't go to pylons to - eg. static files, debugger -# it is only needed for the pylons migration and can be removed once complete -class SkippableRoutesMiddleware(RoutesMiddleware): - """ Routes middleware that allows you to skip prefixes """ - - def __init__(self, *args, **kw): - self.skip_prefixes = kw.pop('skip_prefixes', []) - super(SkippableRoutesMiddleware, self).__init__(*args, **kw) - - def __call__(self, environ, start_response): - for prefix in self.skip_prefixes: - if environ['PATH_INFO'].startswith(prefix): - # added to avoid the case when a missing /_static route falls - # through to pylons and causes an exception as pylons is - # expecting wsgiorg.routingargs to be set in the environ - # by RoutesMiddleware. - if 'wsgiorg.routing_args' not in environ: - environ['wsgiorg.routing_args'] = (None, {}) - return self.app(environ, start_response) - - return super(SkippableRoutesMiddleware, self).__call__( - environ, start_response) - - -def make_app(global_conf, static_files=True, **app_conf): - """Create a Pylons WSGI application and return it - - ``global_conf`` - The inherited configuration for this application. Normally from - the [DEFAULT] section of the Paste ini file. - - ``app_conf`` - The application's local configuration. Normally specified in - the [app:] section of the Paste ini file (where - defaults to main). - - """ - # Apply compatibility patches - patches.kombu_1_5_1_python_2_7_11() - patches.inspect_getargspec() - - # Configure the Pylons environment - config = load_environment(global_conf, app_conf) - - # The Pylons WSGI app - app = PylonsApp(config=config) - - # Establish the Registry for this application - app = RegistryManager(app) - - app.config = config - - return app +def is_http_error(response): + # error which should have traceback + return response.status_code > 499 def make_pyramid_app(global_config, **settings): """ - Constructs the WSGI application based on Pyramid and wraps the Pylons based - application. + Constructs the WSGI application based on Pyramid. Specials: - * We migrate from Pylons to Pyramid. While doing this, we keep both - frameworks functional. This involves moving some WSGI middlewares around - and providing access to some data internals, so that the old code is - still functional. - * The application can also be integrated like a plugin via the call to `includeme`. This is accompanied with the other utility functions which are called. Changing this should be done with great care to not break cases when these fragments are assembled from another place. """ - # The edition string should be available in pylons too, so we add it here - # before copying the settings. - settings.setdefault('rhodecode.edition', 'Community Edition') - - # As long as our Pylons application does expect "unprepared" settings, make - # sure that we keep an unmodified copy. This avoids unintentional change of - # behavior in the old application. - settings_pylons = settings.copy() - sanitize_settings_and_apply_defaults(settings) config = Configurator(settings=settings) + + # Apply compatibility patches + patches.inspect_getargspec() + load_pyramid_environment(global_config, settings) - add_pylons_compat_data(config.registry, global_config, settings_pylons) + # Static file view comes first + includeme_first(config) - includeme_first(config) includeme(config) pyramid_app = config.make_wsgi_app() pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config) pyramid_app.config = config + config.configure_celery(global_config['__file__']) # creating the app uses a connection - return it after we are done meta.Session.remove() + log.info('Pyramid app %s created and configured.', pyramid_app) return pyramid_app -def make_not_found_view(config): +def not_found_view(request): """ This creates the view which should be registered as not-found-view to - pyramid. Basically it contains of the old pylons app, converted to a view. - Additionally it is wrapped by some other middlewares. + pyramid. """ - settings = config.registry.settings - vcs_server_enabled = settings['vcs.server.enable'] - # Make pylons app from unprepared settings. - pylons_app = make_app( - config.registry._pylons_compat_global_config, - **config.registry._pylons_compat_settings) - config.registry._pylons_compat_config = pylons_app.config - - # Appenlight monitoring. - pylons_app, appenlight_client = wrap_in_appenlight_if_enabled( - pylons_app, settings) + if not getattr(request, 'vcs_call', None): + # handle like regular case with our error_handler + return error_handler(HTTPNotFound(), request) - # The pylons app is executed inside of the pyramid 404 exception handler. - # Exceptions which are raised inside of it are not handled by pyramid - # again. Therefore we add a middleware that invokes the error handler in - # case of an exception or error response. This way we return proper error - # HTML pages in case of an error. - reraise = (settings.get('debugtoolbar.enabled', False) or - rhodecode.disable_error_handler) - pylons_app = PylonsErrorHandlingMiddleware( - pylons_app, error_handler, reraise) + # handle not found view as a vcs call + settings = request.registry.settings + ae_client = getattr(request, 'ae_client', None) + vcs_app = VCSMiddleware( + HTTPNotFound(), request.registry, settings, + appenlight_client=ae_client) - # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a - # view to handle the request. Therefore it is wrapped around the pylons - # app. It has to be outside of the error handling otherwise error responses - # from the vcsserver are converted to HTML error pages. This confuses the - # command line tools and the user won't get a meaningful error message. - if vcs_server_enabled: - pylons_app = VCSMiddleware( - pylons_app, settings, appenlight_client, registry=config.registry) - - # Convert WSGI app to pyramid view and return it. - return wsgiapp(pylons_app) - - -def add_pylons_compat_data(registry, global_config, settings): - """ - Attach data to the registry to support the Pylons integration. - """ - registry._pylons_compat_global_config = global_config - registry._pylons_compat_settings = settings + return wsgiapp(vcs_app)(None, request) def error_handler(exception, request): @@ -229,10 +129,6 @@ def error_handler(exception, request): elif isinstance(exception, VCSCommunicationError): base_response = VCSServerUnavailable() - def is_http_error(response): - # error which should have traceback - return response.status_code > 499 - if is_http_error(base_response): log.exception( 'error occurred handling this request for path: %s', request.path) @@ -272,26 +168,46 @@ def error_handler(exception, request): return response +def includeme_first(config): + # redirect automatic browser favicon.ico requests to correct place + def favicon_redirect(context, request): + return HTTPFound( + request.static_path('rhodecode:public/images/favicon.ico')) + + config.add_view(favicon_redirect, route_name='favicon') + config.add_route('favicon', '/favicon.ico') + + def robots_redirect(context, request): + return HTTPFound( + request.static_path('rhodecode:public/robots.txt')) + + config.add_view(robots_redirect, route_name='robots') + config.add_route('robots', '/robots.txt') + + config.add_static_view( + '_static/deform', 'deform:static') + config.add_static_view( + '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24) + + def includeme(config): settings = config.registry.settings # plugin information - config.registry.rhodecode_plugins = OrderedDict() + config.registry.rhodecode_plugins = collections.OrderedDict() config.add_directive( 'register_rhodecode_plugin', register_rhodecode_plugin) + config.add_directive('configure_celery', configure_celery) + if asbool(settings.get('appenlight', 'false')): config.include('appenlight_client.ext.pyramid_tween') - if 'mako.default_filters' not in settings: - # set custom default filters if we don't have it defined - settings['mako.imports'] = 'from rhodecode.lib.base import h_filter' - settings['mako.default_filters'] = 'h_filter' - # Includes which are required. The application would fail without them. config.include('pyramid_mako') config.include('pyramid_beaker') + config.include('rhodecode.lib.caches') config.include('rhodecode.authentication') config.include('rhodecode.integrations') @@ -331,16 +247,17 @@ def includeme(config): config.add_subscriber(write_metadata_if_needed, ApplicationCreated) config.add_subscriber(write_js_routes_if_enabled, ApplicationCreated) - config.add_request_method( - 'rhodecode.lib.partial_renderer.get_partial_renderer', - 'get_partial_renderer') - # events # TODO(marcink): this should be done when pyramid migration is finished # config.add_subscriber( # 'rhodecode.integrations.integrations_event_handler', # 'rhodecode.events.RhodecodeEvent') + # request custom methods + config.add_request_method( + 'rhodecode.lib.partial_renderer.get_partial_renderer', + 'get_partial_renderer') + # Set the authorization policy. authz_policy = ACLAuthorizationPolicy() config.set_authorization_policy(authz_policy) @@ -357,65 +274,29 @@ def includeme(config): for inc in includes: config.include(inc) - # This is the glue which allows us to migrate in chunks. By registering the - # pylons based application as the "Not Found" view in Pyramid, we will - # fallback to the old application each time the new one does not yet know - # how to handle a request. - config.add_notfound_view(make_not_found_view(config)) - + # custom not found view, if our pyramid app doesn't know how to handle + # the request pass it to potential VCS handling ap + config.add_notfound_view(not_found_view) if not settings.get('debugtoolbar.enabled', False): # disabled debugtoolbar handle all exceptions via the error_handlers config.add_view(error_handler, context=Exception) + # all errors including 403/404/50X config.add_view(error_handler, context=HTTPError) -def includeme_first(config): - # redirect automatic browser favicon.ico requests to correct place - def favicon_redirect(context, request): - return HTTPFound( - request.static_path('rhodecode:public/images/favicon.ico')) - - config.add_view(favicon_redirect, route_name='favicon') - config.add_route('favicon', '/favicon.ico') - - def robots_redirect(context, request): - return HTTPFound( - request.static_path('rhodecode:public/robots.txt')) - - config.add_view(robots_redirect, route_name='robots') - config.add_route('robots', '/robots.txt') - - config.add_static_view( - '_static/deform', 'deform:static') - config.add_static_view( - '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24) - - def wrap_app_in_wsgi_middlewares(pyramid_app, config): """ Apply outer WSGI middlewares around the application. - - Part of this has been moved up from the Pylons layer, so that the - data is also available if old Pylons code is hit through an already ported - view. """ settings = config.registry.settings # enable https redirects based on HTTP_X_URL_SCHEME set by proxy pyramid_app = HttpsFixup(pyramid_app, settings) - # Add RoutesMiddleware to support the pylons compatibility tween during - # migration to pyramid. - - # TODO(marcink): remove after migration to pyramid - if hasattr(config.registry, '_pylons_compat_config'): - routes_map = config.registry._pylons_compat_config['routes.map'] - pyramid_app = SkippableRoutesMiddleware( - pyramid_app, routes_map, - skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar')) - - pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings) + pyramid_app, _ae_client = wrap_in_appenlight_if_enabled( + pyramid_app, settings) + config.registry.ae_client = _ae_client if settings['gzip_responses']: pyramid_app = make_gzip_middleware( @@ -452,16 +333,21 @@ def sanitize_settings_and_apply_defaults function. """ - # Pyramid's mako renderer has to search in the templates folder so that the - # old templates still work. Ported and new templates are expected to use - # real asset specifications for the includes. - mako_directories = settings.setdefault('mako.directories', [ - # Base templates of the original Pylons application - 'rhodecode:templates', - ]) - log.debug( - "Using the following Mako template directories: %s", - mako_directories) + settings.setdefault('rhodecode.edition', 'Community Edition') + + if 'mako.default_filters' not in settings: + # set custom default filters if we don't have it defined + settings['mako.imports'] = 'from rhodecode.lib.base import h_filter' + settings['mako.default_filters'] = 'h_filter' + + if 'mako.directories' not in settings: + mako_directories = settings.setdefault('mako.directories', [ + # Base templates of the original application + 'rhodecode:templates', + ]) + log.debug( + "Using the following Mako template directories: %s", + mako_directories) # Default includes, possible to change as a user pyramid_includes = settings.setdefault('pyramid.includes', [ @@ -526,10 +412,10 @@ def _int_setting(settings, name, default def _bool_setting(settings, name, default): - input = settings.get(name, default) - if isinstance(input, unicode): - input = input.encode('utf8') - settings[name] = asbool(input) + input_val = settings.get(name, default) + if isinstance(input_val, unicode): + input_val = input_val.encode('utf8') + settings[name] = asbool(input_val) def _list_setting(settings, name, default): diff --git a/rhodecode/config/patches.py b/rhodecode/config/patches.py --- a/rhodecode/config/patches.py +++ b/rhodecode/config/patches.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -32,26 +32,10 @@ Please keep the following principles in """ -def kombu_1_5_1_python_2_7_11(): - """ - Kombu 1.5.1 relies on a private method which got removed in Python 2.7.11. - - This patch adds the symbol to the module :mod:`uuid` and assigns the value - ``None`` to it. This causes kombu to fall back to the public API of - :mod:`uuid`. - - This patch can most probably be removed once celery and kombu are updated - to more recent versions. - """ - import uuid - - if not hasattr(uuid, '_uuid_generate_random'): - uuid._uuid_generate_random = None - def inspect_getargspec(): """ - Pyramid and Pylons rely on inspect.getargspec to lookup the signature of + Pyramid rely on inspect.getargspec to lookup the signature of view functions. This is not compatible with cython, therefore we replace getargspec with a custom version. Code is inspired by the inspect module from Python-3.4 diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py deleted file mode 100644 --- a/rhodecode/config/routing.py +++ /dev/null @@ -1,264 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (C) 2010-2017 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 . -# -# 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/ - -""" -Routes configuration - -The more specific and detailed routes should be defined first so they -may take precedent over the more generic routes. For more information -refer to the routes manual at http://routes.groovie.org/docs/ - -IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py -and _route_name variable which uses some of stored naming here to do redirects. -""" -import os -import re -from routes import Mapper - -# prefix for non repository related links needs to be prefixed with `/` -ADMIN_PREFIX = '/_admin' -STATIC_FILE_PREFIX = '/_static' - -# Default requirements for URL parts -URL_NAME_REQUIREMENTS = { - # group name can have a slash in them, but they must not end with a slash - 'group_name': r'.*?[^/]', - 'repo_group_name': r'.*?[^/]', - # repo names can have a slash in them, but they must not end with a slash - 'repo_name': r'.*?[^/]', - # file path eats up everything at the end - 'f_path': r'.*', - # reference types - 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)', - 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)', -} - - -class JSRoutesMapper(Mapper): - """ - Wrapper for routes.Mapper to make pyroutes compatible url definitions - """ - _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$') - _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)') - def __init__(self, *args, **kw): - super(JSRoutesMapper, self).__init__(*args, **kw) - self._jsroutes = [] - - def connect(self, *args, **kw): - """ - Wrapper for connect to take an extra argument jsroute=True - - :param jsroute: boolean, if True will add the route to the pyroutes list - """ - if kw.pop('jsroute', False): - if not self._named_route_regex.match(args[0]): - raise Exception('only named routes can be added to pyroutes') - self._jsroutes.append(args[0]) - - super(JSRoutesMapper, self).connect(*args, **kw) - - def _extract_route_information(self, route): - """ - Convert a route into tuple(name, path, args), eg: - ('show_user', '/profile/%(username)s', ['username']) - """ - routepath = route.routepath - def replace(matchobj): - if matchobj.group(1): - return "%%(%s)s" % matchobj.group(1).split(':')[0] - else: - return "%%(%s)s" % matchobj.group(2) - - routepath = self._argument_prog.sub(replace, routepath) - return ( - route.name, - routepath, - [(arg[0].split(':')[0] if arg[0] != '' else arg[1]) - for arg in self._argument_prog.findall(route.routepath)] - ) - - def jsroutes(self): - """ - Return a list of pyroutes.js compatible routes - """ - for route_name in self._jsroutes: - yield self._extract_route_information(self._routenames[route_name]) - - -def make_map(config): - """Create, configure and return the routes Mapper""" - rmap = JSRoutesMapper( - directory=config['pylons.paths']['controllers'], - always_scan=config['debug']) - rmap.minimization = False - rmap.explicit = False - - from rhodecode.lib.utils2 import str2bool - from rhodecode.model import repo, repo_group - - def check_repo(environ, match_dict): - """ - check for valid repository for proper 404 handling - - :param environ: - :param match_dict: - """ - repo_name = match_dict.get('repo_name') - - if match_dict.get('f_path'): - # fix for multiple initial slashes that causes errors - match_dict['f_path'] = match_dict['f_path'].lstrip('/') - repo_model = repo.RepoModel() - by_name_match = repo_model.get_by_repo_name(repo_name) - # if we match quickly from database, short circuit the operation, - # and validate repo based on the type. - if by_name_match: - return True - - by_id_match = repo_model.get_repo_by_id(repo_name) - if by_id_match: - repo_name = by_id_match.repo_name - match_dict['repo_name'] = repo_name - return True - - return False - - def check_group(environ, match_dict): - """ - check for valid repository group path for proper 404 handling - - :param environ: - :param match_dict: - """ - repo_group_name = match_dict.get('group_name') - repo_group_model = repo_group.RepoGroupModel() - by_name_match = repo_group_model.get_by_group_name(repo_group_name) - if by_name_match: - return True - - return False - - def check_user_group(environ, match_dict): - """ - check for valid user group for proper 404 handling - - :param environ: - :param match_dict: - """ - return True - - def check_int(environ, match_dict): - return match_dict.get('id').isdigit() - - - #========================================================================== - # CUSTOM ROUTES HERE - #========================================================================== - - # ADMIN SETTINGS ROUTES - with rmap.submapper(path_prefix=ADMIN_PREFIX, - controller='admin/settings') as m: - - # default - m.connect('admin_settings', '/settings', - action='settings_global_update', - conditions={'method': ['POST']}) - m.connect('admin_settings', '/settings', - action='settings_global', conditions={'method': ['GET']}) - - m.connect('admin_settings_vcs', '/settings/vcs', - action='settings_vcs_update', - conditions={'method': ['POST']}) - m.connect('admin_settings_vcs', '/settings/vcs', - action='settings_vcs', - conditions={'method': ['GET']}) - m.connect('admin_settings_vcs', '/settings/vcs', - action='delete_svn_pattern', - conditions={'method': ['DELETE']}) - - m.connect('admin_settings_mapping', '/settings/mapping', - action='settings_mapping_update', - conditions={'method': ['POST']}) - m.connect('admin_settings_mapping', '/settings/mapping', - action='settings_mapping', conditions={'method': ['GET']}) - - m.connect('admin_settings_global', '/settings/global', - action='settings_global_update', - conditions={'method': ['POST']}) - m.connect('admin_settings_global', '/settings/global', - action='settings_global', conditions={'method': ['GET']}) - - m.connect('admin_settings_visual', '/settings/visual', - action='settings_visual_update', - conditions={'method': ['POST']}) - m.connect('admin_settings_visual', '/settings/visual', - action='settings_visual', conditions={'method': ['GET']}) - - m.connect('admin_settings_issuetracker', - '/settings/issue-tracker', action='settings_issuetracker', - conditions={'method': ['GET']}) - m.connect('admin_settings_issuetracker_save', - '/settings/issue-tracker/save', - action='settings_issuetracker_save', - conditions={'method': ['POST']}) - m.connect('admin_issuetracker_test', '/settings/issue-tracker/test', - action='settings_issuetracker_test', - conditions={'method': ['POST']}) - m.connect('admin_issuetracker_delete', - '/settings/issue-tracker/delete', - action='settings_issuetracker_delete', - conditions={'method': ['DELETE']}) - - m.connect('admin_settings_email', '/settings/email', - action='settings_email_update', - conditions={'method': ['POST']}) - m.connect('admin_settings_email', '/settings/email', - action='settings_email', conditions={'method': ['GET']}) - - m.connect('admin_settings_hooks', '/settings/hooks', - action='settings_hooks_update', - conditions={'method': ['POST', 'DELETE']}) - m.connect('admin_settings_hooks', '/settings/hooks', - action='settings_hooks', conditions={'method': ['GET']}) - - m.connect('admin_settings_search', '/settings/search', - action='settings_search', conditions={'method': ['GET']}) - - m.connect('admin_settings_supervisor', '/settings/supervisor', - action='settings_supervisor', conditions={'method': ['GET']}) - m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log', - action='settings_supervisor_log', conditions={'method': ['GET']}) - - m.connect('admin_settings_labs', '/settings/labs', - action='settings_labs_update', - conditions={'method': ['POST']}) - m.connect('admin_settings_labs', '/settings/labs', - action='settings_labs', conditions={'method': ['GET']}) - - # ADMIN MY ACCOUNT - with rmap.submapper(path_prefix=ADMIN_PREFIX, - controller='admin/my_account') as m: - - # NOTE(marcink): this needs to be kept for password force flag to be - # handled in pylons controllers, remove after full migration to pyramid - m.connect('my_account_password', '/my_account/password', - action='my_account_password', conditions={'method': ['GET']}) - - return rmap diff --git a/rhodecode/config/routing_links.py b/rhodecode/config/routing_links.py --- a/rhodecode/config/routing_links.py +++ b/rhodecode/config/routing_links.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/config/utils.py b/rhodecode/config/utils.py --- a/rhodecode/config/utils.py +++ b/rhodecode/config/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/controllers/__init__.py b/rhodecode/controllers/__init__.py --- a/rhodecode/controllers/__init__.py +++ b/rhodecode/controllers/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/controllers/admin/__init__.py b/rhodecode/controllers/admin/__init__.py deleted file mode 100644 --- a/rhodecode/controllers/admin/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (C) 2010-2017 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 . -# -# 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/ diff --git a/rhodecode/controllers/admin/settings.py b/rhodecode/controllers/admin/settings.py deleted file mode 100644 --- a/rhodecode/controllers/admin/settings.py +++ /dev/null @@ -1,697 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (C) 2010-2017 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 . -# -# 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/ - - -""" -settings controller for rhodecode admin -""" - -import collections -import logging - -import datetime -import formencode -from formencode import htmlfill -from pylons import request, tmpl_context as c, url, config -from pylons.controllers.util import redirect -from pylons.i18n.translation import _ -from pylons.decorators import jsonify -from pyramid.threadlocal import get_current_registry -from webob.exc import HTTPBadRequest - -import rhodecode -from rhodecode.apps.admin.navigation import navigation_list -from rhodecode.apps.svn_support.config_keys import generate_config -from rhodecode.lib import auth -from rhodecode.lib import helpers as h -from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator -from rhodecode.lib.base import BaseController, render -from rhodecode.lib.celerylib import tasks, run_task -from rhodecode.lib.utils import repo2db_mapper -from rhodecode.lib.utils2 import ( - str2bool, safe_unicode, AttributeDict, safe_int) -from rhodecode.lib.compat import OrderedDict - -from rhodecode.model.db import RhodeCodeUi, Repository -from rhodecode.model.forms import ApplicationSettingsForm, \ - ApplicationUiSettingsForm, ApplicationVisualisationForm, \ - LabsSettingsForm, IssueTrackerPatternsForm -from rhodecode.model.repo_group import RepoGroupModel - -from rhodecode.model.scm import ScmModel -from rhodecode.model.notification import EmailNotificationModel -from rhodecode.model.meta import Session -from rhodecode.model.settings import ( - IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound, - SettingsModel) - -from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER - - -log = logging.getLogger(__name__) - - -class SettingsController(BaseController): - """REST Controller styled on the Atom Publishing Protocol""" - # To properly map this controller, ensure your config/routing.py - # file has a resource setup: - # map.resource('setting', 'settings', controller='admin/settings', - # path_prefix='/admin', name_prefix='admin_') - - @LoginRequired() - def __before__(self): - super(SettingsController, self).__before__() - c.labs_active = str2bool( - rhodecode.CONFIG.get('labs_settings_active', 'true')) - c.navlist = navigation_list(request) - - def _get_ui_settings(self): - ret = RhodeCodeUi.query().all() - - if not ret: - raise Exception('Could not get application ui settings !') - settings = {} - for each in ret: - k = each.ui_key - v = each.ui_value - if k == '/': - k = 'root_path' - - if k in ['push_ssl', 'publish', 'enabled']: - v = str2bool(v) - - if k.find('.') != -1: - k = k.replace('.', '_') - - if each.ui_section in ['hooks', 'extensions']: - v = each.ui_active - - settings[each.ui_section + '_' + k] = v - return settings - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - @jsonify - def delete_svn_pattern(self): - if not request.is_xhr: - raise HTTPBadRequest() - - delete_pattern_id = request.POST.get('delete_svn_pattern') - model = VcsSettingsModel() - try: - model.delete_global_svn_pattern(delete_pattern_id) - except SettingNotFound: - raise HTTPBadRequest() - - Session().commit() - return True - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_vcs_update(self): - """POST /admin/settings: All items in the collection""" - # url('admin_settings_vcs') - c.active = 'vcs' - - model = VcsSettingsModel() - c.svn_branch_patterns = model.get_global_svn_branch_patterns() - c.svn_tag_patterns = model.get_global_svn_tag_patterns() - - # TODO: Replace with request.registry after migrating to pyramid. - pyramid_settings = get_current_registry().settings - c.svn_proxy_generate_config = pyramid_settings[generate_config] - - application_form = ApplicationUiSettingsForm()() - - try: - form_result = application_form.to_python(dict(request.POST)) - except formencode.Invalid as errors: - h.flash( - _("Some form inputs contain invalid data."), - category='error') - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=errors.value, - errors=errors.error_dict or {}, - prefix_error=False, - encoding="UTF-8", - force_defaults=False - ) - - try: - if c.visual.allow_repo_location_change: - model.update_global_path_setting( - form_result['paths_root_path']) - - model.update_global_ssl_setting(form_result['web_push_ssl']) - model.update_global_hook_settings(form_result) - - model.create_or_update_global_svn_settings(form_result) - model.create_or_update_global_hg_settings(form_result) - model.create_or_update_global_git_settings(form_result) - model.create_or_update_global_pr_settings(form_result) - except Exception: - log.exception("Exception while updating settings") - h.flash(_('Error occurred during updating ' - 'application settings'), category='error') - else: - Session().commit() - h.flash(_('Updated VCS settings'), category='success') - return redirect(url('admin_settings_vcs')) - - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=self._form_defaults(), - encoding="UTF-8", - force_defaults=False) - - @HasPermissionAllDecorator('hg.admin') - def settings_vcs(self): - """GET /admin/settings: All items in the collection""" - # url('admin_settings_vcs') - c.active = 'vcs' - model = VcsSettingsModel() - c.svn_branch_patterns = model.get_global_svn_branch_patterns() - c.svn_tag_patterns = model.get_global_svn_tag_patterns() - - # TODO: Replace with request.registry after migrating to pyramid. - pyramid_settings = get_current_registry().settings - c.svn_proxy_generate_config = pyramid_settings[generate_config] - - defaults = self._form_defaults() - - model.create_largeobjects_dirs_if_needed(defaults['paths_root_path']) - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=defaults, - encoding="UTF-8", - force_defaults=False) - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_mapping_update(self): - """POST /admin/settings/mapping: All items in the collection""" - # url('admin_settings_mapping') - c.active = 'mapping' - rm_obsolete = request.POST.get('destroy', False) - invalidate_cache = request.POST.get('invalidate', False) - log.debug( - 'rescanning repo location with destroy obsolete=%s', rm_obsolete) - - if invalidate_cache: - log.debug('invalidating all repositories cache') - for repo in Repository.get_all(): - ScmModel().mark_for_invalidation(repo.repo_name, delete=True) - - filesystem_repos = ScmModel().repo_scan() - added, removed = repo2db_mapper(filesystem_repos, rm_obsolete) - _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-' - h.flash(_('Repositories successfully ' - 'rescanned added: %s ; removed: %s') % - (_repr(added), _repr(removed)), - category='success') - return redirect(url('admin_settings_mapping')) - - @HasPermissionAllDecorator('hg.admin') - def settings_mapping(self): - """GET /admin/settings/mapping: All items in the collection""" - # url('admin_settings_mapping') - c.active = 'mapping' - - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=self._form_defaults(), - encoding="UTF-8", - force_defaults=False) - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_global_update(self): - """POST /admin/settings/global: All items in the collection""" - # url('admin_settings_global') - c.active = 'global' - c.personal_repo_group_default_pattern = RepoGroupModel()\ - .get_personal_group_name_pattern() - application_form = ApplicationSettingsForm()() - try: - form_result = application_form.to_python(dict(request.POST)) - except formencode.Invalid as errors: - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=errors.value, - errors=errors.error_dict or {}, - prefix_error=False, - encoding="UTF-8", - force_defaults=False) - - try: - settings = [ - ('title', 'rhodecode_title', 'unicode'), - ('realm', 'rhodecode_realm', 'unicode'), - ('pre_code', 'rhodecode_pre_code', 'unicode'), - ('post_code', 'rhodecode_post_code', 'unicode'), - ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'), - ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'), - ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'), - ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'), - ] - for setting, form_key, type_ in settings: - sett = SettingsModel().create_or_update_setting( - setting, form_result[form_key], type_) - Session().add(sett) - - Session().commit() - SettingsModel().invalidate_settings_cache() - h.flash(_('Updated application settings'), category='success') - except Exception: - log.exception("Exception while updating application settings") - h.flash( - _('Error occurred during updating application settings'), - category='error') - - return redirect(url('admin_settings_global')) - - @HasPermissionAllDecorator('hg.admin') - def settings_global(self): - """GET /admin/settings/global: All items in the collection""" - # url('admin_settings_global') - c.active = 'global' - c.personal_repo_group_default_pattern = RepoGroupModel()\ - .get_personal_group_name_pattern() - - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=self._form_defaults(), - encoding="UTF-8", - force_defaults=False) - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_visual_update(self): - """POST /admin/settings/visual: All items in the collection""" - # url('admin_settings_visual') - c.active = 'visual' - application_form = ApplicationVisualisationForm()() - try: - form_result = application_form.to_python(dict(request.POST)) - except formencode.Invalid as errors: - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=errors.value, - errors=errors.error_dict or {}, - prefix_error=False, - encoding="UTF-8", - force_defaults=False - ) - - try: - settings = [ - ('show_public_icon', 'rhodecode_show_public_icon', 'bool'), - ('show_private_icon', 'rhodecode_show_private_icon', 'bool'), - ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'), - ('repository_fields', 'rhodecode_repository_fields', 'bool'), - ('dashboard_items', 'rhodecode_dashboard_items', 'int'), - ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'), - ('show_version', 'rhodecode_show_version', 'bool'), - ('use_gravatar', 'rhodecode_use_gravatar', 'bool'), - ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'), - ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'), - ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'), - ('support_url', 'rhodecode_support_url', 'unicode'), - ('show_revision_number', 'rhodecode_show_revision_number', 'bool'), - ('show_sha_length', 'rhodecode_show_sha_length', 'int'), - ] - for setting, form_key, type_ in settings: - sett = SettingsModel().create_or_update_setting( - setting, form_result[form_key], type_) - Session().add(sett) - - Session().commit() - SettingsModel().invalidate_settings_cache() - h.flash(_('Updated visualisation settings'), category='success') - except Exception: - log.exception("Exception updating visualization settings") - h.flash(_('Error occurred during updating ' - 'visualisation settings'), - category='error') - - return redirect(url('admin_settings_visual')) - - @HasPermissionAllDecorator('hg.admin') - def settings_visual(self): - """GET /admin/settings/visual: All items in the collection""" - # url('admin_settings_visual') - c.active = 'visual' - - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=self._form_defaults(), - encoding="UTF-8", - force_defaults=False) - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_issuetracker_test(self): - if request.is_xhr: - return h.urlify_commit_message( - request.POST.get('test_text', ''), - 'repo_group/test_repo1') - else: - raise HTTPBadRequest() - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_issuetracker_delete(self): - uid = request.POST.get('uid') - IssueTrackerSettingsModel().delete_entries(uid) - h.flash(_('Removed issue tracker entry'), category='success') - return redirect(url('admin_settings_issuetracker')) - - @HasPermissionAllDecorator('hg.admin') - def settings_issuetracker(self): - """GET /admin/settings/issue-tracker: All items in the collection""" - # url('admin_settings_issuetracker') - c.active = 'issuetracker' - defaults = SettingsModel().get_all_settings() - - entry_key = 'rhodecode_issuetracker_pat_' - - c.issuetracker_entries = {} - for k, v in defaults.items(): - if k.startswith(entry_key): - uid = k[len(entry_key):] - c.issuetracker_entries[uid] = None - - for uid in c.issuetracker_entries: - c.issuetracker_entries[uid] = AttributeDict({ - 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid), - 'url': defaults.get('rhodecode_issuetracker_url_' + uid), - 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid), - 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid), - }) - - return render('admin/settings/settings.mako') - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_issuetracker_save(self): - settings_model = IssueTrackerSettingsModel() - - form = IssueTrackerPatternsForm()().to_python(request.POST) - if form: - for uid in form.get('delete_patterns', []): - settings_model.delete_entries(uid) - - for pattern in form.get('patterns', []): - for setting, value, type_ in pattern: - sett = settings_model.create_or_update_setting( - setting, value, type_) - Session().add(sett) - - Session().commit() - - SettingsModel().invalidate_settings_cache() - h.flash(_('Updated issue tracker entries'), category='success') - return redirect(url('admin_settings_issuetracker')) - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_email_update(self): - """POST /admin/settings/email: All items in the collection""" - # url('admin_settings_email') - c.active = 'email' - - test_email = request.POST.get('test_email') - - if not test_email: - h.flash(_('Please enter email address'), category='error') - return redirect(url('admin_settings_email')) - - email_kwargs = { - 'date': datetime.datetime.now(), - 'user': c.rhodecode_user, - 'rhodecode_version': c.rhodecode_version - } - - (subject, headers, email_body, - email_body_plaintext) = EmailNotificationModel().render_email( - EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs) - - recipients = [test_email] if test_email else None - - run_task(tasks.send_email, recipients, subject, - email_body_plaintext, email_body) - - h.flash(_('Send email task created'), category='success') - return redirect(url('admin_settings_email')) - - @HasPermissionAllDecorator('hg.admin') - def settings_email(self): - """GET /admin/settings/email: All items in the collection""" - # url('admin_settings_email') - c.active = 'email' - c.rhodecode_ini = rhodecode.CONFIG - - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=self._form_defaults(), - encoding="UTF-8", - force_defaults=False) - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_hooks_update(self): - """POST or DELETE /admin/settings/hooks: All items in the collection""" - # url('admin_settings_hooks') - c.active = 'hooks' - if c.visual.allow_custom_hooks_settings: - ui_key = request.POST.get('new_hook_ui_key') - ui_value = request.POST.get('new_hook_ui_value') - - hook_id = request.POST.get('hook_id') - new_hook = False - - model = SettingsModel() - try: - if ui_value and ui_key: - model.create_or_update_hook(ui_key, ui_value) - h.flash(_('Added new hook'), category='success') - new_hook = True - elif hook_id: - RhodeCodeUi.delete(hook_id) - Session().commit() - - # check for edits - update = False - _d = request.POST.dict_of_lists() - for k, v in zip(_d.get('hook_ui_key', []), - _d.get('hook_ui_value_new', [])): - model.create_or_update_hook(k, v) - update = True - - if update and not new_hook: - h.flash(_('Updated hooks'), category='success') - Session().commit() - except Exception: - log.exception("Exception during hook creation") - h.flash(_('Error occurred during hook creation'), - category='error') - - return redirect(url('admin_settings_hooks')) - - @HasPermissionAllDecorator('hg.admin') - def settings_hooks(self): - """GET /admin/settings/hooks: All items in the collection""" - # url('admin_settings_hooks') - c.active = 'hooks' - - model = SettingsModel() - c.hooks = model.get_builtin_hooks() - c.custom_hooks = model.get_custom_hooks() - - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=self._form_defaults(), - encoding="UTF-8", - force_defaults=False) - - @HasPermissionAllDecorator('hg.admin') - def settings_search(self): - """GET /admin/settings/search: All items in the collection""" - # url('admin_settings_search') - c.active = 'search' - - from rhodecode.lib.index import searcher_from_config - searcher = searcher_from_config(config) - c.statistics = searcher.statistics() - - return render('admin/settings/settings.mako') - - @HasPermissionAllDecorator('hg.admin') - def settings_supervisor(self): - c.rhodecode_ini = rhodecode.CONFIG - c.active = 'supervisor' - - c.supervisor_procs = OrderedDict([ - (SUPERVISOR_MASTER, {}), - ]) - - c.log_size = 10240 - supervisor = SupervisorModel() - - _connection = supervisor.get_connection( - c.rhodecode_ini.get('supervisor.uri')) - c.connection_error = None - try: - _connection.supervisor.getAllProcessInfo() - except Exception as e: - c.connection_error = str(e) - log.exception("Exception reading supervisor data") - return render('admin/settings/settings.mako') - - groupid = c.rhodecode_ini.get('supervisor.group_id') - - # feed our group processes to the main - for proc in supervisor.get_group_processes(_connection, groupid): - c.supervisor_procs[proc['name']] = {} - - for k in c.supervisor_procs.keys(): - try: - # master process info - if k == SUPERVISOR_MASTER: - _data = supervisor.get_master_state(_connection) - _data['name'] = 'supervisor master' - _data['description'] = 'pid %s, id: %s, ver: %s' % ( - _data['pid'], _data['id'], _data['ver']) - c.supervisor_procs[k] = _data - else: - procid = groupid + ":" + k - c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid) - except Exception as e: - log.exception("Exception reading supervisor data") - c.supervisor_procs[k] = {'_rhodecode_error': str(e)} - - return render('admin/settings/settings.mako') - - @HasPermissionAllDecorator('hg.admin') - def settings_supervisor_log(self, procid): - import rhodecode - c.rhodecode_ini = rhodecode.CONFIG - c.active = 'supervisor_tail' - - supervisor = SupervisorModel() - _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri')) - groupid = c.rhodecode_ini.get('supervisor.group_id') - procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid - - c.log_size = 10240 - offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1 - c.log = supervisor.read_process_log(_connection, procid, offset, 0) - - return render('admin/settings/settings.mako') - - @HasPermissionAllDecorator('hg.admin') - @auth.CSRFRequired() - def settings_labs_update(self): - """POST /admin/settings/labs: All items in the collection""" - # url('admin_settings/labs', method={'POST'}) - c.active = 'labs' - - application_form = LabsSettingsForm()() - try: - form_result = application_form.to_python(dict(request.POST)) - except formencode.Invalid as errors: - h.flash( - _('Some form inputs contain invalid data.'), - category='error') - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=errors.value, - errors=errors.error_dict or {}, - prefix_error=False, - encoding='UTF-8', - force_defaults=False - ) - - try: - session = Session() - for setting in _LAB_SETTINGS: - setting_name = setting.key[len('rhodecode_'):] - sett = SettingsModel().create_or_update_setting( - setting_name, form_result[setting.key], setting.type) - session.add(sett) - - except Exception: - log.exception('Exception while updating lab settings') - h.flash(_('Error occurred during updating labs settings'), - category='error') - else: - Session().commit() - SettingsModel().invalidate_settings_cache() - h.flash(_('Updated Labs settings'), category='success') - return redirect(url('admin_settings_labs')) - - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=self._form_defaults(), - encoding='UTF-8', - force_defaults=False) - - @HasPermissionAllDecorator('hg.admin') - def settings_labs(self): - """GET /admin/settings/labs: All items in the collection""" - # url('admin_settings_labs') - if not c.labs_active: - redirect(url('admin_settings')) - - c.active = 'labs' - c.lab_settings = _LAB_SETTINGS - - return htmlfill.render( - render('admin/settings/settings.mako'), - defaults=self._form_defaults(), - encoding='UTF-8', - force_defaults=False) - - def _form_defaults(self): - defaults = SettingsModel().get_all_settings() - defaults.update(self._get_ui_settings()) - - defaults.update({ - 'new_svn_branch': '', - 'new_svn_tag': '', - }) - return defaults - - -# :param key: name of the setting including the 'rhodecode_' prefix -# :param type: the RhodeCodeSetting type to use. -# :param group: the i18ned group in which we should dispaly this setting -# :param label: the i18ned label we should display for this setting -# :param help: the i18ned help we should dispaly for this setting -LabSetting = collections.namedtuple( - 'LabSetting', ('key', 'type', 'group', 'label', 'help')) - - -# This list has to be kept in sync with the form -# rhodecode.model.forms.LabsSettingsForm. -_LAB_SETTINGS = [ - -] diff --git a/rhodecode/controllers/utils.py b/rhodecode/controllers/utils.py --- a/rhodecode/controllers/utils.py +++ b/rhodecode/controllers/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/events/__init__.py b/rhodecode/events/__init__.py --- a/rhodecode/events/__init__.py +++ b/rhodecode/events/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/events/base.py b/rhodecode/events/base.py --- a/rhodecode/events/base.py +++ b/rhodecode/events/base.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/events/interfaces.py b/rhodecode/events/interfaces.py --- a/rhodecode/events/interfaces.py +++ b/rhodecode/events/interfaces.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/events/pullrequest.py b/rhodecode/events/pullrequest.py --- a/rhodecode/events/pullrequest.py +++ b/rhodecode/events/pullrequest.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/events/repo.py b/rhodecode/events/repo.py --- a/rhodecode/events/repo.py +++ b/rhodecode/events/repo.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 @@ -18,6 +18,7 @@ import collections import logging +import datetime from rhodecode.translation import lazy_ugettext from rhodecode.model.db import User, Repository, Session @@ -58,21 +59,60 @@ def _commits_as_dict(event, commit_ids, return commits # return early if we have the commits we need vcs_repo = repo.scm_instance(cache=False) + try: # use copy of needed_commits since we modify it while iterating for commit_id in list(needed_commits): - try: - cs = vcs_repo.get_changeset(commit_id) - except CommitDoesNotExistError: - continue # maybe its in next repo + if commit_id.startswith('tag=>'): + raw_id = commit_id[5:] + cs_data = { + 'raw_id': commit_id, 'short_id': commit_id, + 'branch': None, + 'git_ref_change': 'tag_add', + 'message': 'Added new tag {}'.format(raw_id), + 'author': event.actor.full_contact, + 'date': datetime.datetime.now(), + 'refs': { + 'branches': [], + 'bookmarks': [], + 'tags': [] + } + } + commits.append(cs_data) - cs_data = cs.__json__() + elif commit_id.startswith('delete_branch=>'): + raw_id = commit_id[15:] + cs_data = { + 'raw_id': commit_id, 'short_id': commit_id, + 'branch': None, + 'git_ref_change': 'branch_delete', + 'message': 'Deleted branch {}'.format(raw_id), + 'author': event.actor.full_contact, + 'date': datetime.datetime.now(), + 'refs': { + 'branches': [], + 'bookmarks': [], + 'tags': [] + } + } + commits.append(cs_data) + + else: + try: + cs = vcs_repo.get_changeset(commit_id) + except CommitDoesNotExistError: + continue # maybe its in next repo + + cs_data = cs.__json__() + cs_data['refs'] = cs._get_refs() + cs_data['mentions'] = extract_mentioned_users(cs_data['message']) cs_data['reviewers'] = reviewers cs_data['url'] = RepoModel().get_commit_url( repo, cs_data['raw_id'], request=event.request) cs_data['permalink_url'] = RepoModel().get_commit_url( - repo, cs_data['raw_id'], request=event.request, permalink=True) + repo, cs_data['raw_id'], request=event.request, + permalink=True) urlified_message, issues_data = process_patterns( cs_data['message'], repo.repo_name) cs_data['issues'] = issues_data @@ -84,8 +124,8 @@ def _commits_as_dict(event, commit_ids, needed_commits.remove(commit_id) - except Exception as e: - log.exception(e) + except Exception: + log.exception('Failed to extract commits data') # we don't send any commits when crash happens, only full list # matters we short circuit then. return [] @@ -247,6 +287,7 @@ class RepoPushEvent(RepoVCSEvent): def __init__(self, repo_name, pushed_commit_ids, extras): super(RepoPushEvent, self).__init__(repo_name, extras) self.pushed_commit_ids = pushed_commit_ids + self.new_refs = extras.new_refs def as_dict(self): data = super(RepoPushEvent, self).as_dict() @@ -255,6 +296,10 @@ class RepoPushEvent(RepoVCSEvent): return '{}/changelog?branch={}'.format( data['repo']['url'], branch_name) + def tag_url(tag_name): + return '{}/files/{}/'.format( + data['repo']['url'], tag_name) + commits = _commits_as_dict( self, commit_ids=self.pushed_commit_ids, repos=[self.repo]) @@ -264,8 +309,21 @@ class RepoPushEvent(RepoVCSEvent): last_branch = commit['branch'] issues = _issues_as_dict(commits) - branches = set( - commit['branch'] for commit in commits if commit['branch']) + branches = set() + tags = set() + for commit in commits: + if commit['refs']['tags']: + for tag in commit['refs']['tags']: + tags.add(tag) + if commit['branch']: + branches.add(commit['branch']) + + # maybe we have branches in new_refs ? + try: + branches = branches.union(set(self.new_refs['branches'])) + except Exception: + pass + branches = [ { 'name': branch, @@ -274,9 +332,24 @@ class RepoPushEvent(RepoVCSEvent): for branch in branches ] + # maybe we have branches in new_refs ? + try: + tags = tags.union(set(self.new_refs['tags'])) + except Exception: + pass + + tags = [ + { + 'name': tag, + 'url': tag_url(tag) + } + for tag in tags + ] + data['push'] = { 'commits': commits, 'issues': issues, 'branches': branches, + 'tags': tags, } return data diff --git a/rhodecode/events/repo_group.py b/rhodecode/events/repo_group.py --- a/rhodecode/events/repo_group.py +++ b/rhodecode/events/repo_group.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/events/user.py b/rhodecode/events/user.py --- a/rhodecode/events/user.py +++ b/rhodecode/events/user.py @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/forms/__init__.py b/rhodecode/forms/__init__.py --- a/rhodecode/forms/__init__.py +++ b/rhodecode/forms/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/i18n/rhodecode.pot b/rhodecode/i18n/rhodecode.pot --- a/rhodecode/i18n/rhodecode.pot +++ b/rhodecode/i18n/rhodecode.pot @@ -1,14 +1,14 @@ # Translations template for rhodecode-enterprise-ce. -# Copyright (C) 2017 RhodeCode GmbH +# Copyright (C) 2018 RhodeCode GmbH # This file is distributed under the same license as the rhodecode-enterprise-ce project. -# FIRST AUTHOR , 2017. +# FIRST AUTHOR , 2018. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: rhodecode-enterprise-ce 4.10.0\n" +"Project-Id-Version: rhodecode-enterprise-ce 4.11.0\n" "Report-Msgid-Bugs-To: marcin@rhodecode.com\n" -"POT-Creation-Date: 2017-11-06 12:44+0100\n" +"POT-Creation-Date: 2018-01-30 17:32+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,32 +17,51 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 1.3\n" -#: rhodecode/apps/admin/navigation.py:83 rhodecode/authentication/routes.py:60 +#: rhodecode/apps/_base/__init__.py:142 +#, python-format +msgid "Error creating repository %s: invalid certificate" +msgstr "" + +#: rhodecode/apps/_base/__init__.py:146 +#, python-format +msgid "Error creating repository %s" +msgstr "" + +#: rhodecode/apps/_base/__init__.py:219 +#, python-format +msgid "The repository `%(repo_name)s` cannot be loaded in filesystem. Please check if it exist, or is not damaged." +msgstr "" + +#: rhodecode/apps/_base/__init__.py:274 +msgid "Editing user `{}` is disabled." +msgstr "" + +#: rhodecode/apps/admin/navigation.py:72 rhodecode/authentication/routes.py:60 #: rhodecode/integrations/views.py:154 #: rhodecode/templates/admin/permissions/permissions.mako:36 msgid "Global" msgstr "" -#: rhodecode/apps/admin/navigation.py:84 +#: rhodecode/apps/admin/navigation.py:74 #: rhodecode/templates/admin/repos/repo_edit.mako:55 msgid "VCS" msgstr "" -#: rhodecode/apps/admin/navigation.py:85 +#: rhodecode/apps/admin/navigation.py:76 msgid "Visual" msgstr "" -#: rhodecode/apps/admin/navigation.py:86 +#: rhodecode/apps/admin/navigation.py:78 msgid "Remap and Rescan" msgstr "" -#: rhodecode/apps/admin/navigation.py:87 +#: rhodecode/apps/admin/navigation.py:80 #: rhodecode/templates/admin/repos/repo_edit.mako:61 msgid "Issue Tracker" msgstr "" -#: rhodecode/apps/admin/navigation.py:89 -#: rhodecode/integrations/types/email.py:232 +#: rhodecode/apps/admin/navigation.py:82 +#: rhodecode/integrations/types/email.py:233 #: rhodecode/templates/register.mako:76 #: rhodecode/templates/admin/my_account/my_account_profile.mako:48 #: rhodecode/templates/admin/my_account/my_account_profile_edit.mako:97 @@ -54,15 +73,15 @@ msgstr "" msgid "Email" msgstr "" -#: rhodecode/apps/admin/navigation.py:90 +#: rhodecode/apps/admin/navigation.py:84 msgid "Hooks" msgstr "" -#: rhodecode/apps/admin/navigation.py:91 +#: rhodecode/apps/admin/navigation.py:86 msgid "Full Text Search" msgstr "" -#: rhodecode/apps/admin/navigation.py:93 +#: rhodecode/apps/admin/navigation.py:88 #: rhodecode/templates/admin/integrations/base.mako:23 #: rhodecode/templates/admin/integrations/form.mako:8 #: rhodecode/templates/admin/integrations/form.mako:21 @@ -76,28 +95,28 @@ msgstr "" #: rhodecode/templates/admin/integrations/new.mako:23 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:51 #: rhodecode/templates/admin/repos/repo_edit.mako:75 -#: rhodecode/templates/base/base.mako:82 +#: rhodecode/templates/base/base.mako:84 msgid "Integrations" msgstr "" -#: rhodecode/apps/admin/navigation.py:95 +#: rhodecode/apps/admin/navigation.py:90 #: rhodecode/templates/admin/settings/settings_system.mako:9 msgid "System Info" msgstr "" -#: rhodecode/apps/admin/navigation.py:97 +#: rhodecode/apps/admin/navigation.py:92 msgid "Processes" msgstr "" -#: rhodecode/apps/admin/navigation.py:99 +#: rhodecode/apps/admin/navigation.py:94 msgid "User Sessions" msgstr "" +#: rhodecode/apps/admin/navigation.py:96 +msgid "Open Source Licenses" +msgstr "" + #: rhodecode/apps/admin/navigation.py:101 -msgid "Open Source Licenses" -msgstr "" - -#: rhodecode/apps/admin/navigation.py:109 msgid "Labs" msgstr "" @@ -109,13 +128,13 @@ msgstr "" msgid "Error occurred during update of default values" msgstr "" -#: rhodecode/apps/admin/views/permissions.py:121 +#: rhodecode/apps/admin/views/permissions.py:120 msgid "Application permissions updated successfully" msgstr "" -#: rhodecode/apps/admin/views/permissions.py:142 +#: rhodecode/apps/admin/views/permissions.py:141 #: rhodecode/apps/admin/views/permissions.py:213 -#: rhodecode/apps/admin/views/permissions.py:287 +#: rhodecode/apps/admin/views/permissions.py:288 msgid "Error occurred during update of permissions" msgstr "" @@ -123,11 +142,11 @@ msgstr "" msgid "Object permissions updated successfully" msgstr "" -#: rhodecode/apps/admin/views/permissions.py:267 +#: rhodecode/apps/admin/views/permissions.py:268 msgid "Global permissions updated successfully" msgstr "" -#: rhodecode/apps/admin/views/permissions.py:448 +#: rhodecode/apps/admin/views/permissions.py:450 #: rhodecode/templates/admin/gists/show.mako:63 #: rhodecode/templates/admin/integrations/list.mako:208 #: rhodecode/templates/admin/my_account/my_account_profile.mako:5 @@ -148,20 +167,20 @@ msgstr "" msgid "Edit" msgstr "" -#: rhodecode/apps/admin/views/permissions.py:476 +#: rhodecode/apps/admin/views/permissions.py:478 msgid "Updated SSH keys file: {}" msgstr "" -#: rhodecode/apps/admin/views/permissions.py:479 +#: rhodecode/apps/admin/views/permissions.py:481 msgid "SSH key support is disabled in .ini file" msgstr "" -#: rhodecode/apps/admin/views/repo_groups.py:180 +#: rhodecode/apps/admin/views/repo_groups.py:181 #, python-format msgid "Created repository group %s" msgstr "" -#: rhodecode/apps/admin/views/repo_groups.py:198 +#: rhodecode/apps/admin/views/repo_groups.py:199 #, python-format msgid "Error occurred during creation of repository group %s" msgstr "" @@ -170,10 +189,86 @@ msgstr "" msgid "Cleaned up old sessions" msgstr "" -#: rhodecode/apps/admin/views/sessions.py:98 +#: rhodecode/apps/admin/views/sessions.py:97 msgid "Failed to cleanup up old sessions" msgstr "" +#: rhodecode/apps/admin/views/settings.py:162 +#: rhodecode/apps/admin/views/settings.py:708 +#: rhodecode/apps/repository/views/repo_settings_vcs.py:124 +msgid "Some form inputs contain invalid data." +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:190 +#: rhodecode/apps/admin/views/settings.py:351 +msgid "Error occurred during updating application settings" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:194 +#: rhodecode/apps/repository/views/repo_settings_vcs.py:143 +msgid "Updated VCS settings" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:268 +#, python-format +msgid "Repositories successfully rescanned added: %s ; removed: %s" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:347 +msgid "Updated application settings" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:426 +msgid "Updated visualisation settings" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:429 +msgid "Error occurred during updating visualisation settings" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:491 +#: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:125 +msgid "Invalid issue tracker pattern: {}" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:508 +#: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:134 +msgid "Updated issue tracker entries" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:526 +#: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:89 +msgid "Removed issue tracker entry" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:563 +msgid "Please enter email address" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:581 +msgid "Send email task created" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:631 +msgid "Added new hook" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:646 +msgid "Updated hooks" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:650 +msgid "Error occurred during hook creation" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:732 +msgid "Error occurred during updating labs settings" +msgstr "" + +#: rhodecode/apps/admin/views/settings.py:737 +msgid "Updated Labs settings" +msgstr "" + #: rhodecode/apps/admin/views/svn_config.py:46 msgid "Apache configuration for Subversion generated." msgstr "" @@ -182,147 +277,151 @@ msgstr "" msgid "Failed to generate the Apache configuration for Subversion." msgstr "" +#: rhodecode/apps/admin/views/system_info.py:79 +msgid "Note: please make sure this server can access `${url}` for the update link to work" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:90 +msgid "Update info" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:92 +msgid "Check for updates" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:97 +msgid "RhodeCode Version" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:98 +msgid "Latest version" +msgstr "" + #: rhodecode/apps/admin/views/system_info.py:99 -msgid "Note: please make sure this server can access `${url}` for the update link to work" +msgid "RhodeCode Server IP" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:100 +msgid "RhodeCode Server ID" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:101 +msgid "RhodeCode Configuration" msgstr "" #: rhodecode/apps/admin/views/system_info.py:102 -msgid "Update info" +msgid "RhodeCode Certificate" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:103 +msgid "Workers" msgstr "" #: rhodecode/apps/admin/views/system_info.py:104 -msgid "Check for updates" +msgid "Worker Type" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:108 +msgid "Database" msgstr "" #: rhodecode/apps/admin/views/system_info.py:109 -msgid "RhodeCode Version" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:110 -msgid "RhodeCode Server IP" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:111 -msgid "RhodeCode Server ID" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:112 -msgid "RhodeCode Configuration" +msgid "Database version" msgstr "" #: rhodecode/apps/admin/views/system_info.py:113 -msgid "RhodeCode Certificate" +msgid "Platform" msgstr "" #: rhodecode/apps/admin/views/system_info.py:114 -msgid "Workers" +msgid "Platform UUID" msgstr "" #: rhodecode/apps/admin/views/system_info.py:115 -msgid "Worker Type" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:119 -msgid "Database" +msgid "Python version" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:116 +msgid "Python path" msgstr "" #: rhodecode/apps/admin/views/system_info.py:120 -msgid "Database version" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:124 -msgid "Platform" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:125 -msgid "Platform UUID" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:126 -msgid "Python version" +msgid "CPU" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:121 +msgid "Load" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:122 +msgid "Memory" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:123 +msgid "Uptime" msgstr "" #: rhodecode/apps/admin/views/system_info.py:127 -msgid "Python path" +msgid "Storage location" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:128 +msgid "Storage info" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:129 +msgid "Storage inodes" msgstr "" #: rhodecode/apps/admin/views/system_info.py:131 -msgid "CPU" +msgid "Gist storage location" msgstr "" #: rhodecode/apps/admin/views/system_info.py:132 -msgid "Load" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:133 -msgid "Memory" +msgid "Gist storage info" msgstr "" #: rhodecode/apps/admin/views/system_info.py:134 -msgid "Uptime" +msgid "Archive cache storage location" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:135 +msgid "Archive cache info" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:137 +msgid "Temp storage location" msgstr "" #: rhodecode/apps/admin/views/system_info.py:138 -msgid "Storage location" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:139 -msgid "Storage info" +msgid "Temp storage info" msgstr "" #: rhodecode/apps/admin/views/system_info.py:140 -msgid "Storage inodes" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:142 -msgid "Gist storage location" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:143 -msgid "Gist storage info" +msgid "Search info" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:141 +msgid "Search location" msgstr "" #: rhodecode/apps/admin/views/system_info.py:145 -msgid "Archive cache storage location" +msgid "VCS Backends" msgstr "" #: rhodecode/apps/admin/views/system_info.py:146 -msgid "Archive cache info" +msgid "VCS Server" +msgstr "" + +#: rhodecode/apps/admin/views/system_info.py:147 +msgid "GIT" msgstr "" #: rhodecode/apps/admin/views/system_info.py:148 -msgid "Temp storage location" +msgid "HG" msgstr "" #: rhodecode/apps/admin/views/system_info.py:149 -msgid "Temp storage info" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:151 -msgid "Search info" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:152 -msgid "Search location" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:156 -msgid "VCS Backends" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:157 -msgid "VCS Server" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:158 -msgid "GIT" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:159 -msgid "HG" -msgstr "" - -#: rhodecode/apps/admin/views/system_info.py:160 msgid "SVN" msgstr "" @@ -336,188 +435,188 @@ msgstr "" msgid "Error occurred during creation of user group %s" msgstr "" -#: rhodecode/apps/admin/views/users.py:208 +#: rhodecode/apps/admin/views/users.py:209 #, python-format msgid "Created user %(user_link)s" msgstr "" -#: rhodecode/apps/admin/views/users.py:229 +#: rhodecode/apps/admin/views/users.py:230 #, python-format msgid "Error occurred during creation of user %s" msgstr "" -#: rhodecode/apps/admin/views/users.py:303 +#: rhodecode/apps/admin/views/users.py:304 msgid "User updated successfully" msgstr "" -#: rhodecode/apps/admin/views/users.py:321 -#: rhodecode/apps/my_account/views/my_account.py:485 +#: rhodecode/apps/admin/views/users.py:322 +#: rhodecode/apps/my_account/views/my_account.py:490 #, python-format msgid "Error occurred during update of user %s" msgstr "" -#: rhodecode/apps/admin/views/users.py:353 +#: rhodecode/apps/admin/views/users.py:354 #, python-format msgid "Detached %s repositories" msgstr "" -#: rhodecode/apps/admin/views/users.py:358 +#: rhodecode/apps/admin/views/users.py:359 #, python-format msgid "Deleted %s repositories" msgstr "" -#: rhodecode/apps/admin/views/users.py:366 +#: rhodecode/apps/admin/views/users.py:367 #, python-format msgid "Detached %s repository groups" msgstr "" -#: rhodecode/apps/admin/views/users.py:371 +#: rhodecode/apps/admin/views/users.py:372 #, python-format msgid "Deleted %s repository groups" msgstr "" -#: rhodecode/apps/admin/views/users.py:379 +#: rhodecode/apps/admin/views/users.py:380 #, python-format msgid "Detached %s user groups" msgstr "" -#: rhodecode/apps/admin/views/users.py:384 +#: rhodecode/apps/admin/views/users.py:385 #, python-format msgid "Deleted %s user groups" msgstr "" -#: rhodecode/apps/admin/views/users.py:401 +#: rhodecode/apps/admin/views/users.py:402 msgid "Successfully deleted user" msgstr "" -#: rhodecode/apps/admin/views/users.py:407 +#: rhodecode/apps/admin/views/users.py:408 msgid "An error occurred during deletion of user" msgstr "" -#: rhodecode/apps/admin/views/users.py:472 +#: rhodecode/apps/admin/views/users.py:473 msgid "" "The user participates as reviewer in {} pull request and cannot be deleted. \n" "You can set the user to \"{}\" instead of deleting it." msgstr "" -#: rhodecode/apps/admin/views/users.py:478 +#: rhodecode/apps/admin/views/users.py:479 msgid "" "The user participates as reviewer in {} pull requests and cannot be deleted. \n" "You can set the user to \"{}\" instead of deleting it." msgstr "" -#: rhodecode/apps/admin/views/users.py:565 +#: rhodecode/apps/admin/views/users.py:567 msgid "User global permissions updated successfully" msgstr "" -#: rhodecode/apps/admin/views/users.py:583 -#: rhodecode/apps/user_group/views/__init__.py:472 +#: rhodecode/apps/admin/views/users.py:585 +#: rhodecode/apps/user_group/views/__init__.py:448 msgid "An error occurred during permissions saving" msgstr "" -#: rhodecode/apps/admin/views/users.py:608 +#: rhodecode/apps/admin/views/users.py:610 msgid "Force password change disabled for user" msgstr "" -#: rhodecode/apps/admin/views/users.py:613 +#: rhodecode/apps/admin/views/users.py:615 msgid "Force password change enabled for user" msgstr "" -#: rhodecode/apps/admin/views/users.py:622 +#: rhodecode/apps/admin/views/users.py:624 msgid "An error occurred during password reset for user" msgstr "" -#: rhodecode/apps/admin/views/users.py:661 +#: rhodecode/apps/admin/views/users.py:663 #, python-format msgid "Linked repository group `%s` as personal" msgstr "" -#: rhodecode/apps/admin/views/users.py:667 +#: rhodecode/apps/admin/views/users.py:669 #, python-format msgid "Created repository group `%s`" msgstr "" -#: rhodecode/apps/admin/views/users.py:671 +#: rhodecode/apps/admin/views/users.py:673 #, python-format msgid "Repository group `%s` is already taken" msgstr "" -#: rhodecode/apps/admin/views/users.py:676 +#: rhodecode/apps/admin/views/users.py:678 msgid "An error occurred during repository group creation for user" msgstr "" -#: rhodecode/apps/admin/views/users.py:699 -#: rhodecode/apps/my_account/views/my_account.py:159 +#: rhodecode/apps/admin/views/users.py:701 +#: rhodecode/apps/my_account/views/my_account.py:160 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:16 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:16 msgid "Role" msgstr "" -#: rhodecode/apps/admin/views/users.py:737 -#: rhodecode/apps/my_account/views/my_account.py:193 +#: rhodecode/apps/admin/views/users.py:739 +#: rhodecode/apps/my_account/views/my_account.py:194 msgid "Auth token successfully created" msgstr "" -#: rhodecode/apps/admin/views/users.py:766 -#: rhodecode/apps/my_account/views/my_account.py:217 +#: rhodecode/apps/admin/views/users.py:768 +#: rhodecode/apps/my_account/views/my_account.py:218 msgid "Auth token successfully deleted" msgstr "" -#: rhodecode/apps/admin/views/users.py:838 +#: rhodecode/apps/admin/views/users.py:840 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:113 msgid "Ssh Key successfully created" msgstr "" -#: rhodecode/apps/admin/views/users.py:842 -#: rhodecode/apps/admin/views/users.py:847 +#: rhodecode/apps/admin/views/users.py:844 +#: rhodecode/apps/admin/views/users.py:849 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:117 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:122 msgid "An error occurred during ssh key saving: {}" msgstr "" -#: rhodecode/apps/admin/views/users.py:881 +#: rhodecode/apps/admin/views/users.py:883 #: rhodecode/apps/my_account/views/my_account_ssh_keys.py:152 msgid "Ssh key successfully deleted" msgstr "" -#: rhodecode/apps/admin/views/users.py:922 -#: rhodecode/apps/my_account/views/my_account.py:255 +#: rhodecode/apps/admin/views/users.py:929 +#: rhodecode/apps/my_account/views/my_account.py:260 #, python-format msgid "Added new email address `%s` for user account" msgstr "" -#: rhodecode/apps/admin/views/users.py:928 +#: rhodecode/apps/admin/views/users.py:935 msgid "Email `{}` is already registered for another user." msgstr "" -#: rhodecode/apps/admin/views/users.py:932 -#: rhodecode/apps/my_account/views/my_account.py:261 +#: rhodecode/apps/admin/views/users.py:939 +#: rhodecode/apps/my_account/views/my_account.py:266 msgid "An error occurred during email saving" msgstr "" -#: rhodecode/apps/admin/views/users.py:959 +#: rhodecode/apps/admin/views/users.py:966 msgid "Removed email address from user account" msgstr "" -#: rhodecode/apps/admin/views/users.py:1005 +#: rhodecode/apps/admin/views/users.py:1012 #, python-format msgid "An error occurred during ip saving:%s" msgstr "" -#: rhodecode/apps/admin/views/users.py:1023 +#: rhodecode/apps/admin/views/users.py:1034 msgid "An error occurred during ip saving" msgstr "" -#: rhodecode/apps/admin/views/users.py:1027 +#: rhodecode/apps/admin/views/users.py:1038 #, python-format msgid "Added ips %s to user whitelist" msgstr "" -#: rhodecode/apps/admin/views/users.py:1057 +#: rhodecode/apps/admin/views/users.py:1068 msgid "Removed ip address from user whitelist" msgstr "" -#: rhodecode/apps/admin/views/users.py:1122 +#: rhodecode/apps/admin/views/users.py:1133 msgid "Groups successfully changed" msgstr "" @@ -542,10 +641,10 @@ msgid "1 month" msgstr "" #: rhodecode/apps/gist/views.py:64 -#: rhodecode/public/js/rhodecode-components.js:47769 -#: rhodecode/public/js/scripts.js:39617 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:19 -#: rhodecode/public/js/src/rhodecode.js:507 +#: rhodecode/public/js/rhodecode-components.js:49320 +#: rhodecode/public/js/scripts.js:41124 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:21 +#: rhodecode/public/js/src/rhodecode.js:538 msgid "Lifetime" msgstr "" @@ -596,72 +695,72 @@ msgstr "" msgid "Error occurred during update of gist %s" msgstr "" -#: rhodecode/apps/home/views.py:215 rhodecode/apps/home/views.py:248 -#: rhodecode/apps/repository/views/repo_pull_requests.py:731 -#: rhodecode/templates/admin/my_account/my_account.mako:39 +#: rhodecode/apps/home/views.py:218 rhodecode/apps/home/views.py:251 +#: rhodecode/apps/repository/views/repo_pull_requests.py:719 +#: rhodecode/templates/admin/my_account/my_account.mako:41 #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:126 #: rhodecode/templates/admin/repos/repo_add.mako:15 #: rhodecode/templates/admin/repos/repo_add.mako:19 #: rhodecode/templates/admin/users/user_edit_advanced.mako:11 -#: rhodecode/templates/base/base.mako:76 rhodecode/templates/base/base.mako:148 -#: rhodecode/templates/base/base.mako:580 +#: rhodecode/templates/base/base.mako:78 rhodecode/templates/base/base.mako:150 +#: rhodecode/templates/base/base.mako:582 msgid "Repositories" msgstr "" -#: rhodecode/apps/home/views.py:241 +#: rhodecode/apps/home/views.py:244 msgid "Groups" msgstr "" -#: rhodecode/apps/home/views.py:261 +#: rhodecode/apps/home/views.py:264 #, python-format msgid "Commits in %(repo)s" msgstr "" -#: rhodecode/apps/journal/views.py:132 rhodecode/apps/journal/views.py:177 +#: rhodecode/apps/journal/views.py:132 rhodecode/apps/journal/views.py:178 msgid "public journal" msgstr "" -#: rhodecode/apps/journal/views.py:136 rhodecode/apps/journal/views.py:181 +#: rhodecode/apps/journal/views.py:136 rhodecode/apps/journal/views.py:182 msgid "journal" msgstr "" -#: rhodecode/apps/login/views.py:272 rhodecode/apps/login/views.py:341 +#: rhodecode/apps/login/views.py:272 rhodecode/apps/login/views.py:349 msgid "Bad captcha" msgstr "" -#: rhodecode/apps/login/views.py:281 +#: rhodecode/apps/login/views.py:288 msgid "You have successfully registered with RhodeCode" msgstr "" -#: rhodecode/apps/login/views.py:317 +#: rhodecode/apps/login/views.py:325 msgid "If such email exists, a password reset link was sent to it." msgstr "" -#: rhodecode/apps/login/views.py:323 +#: rhodecode/apps/login/views.py:331 msgid "Password reset has been disabled." msgstr "" -#: rhodecode/apps/login/views.py:412 -msgid "Given reset token is invalid" -msgstr "" - #: rhodecode/apps/login/views.py:420 +msgid "Given reset token is invalid" +msgstr "" + +#: rhodecode/apps/login/views.py:428 msgid "Your password reset was successful, a new password has been sent to your email" msgstr "" -#: rhodecode/apps/my_account/views/my_account.py:134 +#: rhodecode/apps/my_account/views/my_account.py:135 msgid "Error occurred during update of user password" msgstr "" -#: rhodecode/apps/my_account/views/my_account.py:141 +#: rhodecode/apps/my_account/views/my_account.py:142 msgid "Successfully updated password" msgstr "" -#: rhodecode/apps/my_account/views/my_account.py:283 +#: rhodecode/apps/my_account/views/my_account.py:288 msgid "Email successfully deleted" msgstr "" -#: rhodecode/apps/my_account/views/my_account.py:465 +#: rhodecode/apps/my_account/views/my_account.py:470 msgid "Your account was updated successfully" msgstr "" @@ -676,7 +775,7 @@ msgid "Error occurred during deletion of msgstr "" #: rhodecode/apps/repo_group/views/repo_group_permissions.py:73 -#: rhodecode/apps/user_group/views/__init__.py:353 +#: rhodecode/apps/user_group/views/__init__.py:328 msgid "Cannot change permission for yourself as admin" msgstr "" @@ -703,29 +802,29 @@ msgstr "" #: rhodecode/apps/repository/views/repo_changelog.py:66 #: rhodecode/apps/repository/views/repo_compare.py:66 -#: rhodecode/apps/repository/views/repo_pull_requests.py:607 +#: rhodecode/apps/repository/views/repo_pull_requests.py:585 msgid "There are no commits yet" msgstr "" #: rhodecode/apps/repository/views/repo_changelog.py:71 -#: rhodecode/apps/repository/views/repo_commits.py:193 +#: rhodecode/apps/repository/views/repo_commits.py:192 #: rhodecode/apps/repository/views/repo_files.py:150 #: rhodecode/apps/repository/views/repo_files.py:170 msgid "No such commit exists for this repository" msgstr "" -#: rhodecode/apps/repository/views/repo_checks.py:95 +#: rhodecode/apps/repository/views/repo_checks.py:98 #, python-format msgid "Created repository %s from %s" msgstr "" -#: rhodecode/apps/repository/views/repo_checks.py:104 -#, python-format -msgid "Forked repository %s as %s" -msgstr "" - #: rhodecode/apps/repository/views/repo_checks.py:107 #, python-format +msgid "Forked repository %s as %s" +msgstr "" + +#: rhodecode/apps/repository/views/repo_checks.py:110 +#, python-format msgid "Created repository %s" msgstr "" @@ -753,13 +852,13 @@ msgstr "" msgid "Increase context for all diffs" msgstr "" -#: rhodecode/apps/repository/views/repo_commits.py:389 -#: rhodecode/apps/repository/views/repo_pull_requests.py:1126 +#: rhodecode/apps/repository/views/repo_commits.py:388 +#: rhodecode/apps/repository/views/repo_pull_requests.py:1129 #, python-format msgid "Status change %(transition_icon)s %(status)s" msgstr "" -#: rhodecode/apps/repository/views/repo_commits.py:433 +#: rhodecode/apps/repository/views/repo_commits.py:432 msgid "Changing the status of a commit associated with a closed pull request is not allowed" msgstr "" @@ -837,13 +936,13 @@ msgid "Changesets" msgstr "" #: rhodecode/apps/repository/views/repo_files.py:886 -#: rhodecode/apps/repository/views/repo_summary.py:321 -#: rhodecode/model/pull_request.py:1366 rhodecode/model/scm.py:776 +#: rhodecode/apps/repository/views/repo_summary.py:322 +#: rhodecode/model/pull_request.py:1421 rhodecode/model/scm.py:789 #: rhodecode/templates/base/vcs_settings.mako:235 msgid "Branches" msgstr "" -#: rhodecode/apps/repository/views/repo_files.py:890 rhodecode/model/scm.py:791 +#: rhodecode/apps/repository/views/repo_files.py:890 rhodecode/model/scm.py:804 #: rhodecode/templates/base/vcs_settings.mako:260 msgid "Tags" msgstr "" @@ -903,12 +1002,12 @@ msgstr "" msgid "The location specified must be a relative path and must not contain .. in the path" msgstr "" -#: rhodecode/apps/repository/views/repo_forks.py:144 -#: rhodecode/templates/base/base.mako:262 +#: rhodecode/apps/repository/views/repo_forks.py:146 +#: rhodecode/templates/base/base.mako:264 msgid "Compare fork" msgstr "" -#: rhodecode/apps/repository/views/repo_forks.py:250 +#: rhodecode/apps/repository/views/repo_forks.py:251 #, python-format msgid "An error occurred during repository forking %s" msgstr "" @@ -917,89 +1016,86 @@ msgstr "" msgid "Repository permissions updated" msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:636 +#: rhodecode/apps/repository/views/repo_pull_requests.py:615 msgid "Commit does not exist" msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:757 -msgid "Pull request requires a title with min. 3 chars" -msgstr "" - -#: rhodecode/apps/repository/views/repo_pull_requests.py:759 +#: rhodecode/apps/repository/views/repo_pull_requests.py:750 msgid "Error creating pull request: {}" msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:784 +#: rhodecode/apps/repository/views/repo_pull_requests.py:775 msgid "Not Enough permissions to source repo `{}`." msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:798 +#: rhodecode/apps/repository/views/repo_pull_requests.py:790 msgid "Not Enough permissions to target repo `{}`." msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:849 +#: rhodecode/apps/repository/views/repo_pull_requests.py:841 msgid "Successfully opened new pull request" msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:852 +#: rhodecode/apps/repository/views/repo_pull_requests.py:844 msgid "Error occurred during creation of this pull request." msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:904 +#: rhodecode/apps/repository/views/repo_pull_requests.py:875 +#: rhodecode/apps/repository/views/repo_pull_requests.py:905 msgid "Cannot update closed pull requests." msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:910 +#: rhodecode/apps/repository/views/repo_pull_requests.py:911 msgid "Pull request title & description updated." msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:929 +#: rhodecode/apps/repository/views/repo_pull_requests.py:930 msgid "Pull request updated to \"{source_commit_id}\" with {count_added} added, {count_removed} removed commits. Source of changes: {change_source}" msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:945 +#: rhodecode/apps/repository/views/repo_pull_requests.py:946 msgid "Reload page" msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:1008 +#: rhodecode/apps/repository/views/repo_pull_requests.py:1010 msgid "Pull request was successfully merged and closed." msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:1032 +#: rhodecode/apps/repository/views/repo_pull_requests.py:1034 msgid "Pull request reviewers updated." msgstr "" -#: rhodecode/apps/repository/views/repo_pull_requests.py:1057 +#: rhodecode/apps/repository/views/repo_pull_requests.py:1060 msgid "Successfully deleted pull request" msgstr "" -#: rhodecode/apps/repository/views/repo_settings.py:167 +#: rhodecode/apps/repository/views/repo_settings.py:168 msgid "Repository `{}` updated successfully" msgstr "" -#: rhodecode/apps/repository/views/repo_settings.py:171 +#: rhodecode/apps/repository/views/repo_settings.py:172 msgid "Error occurred during update of repository {}" msgstr "" -#: rhodecode/apps/repository/views/repo_settings.py:193 +#: rhodecode/apps/repository/views/repo_settings.py:194 msgid "Unlocked" msgstr "" -#: rhodecode/apps/repository/views/repo_settings.py:198 +#: rhodecode/apps/repository/views/repo_settings.py:199 msgid "Locked" msgstr "" -#: rhodecode/apps/repository/views/repo_settings.py:200 +#: rhodecode/apps/repository/views/repo_settings.py:201 #, python-format msgid "Repository has been %s" msgstr "" -#: rhodecode/apps/repository/views/repo_settings.py:204 +#: rhodecode/apps/repository/views/repo_settings.py:205 #: rhodecode/apps/repository/views/repo_settings_advanced.py:230 msgid "An error occurred during unlocking" msgstr "" -#: rhodecode/apps/repository/views/repo_settings.py:248 +#: rhodecode/apps/repository/views/repo_settings.py:249 msgid "An error occurred during deletion of repository stats" msgstr "" @@ -1060,28 +1156,18 @@ msgstr "" msgid "Unlocked repository" msgstr "" -#: rhodecode/apps/repository/views/repo_settings_fields.py:85 +#: rhodecode/apps/repository/views/repo_settings_fields.py:86 msgid "An error occurred during creation of field" msgstr "" -#: rhodecode/apps/repository/views/repo_settings_fields.py:107 +#: rhodecode/apps/repository/views/repo_settings_fields.py:108 msgid "An error occurred during removal of field" msgstr "" -#: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:85 +#: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:86 msgid "Error occurred during deleting issue tracker entry" msgstr "" -#: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:88 -#: rhodecode/controllers/admin/settings.py:384 -msgid "Removed issue tracker entry" -msgstr "" - -#: rhodecode/apps/repository/views/repo_settings_issue_trackers.py:123 -#: rhodecode/controllers/admin/settings.py:431 -msgid "Updated issue tracker entries" -msgstr "" - #: rhodecode/apps/repository/views/repo_settings_remote.py:66 msgid "Pulled from remote location" msgstr "" @@ -1090,34 +1176,23 @@ msgstr "" msgid "An error occurred during pull from remote location" msgstr "" -#: rhodecode/apps/repository/views/repo_settings_vcs.py:124 -#: rhodecode/controllers/admin/settings.py:147 -#: rhodecode/controllers/admin/settings.py:622 -msgid "Some form inputs contain invalid data." -msgstr "" - -#: rhodecode/apps/repository/views/repo_settings_vcs.py:143 -#: rhodecode/controllers/admin/settings.py:176 -msgid "Updated VCS settings" -msgstr "" - #: rhodecode/apps/repository/views/repo_settings_vcs.py:147 msgid "Error occurred during updating repository VCS settings" msgstr "" -#: rhodecode/apps/repository/views/repo_summary.py:296 -msgid "Branch" -msgstr "" - #: rhodecode/apps/repository/views/repo_summary.py:297 -msgid "Tag" +msgid "Branch" msgstr "" #: rhodecode/apps/repository/views/repo_summary.py:298 +msgid "Tag" +msgstr "" + +#: rhodecode/apps/repository/views/repo_summary.py:299 msgid "Bookmark" msgstr "" -#: rhodecode/apps/repository/views/repo_summary.py:322 +#: rhodecode/apps/repository/views/repo_summary.py:323 msgid "Closed branches" msgstr "" @@ -1129,41 +1204,41 @@ msgstr "" msgid "Configuration for Apache mad_dav_svn changed." msgstr "" -#: rhodecode/apps/user_group/views/__init__.py:209 +#: rhodecode/apps/user_group/views/__init__.py:184 #, python-format msgid "Updated user group %s" msgstr "" -#: rhodecode/apps/user_group/views/__init__.py:231 +#: rhodecode/apps/user_group/views/__init__.py:206 #, python-format msgid "Error occurred during update of user group %s" msgstr "" -#: rhodecode/apps/user_group/views/__init__.py:257 +#: rhodecode/apps/user_group/views/__init__.py:232 msgid "Successfully deleted user group" msgstr "" -#: rhodecode/apps/user_group/views/__init__.py:262 +#: rhodecode/apps/user_group/views/__init__.py:237 msgid "An error occurred during deletion of user group" msgstr "" -#: rhodecode/apps/user_group/views/__init__.py:366 +#: rhodecode/apps/user_group/views/__init__.py:341 msgid "Target group cannot be the same" msgstr "" -#: rhodecode/apps/user_group/views/__init__.py:381 +#: rhodecode/apps/user_group/views/__init__.py:356 msgid "User Group permissions updated" msgstr "" -#: rhodecode/apps/user_group/views/__init__.py:452 +#: rhodecode/apps/user_group/views/__init__.py:428 msgid "User Group global permissions updated successfully" msgstr "" -#: rhodecode/apps/user_group/views/__init__.py:534 +#: rhodecode/apps/user_group/views/__init__.py:510 msgid "User Group synchronization updated successfully" msgstr "" -#: rhodecode/apps/user_group/views/__init__.py:538 +#: rhodecode/apps/user_group/views/__init__.py:514 msgid "An error occurred during synchronization update" msgstr "" @@ -1190,19 +1265,19 @@ msgstr "" msgid "Auth Cache TTL" msgstr "" -#: rhodecode/authentication/views.py:90 +#: rhodecode/authentication/views.py:93 msgid "Errors exist when saving plugin settings. Please check the form inputs." msgstr "" -#: rhodecode/authentication/views.py:103 rhodecode/authentication/views.py:176 +#: rhodecode/authentication/views.py:105 rhodecode/authentication/views.py:170 msgid "Auth settings updated successfully." msgstr "" +#: rhodecode/authentication/views.py:173 +msgid "Errors exist when saving plugin setting. Please check the form inputs." +msgstr "" + #: rhodecode/authentication/views.py:181 -msgid "Errors exist when saving plugin setting. Please check the form inputs." -msgstr "" - -#: rhodecode/authentication/views.py:191 msgid "Error occurred during update of auth settings." msgstr "" @@ -1321,11 +1396,11 @@ msgid "Password to authenticate for give msgstr "" #: rhodecode/authentication/plugins/auth_ldap.py:105 -#: rhodecode/integrations/types/webhook.py:214 +#: rhodecode/integrations/types/webhook.py:220 #: rhodecode/templates/login.mako:50 rhodecode/templates/register.mako:48 #: rhodecode/templates/admin/my_account/my_account.mako:30 #: rhodecode/templates/admin/users/user_add.mako:44 -#: rhodecode/templates/base/base.mako:324 +#: rhodecode/templates/base/base.mako:326 #: rhodecode/templates/debug_style/login.html:45 msgid "Password" msgstr "" @@ -1448,56 +1523,6 @@ msgstr "" msgid "Rhodecode Token Auth" msgstr "" -#: rhodecode/controllers/admin/settings.py:172 -#: rhodecode/controllers/admin/settings.py:286 -msgid "Error occurred during updating application settings" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:226 -#, python-format -msgid "Repositories successfully rescanned added: %s ; removed: %s" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:282 -msgid "Updated application settings" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:348 -msgid "Updated visualisation settings" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:351 -msgid "Error occurred during updating visualisation settings" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:444 -msgid "Please enter email address" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:462 -msgid "Send email task created" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:495 -msgid "Added new hook" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:510 -msgid "Updated hooks" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:514 -msgid "Error occurred during hook creation" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:643 -msgid "Error occurred during updating labs settings" -msgstr "" - -#: rhodecode/controllers/admin/settings.py:648 -msgid "Updated Labs settings" -msgstr "" - #: rhodecode/events/pullrequest.py:72 msgid "pullrequest created" msgstr "" @@ -1522,35 +1547,35 @@ msgstr "" msgid "pullrequest commented" msgstr "" -#: rhodecode/events/repo.py:149 +#: rhodecode/events/repo.py:189 msgid "repository pre create" msgstr "" -#: rhodecode/events/repo.py:158 +#: rhodecode/events/repo.py:198 msgid "repository created" msgstr "" -#: rhodecode/events/repo.py:167 +#: rhodecode/events/repo.py:207 msgid "repository pre delete" msgstr "" -#: rhodecode/events/repo.py:176 -msgid "repository deleted" -msgstr "" - #: rhodecode/events/repo.py:216 +msgid "repository deleted" +msgstr "" + +#: rhodecode/events/repo.py:256 msgid "repository pre pull" msgstr "" -#: rhodecode/events/repo.py:225 +#: rhodecode/events/repo.py:265 msgid "repository pull" msgstr "" -#: rhodecode/events/repo.py:234 +#: rhodecode/events/repo.py:274 msgid "repository pre push" msgstr "" -#: rhodecode/events/repo.py:245 +#: rhodecode/events/repo.py:285 msgid "repository push" msgstr "" @@ -1601,7 +1626,7 @@ msgstr "" #: rhodecode/templates/admin/settings/settings_issuetracker.mako:16 #: rhodecode/templates/admin/settings/settings_labs.mako:49 #: rhodecode/templates/admin/settings/settings_vcs.mako:14 -#: rhodecode/templates/admin/settings/settings_visual.mako:211 +#: rhodecode/templates/admin/settings/settings_visual.mako:215 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:121 #: rhodecode/templates/admin/users/user_edit_auth_tokens.mako:83 #: rhodecode/templates/admin/users/user_edit_emails.mako:63 @@ -1629,9 +1654,9 @@ msgstr "" #: rhodecode/templates/base/issue_tracker_settings.mako:69 #: rhodecode/templates/base/vcs_settings.mako:244 #: rhodecode/templates/base/vcs_settings.mako:269 -#: rhodecode/templates/changeset/changeset_file_comment.mako:142 -#: rhodecode/templates/changeset/changeset_file_comment.mako:144 -#: rhodecode/templates/changeset/changeset_file_comment.mako:147 +#: rhodecode/templates/changeset/changeset_file_comment.mako:143 +#: rhodecode/templates/changeset/changeset_file_comment.mako:145 +#: rhodecode/templates/changeset/changeset_file_comment.mako:148 #: rhodecode/templates/data_table/_dt_elements.mako:171 #: rhodecode/templates/data_table/_dt_elements.mako:244 #: rhodecode/templates/data_table/_dt_elements.mako:258 @@ -1692,80 +1717,80 @@ msgstr "" msgid "Integration {integration_name} deleted successfully." msgstr "" -#: rhodecode/integrations/views.py:301 +#: rhodecode/integrations/views.py:302 msgid "Errors exist when saving integration settings. Please check the form inputs." msgstr "" -#: rhodecode/integrations/views.py:326 +#: rhodecode/integrations/views.py:327 msgid "Integration {integration_name} updated successfully." msgstr "" -#: rhodecode/integrations/types/email.py:214 -msgid "Recipients" -msgstr "" - #: rhodecode/integrations/types/email.py:215 +msgid "Recipients" +msgstr "" + +#: rhodecode/integrations/types/email.py:216 msgid "Email addresses to send push events to" msgstr "" -#: rhodecode/integrations/types/email.py:220 #: rhodecode/integrations/types/email.py:221 +#: rhodecode/integrations/types/email.py:222 msgid "Email address" msgstr "" -#: rhodecode/integrations/types/email.py:233 +#: rhodecode/integrations/types/email.py:234 msgid "Send repo push summaries to a list of recipients via email" msgstr "" +#: rhodecode/integrations/types/hipchat.py:41 +msgid "Yellow" +msgstr "" + +#: rhodecode/integrations/types/hipchat.py:42 +msgid "Red" +msgstr "" + #: rhodecode/integrations/types/hipchat.py:43 -msgid "Yellow" +msgid "Green" msgstr "" #: rhodecode/integrations/types/hipchat.py:44 -msgid "Red" +msgid "Purple" msgstr "" #: rhodecode/integrations/types/hipchat.py:45 -msgid "Green" -msgstr "" - -#: rhodecode/integrations/types/hipchat.py:46 -msgid "Purple" -msgstr "" - -#: rhodecode/integrations/types/hipchat.py:47 msgid "Gray" msgstr "" -#: rhodecode/integrations/types/hipchat.py:52 +#: rhodecode/integrations/types/hipchat.py:50 msgid "Hipchat server URL" msgstr "" -#: rhodecode/integrations/types/hipchat.py:53 +#: rhodecode/integrations/types/hipchat.py:51 msgid "Hipchat integration url." msgstr "" -#: rhodecode/integrations/types/hipchat.py:63 +#: rhodecode/integrations/types/hipchat.py:61 msgid "Notify" msgstr "" -#: rhodecode/integrations/types/hipchat.py:64 +#: rhodecode/integrations/types/hipchat.py:62 msgid "Make a notification to the users in room." msgstr "" -#: rhodecode/integrations/types/hipchat.py:70 +#: rhodecode/integrations/types/hipchat.py:68 msgid "Color" msgstr "" -#: rhodecode/integrations/types/hipchat.py:71 +#: rhodecode/integrations/types/hipchat.py:69 msgid "Background color of message." msgstr "" -#: rhodecode/integrations/types/hipchat.py:99 +#: rhodecode/integrations/types/hipchat.py:97 msgid "Hipchat" msgstr "" -#: rhodecode/integrations/types/hipchat.py:100 +#: rhodecode/integrations/types/hipchat.py:98 msgid "Send events such as repo pushes and pull requests to your hipchat channel." msgstr "" @@ -1778,7 +1803,7 @@ msgid "This can be setup at the %s" msgstr "" -#: rhodecode/lib/action_parser.py:228 +#: rhodecode/lib/action_parser.py:231 msgid "compare view" msgstr "" -#: rhodecode/lib/action_parser.py:235 +#: rhodecode/lib/action_parser.py:238 #, python-format msgid " and %(num)s more commits" msgstr "" -#: rhodecode/lib/action_parser.py:288 +#: rhodecode/lib/action_parser.py:293 #, python-format msgid "Deleted branch: %s" msgstr "" -#: rhodecode/lib/action_parser.py:291 +#: rhodecode/lib/action_parser.py:296 #, python-format msgid "Created tag: %s" msgstr "" -#: rhodecode/lib/action_parser.py:304 +#: rhodecode/lib/action_parser.py:309 msgid "Commit not found" msgstr "" -#: rhodecode/lib/auth.py:1445 +#: rhodecode/lib/auth.py:1441 #, python-format msgid "IP %s not allowed" msgstr "" -#: rhodecode/lib/auth.py:1535 +#: rhodecode/lib/auth.py:1531 msgid "You need to be a registered user to perform this action" msgstr "" -#: rhodecode/lib/auth.py:1577 +#: rhodecode/lib/auth.py:1575 msgid "You need to be signed in to view this page" msgstr "" -#: rhodecode/lib/diffs.py:62 -msgid "Click to comment" -msgstr "" - -#: rhodecode/lib/diffs.py:77 -msgid "Binary file" -msgstr "" - -#: rhodecode/lib/diffs.py:98 -msgid "Changeset was too big and was cut off, use diff menu to display this diff" -msgstr "" - -#: rhodecode/lib/diffs.py:109 -msgid "No changes detected" -msgstr "" - -#: rhodecode/lib/diffs.py:927 +#: rhodecode/lib/diffs.py:864 msgid "Click to select line" msgstr "" -#: rhodecode/lib/helpers.py:1869 +#: rhodecode/lib/helpers.py:1855 msgid "" "Example filter terms:\n" " repository:vcs\n" @@ -2056,7 +2065,7 @@ msgid "" " \"username:test AND repository:test*\"\n" msgstr "" -#: rhodecode/lib/helpers.py:1893 +#: rhodecode/lib/helpers.py:1879 msgid "" "Example filter terms for `{searcher}` search:\n" "{terms}\n" @@ -2070,47 +2079,47 @@ msgid "" "More: {search_doc}" msgstr "" -#: rhodecode/lib/helpers.py:1910 +#: rhodecode/lib/helpers.py:1896 #, python-format msgid "%s repository is not mapped to db perhaps it was created or renamed from the filesystem please run the application again in order to rescan repositories" msgstr "" -#: rhodecode/lib/utils2.py:525 +#: rhodecode/lib/utils2.py:524 msgid "in ${ago}" msgstr "" -#: rhodecode/lib/utils2.py:531 +#: rhodecode/lib/utils2.py:530 msgid "${ago} ago" msgstr "" -#: rhodecode/lib/utils2.py:540 +#: rhodecode/lib/utils2.py:539 msgid "${val}, ${detail}" msgstr "" -#: rhodecode/lib/utils2.py:542 +#: rhodecode/lib/utils2.py:541 msgid "${val}, ${detail} ago" msgstr "" -#: rhodecode/lib/utils2.py:544 +#: rhodecode/lib/utils2.py:543 msgid "in ${val}, ${detail}" msgstr "" -#: rhodecode/lib/utils2.py:546 +#: rhodecode/lib/utils2.py:545 msgid "${val} and ${detail}" msgstr "" -#: rhodecode/lib/utils2.py:548 +#: rhodecode/lib/utils2.py:547 msgid "${val} and ${detail} ago" msgstr "" -#: rhodecode/lib/utils2.py:550 +#: rhodecode/lib/utils2.py:549 msgid "in ${val} and ${detail}" msgstr "" -#: rhodecode/lib/utils2.py:554 -#: rhodecode/public/js/rhodecode-components.js:29149 -#: rhodecode/public/js/scripts.js:20997 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:80 +#: rhodecode/lib/utils2.py:553 +#: rhodecode/public/js/rhodecode-components.js:30702 +#: rhodecode/public/js/scripts.js:22550 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:84 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:174 msgid "just now" msgstr "" @@ -2138,6 +2147,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:823 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:945 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:970 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2599 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2287 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2279 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2279 @@ -2145,7 +2155,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2283 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2333 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2334 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2535 rhodecode/model/db.py:2595 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2535 rhodecode/model/db.py:2626 msgid "Repository no access" msgstr "" @@ -2172,6 +2182,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:824 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:946 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:971 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2600 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2288 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2280 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2280 @@ -2179,7 +2190,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2284 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2334 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2335 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2536 rhodecode/model/db.py:2596 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2536 rhodecode/model/db.py:2627 msgid "Repository read access" msgstr "" @@ -2206,6 +2217,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:825 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:947 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:972 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2601 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2289 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2281 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2281 @@ -2213,7 +2225,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2285 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2335 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2336 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2537 rhodecode/model/db.py:2597 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2537 rhodecode/model/db.py:2628 msgid "Repository write access" msgstr "" @@ -2240,6 +2252,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:826 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:948 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:973 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2602 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2290 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2282 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2282 @@ -2247,7 +2260,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2286 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2336 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2337 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2538 rhodecode/model/db.py:2598 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2538 rhodecode/model/db.py:2629 msgid "Repository admin access" msgstr "" @@ -2314,6 +2327,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:844 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:966 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:991 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2620 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2308 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2300 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2300 @@ -2321,7 +2335,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2304 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2354 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2355 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2556 rhodecode/model/db.py:2616 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2556 rhodecode/model/db.py:2647 msgid "Repository creation disabled" msgstr "" @@ -2348,6 +2362,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:845 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:967 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:992 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2621 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2309 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2301 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2301 @@ -2355,7 +2370,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2305 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2355 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2356 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2557 rhodecode/model/db.py:2617 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2557 rhodecode/model/db.py:2648 msgid "Repository creation enabled" msgstr "" @@ -2382,6 +2397,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:849 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:971 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:996 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2625 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2313 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2305 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2305 @@ -2389,7 +2405,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2309 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2359 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2360 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2561 rhodecode/model/db.py:2621 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2561 rhodecode/model/db.py:2652 msgid "Repository forking disabled" msgstr "" @@ -2416,6 +2432,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:850 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:972 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:997 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2626 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2314 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2306 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2306 @@ -2423,7 +2440,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2310 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2360 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2361 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2562 rhodecode/model/db.py:2622 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2562 rhodecode/model/db.py:2653 msgid "Repository forking enabled" msgstr "" @@ -2471,6 +2488,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1195 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1317 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1342 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3328 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2946 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2940 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2940 @@ -2478,7 +2496,11 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2944 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3044 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3045 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3264 rhodecode/model/db.py:3324 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3264 rhodecode/model/db.py:3355 +#: rhodecode/public/js/rhodecode-components.js:48211 +#: rhodecode/public/js/scripts.js:40015 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:39 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:313 msgid "Not Reviewed" msgstr "" @@ -2505,6 +2527,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1196 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1318 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1343 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3329 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2947 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2941 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2941 @@ -2512,7 +2535,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2945 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3045 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3046 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3265 rhodecode/model/db.py:3325 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3265 rhodecode/model/db.py:3356 msgid "Approved" msgstr "" @@ -2539,6 +2562,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1197 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1319 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1344 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3330 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2948 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2942 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2942 @@ -2546,7 +2570,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2946 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3046 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3047 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3266 rhodecode/model/db.py:3326 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3266 rhodecode/model/db.py:3357 msgid "Rejected" msgstr "" @@ -2573,6 +2597,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:1198 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:1320 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1345 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:3331 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2949 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2943 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2943 @@ -2580,7 +2605,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2947 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:3047 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:3048 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3267 rhodecode/model/db.py:3327 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:3267 rhodecode/model/db.py:3358 msgid "Under Review" msgstr "" @@ -2604,6 +2629,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:828 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:950 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:975 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2604 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2292 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2284 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2284 @@ -2611,7 +2637,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2288 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2338 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2339 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2540 rhodecode/model/db.py:2600 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2540 rhodecode/model/db.py:2631 msgid "Repository group no access" msgstr "" @@ -2635,6 +2661,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:829 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:951 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:976 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2605 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2293 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2285 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2285 @@ -2642,7 +2669,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2289 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2339 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2340 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2541 rhodecode/model/db.py:2601 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2541 rhodecode/model/db.py:2632 msgid "Repository group read access" msgstr "" @@ -2666,6 +2693,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:830 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:952 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:977 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2606 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2294 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2286 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2286 @@ -2673,7 +2701,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2290 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2340 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2341 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2542 rhodecode/model/db.py:2602 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2542 rhodecode/model/db.py:2633 msgid "Repository group write access" msgstr "" @@ -2697,6 +2725,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:831 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:953 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:978 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2607 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2295 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2287 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2287 @@ -2704,7 +2733,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2291 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2341 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2342 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2543 rhodecode/model/db.py:2603 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2543 rhodecode/model/db.py:2634 msgid "Repository group admin access" msgstr "" @@ -2727,6 +2756,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:833 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:955 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:980 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2609 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2297 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2289 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2289 @@ -2734,7 +2764,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2293 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2343 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2344 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2545 rhodecode/model/db.py:2605 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2545 rhodecode/model/db.py:2636 msgid "User group no access" msgstr "" @@ -2757,6 +2787,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:834 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:956 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:981 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2610 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2298 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2290 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2290 @@ -2764,7 +2795,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2294 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2344 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2345 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2546 rhodecode/model/db.py:2606 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2546 rhodecode/model/db.py:2637 msgid "User group read access" msgstr "" @@ -2787,6 +2818,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:835 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:957 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:982 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2611 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2299 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2291 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2291 @@ -2794,7 +2826,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2295 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2345 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2346 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2547 rhodecode/model/db.py:2607 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2547 rhodecode/model/db.py:2638 msgid "User group write access" msgstr "" @@ -2817,6 +2849,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:836 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:958 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:983 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2612 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2300 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2292 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2292 @@ -2824,7 +2857,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2296 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2346 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2347 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2548 rhodecode/model/db.py:2608 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2548 rhodecode/model/db.py:2639 msgid "User group admin access" msgstr "" @@ -2847,6 +2880,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:838 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:960 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:985 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2614 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2302 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2294 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2294 @@ -2854,7 +2888,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2298 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2348 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2349 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2550 rhodecode/model/db.py:2610 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2550 rhodecode/model/db.py:2641 msgid "Repository Group creation disabled" msgstr "" @@ -2877,6 +2911,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:839 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:961 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:986 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2615 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2303 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2295 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2295 @@ -2884,7 +2919,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2299 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2349 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2350 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2551 rhodecode/model/db.py:2611 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2551 rhodecode/model/db.py:2642 msgid "Repository Group creation enabled" msgstr "" @@ -2907,6 +2942,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:841 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:963 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:988 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2617 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2305 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2297 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2297 @@ -2914,7 +2950,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2301 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2351 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2352 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2553 rhodecode/model/db.py:2613 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2553 rhodecode/model/db.py:2644 msgid "User Group creation disabled" msgstr "" @@ -2937,6 +2973,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:842 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:964 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:989 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2618 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2306 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2298 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2298 @@ -2944,7 +2981,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2302 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2352 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2353 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2554 rhodecode/model/db.py:2614 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2554 rhodecode/model/db.py:2645 msgid "User Group creation enabled" msgstr "" @@ -2967,6 +3004,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:852 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:974 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:999 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2628 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2316 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2308 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2308 @@ -2974,7 +3012,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2312 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2362 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2363 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2564 rhodecode/model/db.py:2624 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2564 rhodecode/model/db.py:2655 msgid "Registration disabled" msgstr "" @@ -2997,6 +3035,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:853 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:975 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1000 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2629 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2317 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2309 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2309 @@ -3004,7 +3043,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2313 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2363 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2364 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2565 rhodecode/model/db.py:2625 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2565 rhodecode/model/db.py:2656 msgid "User Registration with manual account activation" msgstr "" @@ -3027,6 +3066,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:854 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:976 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1001 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2630 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2318 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2310 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2310 @@ -3034,7 +3074,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2314 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2364 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2365 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2566 rhodecode/model/db.py:2626 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2566 rhodecode/model/db.py:2657 msgid "User Registration with automatic account activation" msgstr "" @@ -3057,6 +3097,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:856 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:978 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1003 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2636 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2320 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2312 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2312 @@ -3064,7 +3105,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2316 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2370 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2371 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2572 rhodecode/model/db.py:2632 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2572 rhodecode/model/db.py:2663 #: rhodecode/model/permission.py:96 msgid "Manual activation of external account" msgstr "" @@ -3088,6 +3129,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:857 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:979 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1004 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2637 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2321 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2313 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2313 @@ -3095,7 +3137,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2317 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2371 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2372 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2573 rhodecode/model/db.py:2633 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2573 rhodecode/model/db.py:2664 #: rhodecode/model/permission.py:97 msgid "Automatic activation of external account" msgstr "" @@ -3113,6 +3155,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:846 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:968 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:993 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2622 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2310 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2302 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2302 @@ -3120,7 +3163,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2306 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2356 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2357 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2558 rhodecode/model/db.py:2618 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2558 rhodecode/model/db.py:2649 msgid "Repository creation enabled with write permission to a repository group" msgstr "" @@ -3137,6 +3180,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:847 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:969 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:994 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2623 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2311 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2303 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2303 @@ -3144,7 +3188,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2307 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2357 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2358 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2559 rhodecode/model/db.py:2619 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2559 rhodecode/model/db.py:2650 msgid "Repository creation disabled with write permission to a repository group" msgstr "" @@ -3158,6 +3202,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:821 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:943 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:968 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2597 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2285 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2277 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2277 @@ -3165,7 +3210,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2281 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2331 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2332 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2533 rhodecode/model/db.py:2593 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2533 rhodecode/model/db.py:2624 msgid "RhodeCode Super Administrator" msgstr "" @@ -3177,6 +3222,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:859 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:981 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1006 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2639 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2323 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2315 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2315 @@ -3184,7 +3230,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2319 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2373 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2374 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2575 rhodecode/model/db.py:2635 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2575 rhodecode/model/db.py:2666 msgid "Inherit object permissions from default user disabled" msgstr "" @@ -3196,6 +3242,7 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_3_3_0_0.py:860 #: rhodecode/lib/dbmigrate/schema/db_3_5_0_0.py:982 #: rhodecode/lib/dbmigrate/schema/db_3_7_0_0.py:1007 +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2640 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2324 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2316 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2316 @@ -3203,10 +3250,11 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2320 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2374 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2375 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2576 rhodecode/model/db.py:2636 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2576 rhodecode/model/db.py:2667 msgid "Inherit object permissions from default user enabled" msgstr "" +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1103 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:910 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:911 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:911 @@ -3214,10 +3262,11 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:913 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:955 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:956 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1051 rhodecode/model/db.py:1099 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1051 rhodecode/model/db.py:1107 msgid "all" msgstr "" +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1104 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:911 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:912 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:912 @@ -3225,10 +3274,11 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:914 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:956 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:957 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1052 rhodecode/model/db.py:1100 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1052 rhodecode/model/db.py:1108 msgid "http/web interface" msgstr "" +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1105 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:912 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:913 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:913 @@ -3236,10 +3286,11 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:915 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:957 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:958 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1053 rhodecode/model/db.py:1101 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1053 rhodecode/model/db.py:1109 msgid "vcs (git/hg/svn protocol)" msgstr "" +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1106 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:913 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:914 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:914 @@ -3247,10 +3298,11 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:916 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:958 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:959 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1054 rhodecode/model/db.py:1102 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1054 rhodecode/model/db.py:1110 msgid "api calls" msgstr "" +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:1107 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:914 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:915 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:915 @@ -3258,10 +3310,11 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:917 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:959 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:960 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1055 rhodecode/model/db.py:1103 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:1055 rhodecode/model/db.py:1111 msgid "feed access" msgstr "" +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2360 #: rhodecode/lib/dbmigrate/schema/db_4_3_0_0.py:2063 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_0.py:2055 #: rhodecode/lib/dbmigrate/schema/db_4_4_0_1.py:2055 @@ -3269,57 +3322,48 @@ msgstr "" #: rhodecode/lib/dbmigrate/schema/db_4_5_0_0.py:2059 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2102 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2103 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2297 rhodecode/model/db.py:2356 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2297 rhodecode/model/db.py:2387 msgid "No parent" msgstr "" +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2632 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2366 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2367 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2568 rhodecode/model/db.py:2628 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2568 rhodecode/model/db.py:2659 msgid "Password reset enabled" msgstr "" +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2633 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2367 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2368 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2569 rhodecode/model/db.py:2629 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2569 rhodecode/model/db.py:2660 msgid "Password reset hidden" msgstr "" +#: rhodecode/lib/dbmigrate/schema/db_4_11_0_0.py:2634 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_0.py:2368 #: rhodecode/lib/dbmigrate/schema/db_4_7_0_1.py:2369 -#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2570 rhodecode/model/db.py:2630 +#: rhodecode/lib/dbmigrate/schema/db_4_9_0_0.py:2570 rhodecode/model/db.py:2661 msgid "Password reset disabled" msgstr "" -#: rhodecode/lib/index/whoosh.py:150 -msgid "Invalid search query. Try quoting it." -msgstr "" - -#: rhodecode/lib/index/whoosh.py:152 -msgid "There is no index to search in. Please run whoosh indexer" -msgstr "" - -#: rhodecode/lib/index/whoosh.py:157 -msgid "An error occurred during this search operation" +#: rhodecode/lib/index/whoosh.py:164 +msgid "Index Type" msgstr "" #: rhodecode/lib/index/whoosh.py:165 -msgid "Index Type" -msgstr "" - -#: rhodecode/lib/index/whoosh.py:166 msgid "File Index" msgstr "" -#: rhodecode/lib/index/whoosh.py:167 rhodecode/lib/index/whoosh.py:172 +#: rhodecode/lib/index/whoosh.py:166 rhodecode/lib/index/whoosh.py:171 msgid "Indexed documents" msgstr "" -#: rhodecode/lib/index/whoosh.py:169 rhodecode/lib/index/whoosh.py:174 +#: rhodecode/lib/index/whoosh.py:168 rhodecode/lib/index/whoosh.py:173 msgid "Last update" msgstr "" -#: rhodecode/lib/index/whoosh.py:171 +#: rhodecode/lib/index/whoosh.py:170 msgid "Commit index" msgstr "" @@ -3339,28 +3383,28 @@ msgstr "" msgid "1 month {end_date}" msgstr "" -#: rhodecode/model/comment.py:375 +#: rhodecode/model/comment.py:382 msgid "made a comment" msgstr "" -#: rhodecode/model/comment.py:376 +#: rhodecode/model/comment.py:383 msgid "Show it now" msgstr "" -#: rhodecode/model/forms.py:87 -msgid "Please enter a login" -msgstr "" - #: rhodecode/model/forms.py:88 +msgid "Please enter a login" +msgstr "" + +#: rhodecode/model/forms.py:89 #, python-format msgid "Enter a value %(min)i characters long or more" msgstr "" -#: rhodecode/model/forms.py:98 -msgid "Please enter a password" -msgstr "" - #: rhodecode/model/forms.py:99 +msgid "Please enter a password" +msgstr "" + +#: rhodecode/model/forms.py:100 #, python-format msgid "Enter %(min)i characters or more" msgstr "" @@ -3447,8 +3491,8 @@ msgstr "" #: rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako:13 #: rhodecode/templates/admin/repos/repo_edit_permissions.mako:13 #: rhodecode/templates/admin/user_groups/user_group_edit_perms.mako:13 -#: rhodecode/templates/changeset/changeset_file_comment.mako:271 -#: rhodecode/templates/changeset/changeset_file_comment.mako:321 +#: rhodecode/templates/changeset/changeset_file_comment.mako:272 +#: rhodecode/templates/changeset/changeset_file_comment.mako:322 msgid "Write" msgstr "" @@ -3482,8 +3526,8 @@ msgstr "" #: rhodecode/templates/admin/users/user_edit.mako:12 #: rhodecode/templates/admin/users/users.mako:13 #: rhodecode/templates/admin/users/users.mako:76 -#: rhodecode/templates/base/base.mako:417 -#: rhodecode/templates/base/base.mako:424 +#: rhodecode/templates/base/base.mako:419 +#: rhodecode/templates/base/base.mako:426 msgid "Admin" msgstr "" @@ -3586,107 +3630,79 @@ msgstr "" msgid "This pull request cannot be updated because the source reference is missing." msgstr "" -#: rhodecode/model/pull_request.py:1166 +#: rhodecode/model/pull_request.py:1218 msgid "Server-side pull request merging is disabled." msgstr "" -#: rhodecode/model/pull_request.py:1168 +#: rhodecode/model/pull_request.py:1220 msgid "This pull request is closed." msgstr "" -#: rhodecode/model/pull_request.py:1181 +#: rhodecode/model/pull_request.py:1233 msgid "Pull request merging is not supported." msgstr "" -#: rhodecode/model/pull_request.py:1200 +#: rhodecode/model/pull_request.py:1252 msgid "Target repository large files support is disabled." msgstr "" -#: rhodecode/model/pull_request.py:1203 +#: rhodecode/model/pull_request.py:1255 msgid "Source repository large files support is disabled." msgstr "" -#: rhodecode/model/pull_request.py:1365 rhodecode/model/scm.py:784 +#: rhodecode/model/pull_request.py:1420 rhodecode/model/scm.py:797 msgid "Bookmarks" msgstr "" -#: rhodecode/model/pull_request.py:1370 +#: rhodecode/model/pull_request.py:1425 msgid "Commit IDs" msgstr "" -#: rhodecode/model/pull_request.py:1373 +#: rhodecode/model/pull_request.py:1428 msgid "Closed Branches" msgstr "" -#: rhodecode/model/pull_request.py:1533 +#: rhodecode/model/pull_request.py:1588 msgid "User `{}` not allowed to perform merge." msgstr "" -#: rhodecode/model/pull_request.py:1546 +#: rhodecode/model/pull_request.py:1601 msgid "Pull request reviewer approval is pending." msgstr "" -#: rhodecode/model/pull_request.py:1561 +#: rhodecode/model/pull_request.py:1616 msgid "Cannot merge, {} TODO still not resolved." msgstr "" -#: rhodecode/model/pull_request.py:1564 +#: rhodecode/model/pull_request.py:1619 msgid "Cannot merge, {} TODOs still not resolved." msgstr "" -#: rhodecode/model/pull_request.py:1599 +#: rhodecode/model/pull_request.py:1654 msgid "Merge strategy: rebase" msgstr "" -#: rhodecode/model/pull_request.py:1604 +#: rhodecode/model/pull_request.py:1659 msgid "Merge strategy: explicit merge commit" msgstr "" -#: rhodecode/model/pull_request.py:1611 +#: rhodecode/model/pull_request.py:1666 msgid "Source branch will be closed after merge." msgstr "" -#: rhodecode/model/pull_request.py:1613 +#: rhodecode/model/pull_request.py:1668 msgid "Source branch will be deleted after merge." msgstr "" -#: rhodecode/model/scm.py:762 +#: rhodecode/model/scm.py:775 msgid "latest tip" msgstr "" -#: rhodecode/model/user.py:166 -msgid "You can't Edit this user since it's crucial for entire application" -msgstr "" - -#: rhodecode/model/user.py:333 -#, python-format -msgid "You can't edit this user (`%(username)s`) since it's crucial for entire application" -msgstr "" - -#: rhodecode/model/user.py:506 -msgid "You can't remove this user since it's crucial for entire application" -msgstr "" - -#: rhodecode/model/user.py:514 -#, python-format -msgid "user \"%s\" still owns %s repositories and cannot be removed. Switch owners or remove those repositories:%s" -msgstr "" - -#: rhodecode/model/user.py:523 -#, python-format -msgid "user \"%s\" still owns %s repository groups and cannot be removed. Switch owners or remove those repository groups:%s" -msgstr "" - -#: rhodecode/model/user.py:532 -#, python-format -msgid "user \"%s\" still owns %s user groups and cannot be removed. Switch owners or remove those user groups:%s" -msgstr "" - -#: rhodecode/model/validators.py:98 rhodecode/model/validators.py:99 +#: rhodecode/model/validators.py:92 rhodecode/model/validators.py:93 msgid "Value cannot be an empty list" msgstr "" -#: rhodecode/model/validators.py:142 +#: rhodecode/model/validators.py:139 msgid "Pattern already exists" msgstr "" @@ -3705,30 +3721,26 @@ msgstr "" msgid "Username may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character or underscore" msgstr "" -#: rhodecode/model/validators.py:192 -msgid "The input is not valid" -msgstr "" - -#: rhodecode/model/validators.py:199 +#: rhodecode/model/validators.py:195 #, python-format msgid "Username %(username)s is not valid" msgstr "" -#: rhodecode/model/validators.py:200 +#: rhodecode/model/validators.py:196 #, python-format msgid "Username %(username)s is disabled" msgstr "" -#: rhodecode/model/validators.py:223 +#: rhodecode/model/validators.py:221 msgid "Invalid user group name" msgstr "" +#: rhodecode/model/validators.py:222 +#, python-format +msgid "User group `%(usergroup)s` already exists" +msgstr "" + #: rhodecode/model/validators.py:224 -#, python-format -msgid "User group `%(usergroup)s` already exists" -msgstr "" - -#: rhodecode/model/validators.py:226 msgid "user group name may only contain alphanumeric characters underscores, periods or dashes and must begin with alphanumeric character" msgstr "" @@ -3754,160 +3766,160 @@ msgstr "" msgid "no permission to store repository group in root location" msgstr "" -#: rhodecode/model/validators.py:386 +#: rhodecode/model/validators.py:387 msgid "Invalid characters (non-ascii) in password" msgstr "" -#: rhodecode/model/validators.py:401 -msgid "Invalid old password" -msgstr "" - -#: rhodecode/model/validators.py:418 +#: rhodecode/model/validators.py:406 msgid "Passwords do not match" msgstr "" -#: rhodecode/model/validators.py:436 +#: rhodecode/model/validators.py:426 msgid "invalid password" msgstr "" -#: rhodecode/model/validators.py:437 +#: rhodecode/model/validators.py:427 msgid "invalid user name" msgstr "" -#: rhodecode/model/validators.py:438 +#: rhodecode/model/validators.py:428 msgid "Your account is disabled" msgstr "" -#: rhodecode/model/validators.py:470 -msgid "Token mismatch" -msgstr "" - -#: rhodecode/model/validators.py:484 +#: rhodecode/model/validators.py:464 #, python-format msgid "Repository name %(repo)s is disallowed" msgstr "" -#: rhodecode/model/validators.py:486 +#: rhodecode/model/validators.py:466 #, python-format msgid "Repository with name %(repo)s already exists" msgstr "" -#: rhodecode/model/validators.py:488 +#: rhodecode/model/validators.py:468 #, python-format msgid "Repository group with name \"%(repo)s\" already exists" msgstr "" -#: rhodecode/model/validators.py:491 +#: rhodecode/model/validators.py:471 #, python-format msgid "Repository with name %(repo)s exists in group \"%(group)s\"" msgstr "" -#: rhodecode/model/validators.py:493 +#: rhodecode/model/validators.py:473 #, python-format msgid "Repository group with name \"%(repo)s\" exists in group \"%(group)s\"" msgstr "" -#: rhodecode/model/validators.py:581 +#: rhodecode/model/validators.py:566 #: rhodecode/model/validation_schema/schemas/repo_schema.py:219 msgid "Repository name cannot end with .git" msgstr "" -#: rhodecode/model/validators.py:640 +#: rhodecode/model/validators.py:626 #, python-format msgid "invalid clone url for %(rtype)s repository" msgstr "" -#: rhodecode/model/validators.py:641 +#: rhodecode/model/validators.py:627 #, python-format msgid "Invalid clone url, provide a valid clone url starting with one of %(allowed_prefixes)s" msgstr "" -#: rhodecode/model/validators.py:670 +#: rhodecode/model/validators.py:659 msgid "Fork have to be the same type as parent" msgstr "" -#: rhodecode/model/validators.py:685 +#: rhodecode/model/validators.py:676 msgid "You do not have the permission to create repositories in this group." msgstr "" -#: rhodecode/model/validators.py:688 +#: rhodecode/model/validators.py:679 #: rhodecode/model/validation_schema/schemas/repo_schema.py:125 msgid "You do not have the permission to store repositories in the root location." msgstr "" -#: rhodecode/model/validators.py:748 +#: rhodecode/model/validators.py:739 msgid "This username or user group name is not valid" msgstr "" -#: rhodecode/model/validators.py:879 +#: rhodecode/model/validators.py:852 msgid "This is not a valid path" msgstr "" -#: rhodecode/model/validators.py:894 +#: rhodecode/model/validators.py:870 msgid "This e-mail address is already taken" msgstr "" -#: rhodecode/model/validators.py:914 +#: rhodecode/model/validators.py:892 #, python-format msgid "e-mail \"%(email)s\" does not exist." msgstr "" -#: rhodecode/model/validators.py:935 +#: rhodecode/model/validators.py:913 #, python-format msgid "Revisions %(revs)s are already part of pull request or have set status" msgstr "" -#: rhodecode/model/validators.py:966 -#: rhodecode/model/validation_schema/validators.py:40 -#: rhodecode/model/validation_schema/validators.py:53 +#: rhodecode/model/validators.py:946 +#: rhodecode/model/validation_schema/validators.py:41 +#: rhodecode/model/validation_schema/validators.py:54 msgid "Please enter a valid IPv4 or IpV6 address" msgstr "" -#: rhodecode/model/validators.py:967 +#: rhodecode/model/validators.py:947 #, python-format msgid "The network size (bits) must be within the range of 0-32 (not %(bits)r)" msgstr "" -#: rhodecode/model/validators.py:994 +#: rhodecode/model/validators.py:975 msgid "Key name can only consist of letters, underscore, dash or numbers" msgstr "" -#: rhodecode/model/validators.py:1009 +#: rhodecode/model/validators.py:992 #, python-format msgid "Plugins %(loaded)s and %(next_to_load)s both export the same name" msgstr "" -#: rhodecode/model/validators.py:1012 +#: rhodecode/model/validators.py:995 #, python-format msgid "The plugin \"%(plugin_id)s\" is missing an includeme function." msgstr "" -#: rhodecode/model/validators.py:1015 +#: rhodecode/model/validators.py:998 #, python-format msgid "Can not load plugin \"%(plugin_id)s\"" msgstr "" -#: rhodecode/model/validators.py:1017 +#: rhodecode/model/validators.py:1000 #, python-format msgid "No plugin available with ID \"%(plugin_id)s\"" msgstr "" -#: rhodecode/model/validation_schema/validators.py:61 +#: rhodecode/model/validators.py:1068 +msgid "Url must start with http or /" +msgstr "" + +#: rhodecode/model/validation_schema/validators.py:62 msgid "Invalid glob pattern" msgstr "" -#: rhodecode/model/validation_schema/validators.py:70 +#: rhodecode/model/validation_schema/validators.py:71 msgid "Name must start with a letter or number. Got `{}`" msgstr "" -#: rhodecode/model/validation_schema/validators.py:132 +#: rhodecode/model/validation_schema/validators.py:133 msgid "Invalid clone url, provide a valid clone url starting with one of {allowed_prefixes}" msgstr "" -#: rhodecode/model/validation_schema/validators.py:138 +#: rhodecode/model/validation_schema/validators.py:139 msgid "invalid clone url for {repo_type} repository" msgstr "" +#: rhodecode/model/validation_schema/validators.py:148 +msgid "Please enter a valid json object" +msgstr "" + #: rhodecode/model/validation_schema/schemas/comment_schema.py:42 #: rhodecode/model/validation_schema/schemas/gist_schema.py:89 msgid "Gist with name {} already exists" @@ -3954,33 +3966,33 @@ msgstr "" msgid "Integration scope" msgstr "" -#: rhodecode/model/validation_schema/schemas/integration_schema.py:217 +#: rhodecode/model/validation_schema/schemas/integration_schema.py:216 msgid "General integration options" msgstr "" -#: rhodecode/model/validation_schema/schemas/integration_schema.py:220 +#: rhodecode/model/validation_schema/schemas/integration_schema.py:219 msgid "{integration_type} settings" msgstr "" -#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:47 -#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:51 +#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:52 +#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:56 msgid "Parent repository group `{}` does not exist" msgstr "" -#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:53 +#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:58 msgid "You do not have the permission to store repository groups in the root location." msgstr "" -#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:113 +#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:118 msgid "Repo group owner with id `{}` does not exists" msgstr "" -#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:131 -#: rhodecode/model/validation_schema/schemas/repo_schema.py:204 -msgid "Repository with name `{}` already exists" -msgstr "" - #: rhodecode/model/validation_schema/schemas/repo_group_schema.py:136 +#: rhodecode/model/validation_schema/schemas/repo_schema.py:204 +msgid "Repository with name `{}` already exists" +msgstr "" + +#: rhodecode/model/validation_schema/schemas/repo_group_schema.py:141 #: rhodecode/model/validation_schema/schemas/repo_schema.py:209 msgid "Repository group with name `{}` already exists" msgstr "" @@ -4018,449 +4030,449 @@ msgstr "" msgid "New password must be different to old password" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:27153 -#: rhodecode/public/js/scripts.js:19001 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:32 +#: rhodecode/public/js/rhodecode-components.js:28706 +#: rhodecode/public/js/scripts.js:20554 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:34 #: rhodecode/public/js/src/plugins/jquery.autocomplete.js:87 msgid "No results" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29084 -#: rhodecode/public/js/scripts.js:20932 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:104 +#: rhodecode/public/js/rhodecode-components.js:30637 +#: rhodecode/public/js/scripts.js:22485 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:108 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:109 msgid "{0} year" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29085 -#: rhodecode/public/js/scripts.js:20933 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:98 +#: rhodecode/public/js/rhodecode-components.js:30638 +#: rhodecode/public/js/scripts.js:22486 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:102 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:110 msgid "{0} month" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29086 -#: rhodecode/public/js/scripts.js:20934 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:93 +#: rhodecode/public/js/rhodecode-components.js:30639 +#: rhodecode/public/js/scripts.js:22487 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:97 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:111 msgid "{0} day" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29087 -#: rhodecode/public/js/scripts.js:20935 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:95 +#: rhodecode/public/js/rhodecode-components.js:30640 +#: rhodecode/public/js/scripts.js:22488 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:99 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:112 msgid "{0} hour" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29088 -#: rhodecode/public/js/scripts.js:20936 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:97 +#: rhodecode/public/js/rhodecode-components.js:30641 +#: rhodecode/public/js/scripts.js:22489 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:101 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:113 msgid "{0} min" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29089 -#: rhodecode/public/js/scripts.js:20937 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:103 +#: rhodecode/public/js/rhodecode-components.js:30642 +#: rhodecode/public/js/scripts.js:22490 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:107 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:114 msgid "{0} sec" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29109 -#: rhodecode/public/js/scripts.js:20957 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:77 +#: rhodecode/public/js/rhodecode-components.js:30662 +#: rhodecode/public/js/scripts.js:22510 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:81 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:134 msgid "in {0}" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29117 -#: rhodecode/public/js/scripts.js:20965 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:90 +#: rhodecode/public/js/rhodecode-components.js:30670 +#: rhodecode/public/js/scripts.js:22518 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:94 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:142 msgid "{0} ago" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29129 -#: rhodecode/public/js/scripts.js:20977 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:106 +#: rhodecode/public/js/rhodecode-components.js:30682 +#: rhodecode/public/js/scripts.js:22530 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:110 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:154 msgid "{0}, {1} ago" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29131 -#: rhodecode/public/js/scripts.js:20979 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:79 +#: rhodecode/public/js/rhodecode-components.js:30684 +#: rhodecode/public/js/scripts.js:22532 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:83 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:156 msgid "in {0}, {1}" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29135 -#: rhodecode/public/js/scripts.js:20983 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:91 +#: rhodecode/public/js/rhodecode-components.js:30688 +#: rhodecode/public/js/scripts.js:22536 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:95 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:160 msgid "{0} and {1}" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29137 -#: rhodecode/public/js/scripts.js:20985 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:92 +#: rhodecode/public/js/rhodecode-components.js:30690 +#: rhodecode/public/js/scripts.js:22538 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:96 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:162 msgid "{0} and {1} ago" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:29139 -#: rhodecode/public/js/scripts.js:20987 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:78 +#: rhodecode/public/js/rhodecode-components.js:30692 +#: rhodecode/public/js/scripts.js:22540 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:82 #: rhodecode/public/js/src/plugins/jquery.timeago-extension.js:164 msgid "in {0} and {1}" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43198 -#: rhodecode/public/js/scripts.js:35046 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:22 +#: rhodecode/public/js/rhodecode-components.js:44751 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:24 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:4 msgid "Loading more results..." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43201 -#: rhodecode/public/js/scripts.js:35049 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:47 +#: rhodecode/public/js/rhodecode-components.js:44754 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:50 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:7 msgid "Searching..." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43204 -#: rhodecode/public/js/scripts.js:35052 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:27 +#: rhodecode/public/js/rhodecode-components.js:44757 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:29 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:10 msgid "No matches found" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43207 -#: rhodecode/public/js/scripts.js:35055 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:21 +#: rhodecode/public/js/rhodecode-components.js:44760 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:23 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:13 msgid "Loading failed" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43211 -#: rhodecode/public/js/scripts.js:35059 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:38 +#: rhodecode/public/js/rhodecode-components.js:44764 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:41 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:17 msgid "One result is available, press enter to select it." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43213 -#: rhodecode/public/js/scripts.js:35061 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:102 +#: rhodecode/public/js/rhodecode-components.js:44766 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:106 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:19 msgid "{0} results are available, use up and down arrow keys to navigate." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43218 -#: rhodecode/public/js/scripts.js:35066 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:43 +#: rhodecode/public/js/rhodecode-components.js:44771 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:46 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:24 msgid "Please enter {0} or more character" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43220 -#: rhodecode/public/js/scripts.js:35068 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:44 +#: rhodecode/public/js/rhodecode-components.js:44773 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:47 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:26 msgid "Please enter {0} or more characters" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43225 -#: rhodecode/public/js/scripts.js:35073 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:41 +#: rhodecode/public/js/rhodecode-components.js:44778 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:44 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:31 msgid "Please delete {0} character" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43227 -#: rhodecode/public/js/scripts.js:35075 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:42 +#: rhodecode/public/js/rhodecode-components.js:44780 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:45 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:33 msgid "Please delete {0} characters" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43231 -#: rhodecode/public/js/scripts.js:35079 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:69 +#: rhodecode/public/js/rhodecode-components.js:44784 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:73 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:37 msgid "You can only select {0} item" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:43233 -#: rhodecode/public/js/scripts.js:35081 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:70 +#: rhodecode/public/js/rhodecode-components.js:44786 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:74 #: rhodecode/public/js/rhodecode/i18n/select2/translations.js:39 msgid "You can only select {0} items" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:44167 -#: rhodecode/public/js/scripts.js:36015 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:84 +#: rhodecode/public/js/rhodecode-components.js:45724 +#: rhodecode/public/js/scripts.js:37528 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:88 #: rhodecode/public/js/src/rhodecode/changelog.js:35 msgid "showing {0} out of {1} commit" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:44169 -#: rhodecode/public/js/scripts.js:36017 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:85 +#: rhodecode/public/js/rhodecode-components.js:45726 +#: rhodecode/public/js/scripts.js:37530 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:89 #: rhodecode/public/js/src/rhodecode/changelog.js:37 msgid "showing {0} out of {1} commits" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:44615 -#: rhodecode/public/js/scripts.js:36463 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:50 +#: rhodecode/public/js/rhodecode-components.js:46172 +#: rhodecode/public/js/scripts.js:37976 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:53 #: rhodecode/public/js/src/rhodecode/codemirror.js:297 msgid "Set status to Approved" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:44634 -#: rhodecode/public/js/scripts.js:36482 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:51 +#: rhodecode/public/js/rhodecode-components.js:46191 +#: rhodecode/public/js/scripts.js:37995 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:54 #: rhodecode/public/js/src/rhodecode/codemirror.js:316 msgid "Set status to Rejected" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:44653 -#: rhodecode/public/js/scripts.js:36501 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:63 +#: rhodecode/public/js/rhodecode-components.js:46210 +#: rhodecode/public/js/scripts.js:38014 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:66 #: rhodecode/public/js/src/rhodecode/codemirror.js:335 #: rhodecode/templates/email_templates/commit_comment.mako:99 #: rhodecode/templates/email_templates/pull_request_comment.mako:107 msgid "TODO comment" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:44673 -#: rhodecode/public/js/scripts.js:36521 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:37 +#: rhodecode/public/js/rhodecode-components.js:46230 +#: rhodecode/public/js/scripts.js:38034 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:40 #: rhodecode/public/js/src/rhodecode/codemirror.js:355 msgid "Note Comment" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45040 -#: rhodecode/public/js/scripts.js:36888 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:83 +#: rhodecode/public/js/rhodecode-components.js:46597 +#: rhodecode/public/js/scripts.js:38401 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:87 #: rhodecode/public/js/src/rhodecode/comments.js:126 msgid "resolve comment" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45124 -#: rhodecode/public/js/scripts.js:36972 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:58 +#: rhodecode/public/js/rhodecode-components.js:46681 +#: rhodecode/public/js/scripts.js:38485 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:61 #: rhodecode/public/js/src/rhodecode/comments.js:210 msgid "Status Review" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45139 -#: rhodecode/public/js/scripts.js:36987 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:10 +#: rhodecode/public/js/rhodecode-components.js:46696 +#: rhodecode/public/js/scripts.js:38500 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:11 #: rhodecode/public/js/src/rhodecode/comments.js:225 msgid "Comment text will be set automatically based on currently selected status ({0}) ..." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45296 -#: rhodecode/public/js/scripts.js:37144 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:60 +#: rhodecode/public/js/rhodecode-components.js:46853 +#: rhodecode/public/js/scripts.js:38657 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:63 #: rhodecode/public/js/src/rhodecode/comments.js:382 msgid "Submitting..." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45347 -#: rhodecode/public/js/scripts.js:37195 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:20 +#: rhodecode/public/js/rhodecode-components.js:46904 +#: rhodecode/public/js/scripts.js:38708 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:22 #: rhodecode/public/js/src/rhodecode/comments.js:433 #: rhodecode/templates/files/files_browser_tree.mako:51 msgid "Loading ..." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45452 -#: rhodecode/public/js/scripts.js:37300 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:12 -#: rhodecode/public/js/src/rhodecode/comments.js:538 +#: rhodecode/public/js/rhodecode-components.js:47014 +#: rhodecode/public/js/scripts.js:38818 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:13 +#: rhodecode/public/js/src/rhodecode/comments.js:543 msgid "Delete this comment?" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45522 -#: rhodecode/public/js/scripts.js:37370 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:18 -#: rhodecode/public/js/src/rhodecode/comments.js:608 +#: rhodecode/public/js/rhodecode-components.js:47084 +#: rhodecode/public/js/scripts.js:38888 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:20 +#: rhodecode/public/js/src/rhodecode/comments.js:613 msgid "Leave a comment, or click resolve button to resolve TODO comment #{0}" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45599 -#: rhodecode/public/js/scripts.js:37447 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:17 -#: rhodecode/public/js/src/rhodecode/comments.js:685 +#: rhodecode/public/js/rhodecode-components.js:47161 +#: rhodecode/public/js/scripts.js:38965 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:19 +#: rhodecode/public/js/src/rhodecode/comments.js:690 msgid "Leave a comment on line {0}." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45713 -#: rhodecode/public/js/scripts.js:37561 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:64 -#: rhodecode/public/js/src/rhodecode/comments.js:799 +#: rhodecode/public/js/rhodecode-components.js:47275 +#: rhodecode/public/js/scripts.js:39079 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:67 +#: rhodecode/public/js/src/rhodecode/comments.js:804 msgid "TODO from comment {0} was fixed." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45919 -#: rhodecode/public/js/scripts.js:37767 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:87 +#: rhodecode/public/js/rhodecode-components.js:47455 +#: rhodecode/public/js/scripts.js:39259 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:91 #: rhodecode/public/js/src/rhodecode/files.js:150 msgid "truncated result" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45921 -#: rhodecode/public/js/scripts.js:37769 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:88 +#: rhodecode/public/js/rhodecode-components.js:47457 +#: rhodecode/public/js/scripts.js:39261 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:92 #: rhodecode/public/js/src/rhodecode/files.js:152 msgid "truncated results" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:45930 -#: rhodecode/public/js/scripts.js:37778 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:28 +#: rhodecode/public/js/rhodecode-components.js:47466 +#: rhodecode/public/js/scripts.js:39270 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:30 #: rhodecode/public/js/src/rhodecode/files.js:161 msgid "No matching files" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46065 -#: rhodecode/public/js/scripts.js:37913 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:48 +#: rhodecode/public/js/rhodecode-components.js:47601 +#: rhodecode/public/js/scripts.js:39405 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:51 #: rhodecode/public/js/src/rhodecode/files.js:296 msgid "Selection link" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46105 -#: rhodecode/public/js/scripts.js:37953 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:59 +#: rhodecode/public/js/rhodecode-components.js:47641 +#: rhodecode/public/js/scripts.js:39445 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:62 #: rhodecode/public/js/src/rhodecode/followers.js:26 msgid "Stop following this repository" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46106 -#: rhodecode/public/js/scripts.js:37954 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:66 +#: rhodecode/public/js/rhodecode-components.js:47642 +#: rhodecode/public/js/scripts.js:39446 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:69 #: rhodecode/public/js/src/rhodecode/followers.js:27 msgid "Unfollow" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46115 -#: rhodecode/public/js/scripts.js:37963 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:57 +#: rhodecode/public/js/rhodecode-components.js:47651 +#: rhodecode/public/js/scripts.js:39455 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:60 #: rhodecode/public/js/src/rhodecode/followers.js:36 msgid "Start following this repository" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46116 -#: rhodecode/public/js/scripts.js:37964 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:15 +#: rhodecode/public/js/rhodecode-components.js:47652 +#: rhodecode/public/js/scripts.js:39456 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:17 #: rhodecode/public/js/src/rhodecode/followers.js:37 msgid "Follow" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46496 -#: rhodecode/public/js/rhodecode-components.js:46505 -#: rhodecode/public/js/scripts.js:38344 rhodecode/public/js/scripts.js:38353 +#: rhodecode/public/js/rhodecode-components.js:48032 +#: rhodecode/public/js/scripts.js:39836 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:6 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:134 +msgid "All reviewers must vote." +msgstr "" + +#: rhodecode/public/js/rhodecode-components.js:48041 +#: rhodecode/public/js/scripts.js:39845 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:5 -#: rhodecode/public/js/src/rhodecode/pullrequests.js:134 #: rhodecode/public/js/src/rhodecode/pullrequests.js:143 -msgid "All reviewers must vote." -msgstr "" - -#: rhodecode/public/js/rhodecode-components.js:46510 -#: rhodecode/public/js/scripts.js:38358 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:6 +msgid "All individual reviewers must vote." +msgstr "" + +#: rhodecode/public/js/rhodecode-components.js:48046 +#: rhodecode/public/js/scripts.js:39850 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:7 #: rhodecode/public/js/src/rhodecode/pullrequests.js:148 msgid "At least {0} reviewer must vote." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46516 -#: rhodecode/public/js/scripts.js:38364 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:7 +#: rhodecode/public/js/rhodecode-components.js:48052 +#: rhodecode/public/js/scripts.js:39856 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:8 #: rhodecode/public/js/src/rhodecode/pullrequests.js:154 msgid "At least {0} reviewers must vote." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46523 -#: rhodecode/public/js/scripts.js:38371 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:45 -#: rhodecode/public/js/src/rhodecode/pullrequests.js:161 +#: rhodecode/public/js/rhodecode-components.js:48068 +#: rhodecode/public/js/scripts.js:39872 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:48 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:170 msgid "Reviewers picked from source code changes." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46530 -#: rhodecode/public/js/scripts.js:38378 +#: rhodecode/public/js/rhodecode-components.js:48075 +#: rhodecode/public/js/scripts.js:39879 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:4 -#: rhodecode/public/js/src/rhodecode/pullrequests.js:168 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:177 msgid "Adding new reviewers is forbidden." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46537 -#: rhodecode/public/js/scripts.js:38385 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:8 -#: rhodecode/public/js/src/rhodecode/pullrequests.js:175 +#: rhodecode/public/js/rhodecode-components.js:48082 +#: rhodecode/public/js/scripts.js:39886 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:9 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:184 msgid "Author is not allowed to be a reviewer." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46551 -#: rhodecode/public/js/scripts.js:38399 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:11 -#: rhodecode/public/js/src/rhodecode/pullrequests.js:189 +#: rhodecode/public/js/rhodecode-components.js:48096 +#: rhodecode/public/js/scripts.js:39900 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:12 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:198 msgid "Commit Authors are not allowed to be a reviewer." msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46698 -#: rhodecode/public/js/scripts.js:38546 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:68 -#: rhodecode/public/js/src/rhodecode/pullrequests.js:336 +#: rhodecode/public/js/rhodecode-components.js:48198 +#: rhodecode/public/js/scripts.js:40002 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:72 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:300 msgid "User `{0}` not allowed to be a reviewer" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46823 -#: rhodecode/public/js/scripts.js:38671 +#: rhodecode/public/js/rhodecode-components.js:48204 +#: rhodecode/public/js/scripts.js:40008 #: rhodecode/public/js/rhodecode/i18n/js_translations.js:71 -#: rhodecode/public/js/src/rhodecode/pullrequests.js:461 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:306 +msgid "User `{0}` already in reviewers" +msgstr "" + +#: rhodecode/public/js/rhodecode-components.js:48334 +#: rhodecode/public/js/scripts.js:40138 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:75 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:436 msgid "added manually by \"{0}\"" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:46825 -#: rhodecode/public/js/scripts.js:38673 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:82 -#: rhodecode/public/js/src/rhodecode/pullrequests.js:463 +#: rhodecode/public/js/rhodecode-components.js:48338 +#: rhodecode/public/js/scripts.js:40142 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:86 +#: rhodecode/public/js/src/rhodecode/pullrequests.js:440 msgid "member of \"{0}\"" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:47404 -#: rhodecode/public/js/scripts.js:39252 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:75 +#: rhodecode/public/js/rhodecode-components.js:48924 +#: rhodecode/public/js/scripts.js:40728 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:79 #: rhodecode/public/js/src/rhodecode.js:142 msgid "file" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:47424 -#: rhodecode/public/js/scripts.js:39272 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:53 +#: rhodecode/public/js/rhodecode-components.js:48944 +#: rhodecode/public/js/scripts.js:40748 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:56 #: rhodecode/public/js/src/rhodecode.js:162 msgid "Show more" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:47805 -#: rhodecode/public/js/scripts.js:39653 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:72 -#: rhodecode/public/js/src/rhodecode.js:543 +#: rhodecode/public/js/rhodecode-components.js:49356 +#: rhodecode/public/js/scripts.js:41160 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:76 +#: rhodecode/public/js/src/rhodecode.js:574 msgid "date not in future" msgstr "" -#: rhodecode/public/js/rhodecode-components.js:47813 -#: rhodecode/public/js/scripts.js:39661 -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:56 -#: rhodecode/public/js/src/rhodecode.js:551 +#: rhodecode/public/js/rhodecode-components.js:49364 +#: rhodecode/public/js/scripts.js:41168 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:59 +#: rhodecode/public/js/src/rhodecode.js:582 msgid "Specified expiration date" msgstr "" @@ -4469,171 +4481,175 @@ msgid "(from usergroup {0})" msgstr "" #: rhodecode/public/js/rhodecode/i18n/js_translations.js:3 -#: rhodecode/templates/codeblocks/diffs.mako:488 -#: rhodecode/templates/codeblocks/diffs.mako:493 +#: rhodecode/templates/codeblocks/diffs.mako:494 +#: rhodecode/templates/codeblocks/diffs.mako:499 msgid "Add another comment" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:9 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:10 #: rhodecode/public/js/src/i18n_messages.js:5 #: rhodecode/templates/pullrequests/pullrequest_show.mako:331 msgid "Close" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:13 -msgid "Diff to Commit " -msgstr "" - #: rhodecode/public/js/rhodecode/i18n/js_translations.js:14 -msgid "Fetching repository state failed. Error code: {0} {1}. Try refreshing this page." +msgid "Diff to Commit " +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:15 +msgid "Fetching repository state failed. Error code: {0} {1}. Try refreshing this page." msgstr "" #: rhodecode/public/js/rhodecode/i18n/js_translations.js:16 +msgid "Fetching repository state failed. Error code: {0} {1}. Try refreshing this page." +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:18 #: rhodecode/public/js/src/i18n_messages.js:4 msgid "Invite reviewers to this discussion" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:23 -msgid "No bookmarks available yet." -msgstr "" - -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:24 -msgid "No branches available yet." -msgstr "" - #: rhodecode/public/js/rhodecode/i18n/js_translations.js:25 -msgid "No forks available yet." +msgid "No bookmarks available yet." msgstr "" #: rhodecode/public/js/rhodecode/i18n/js_translations.js:26 +msgid "No branches available yet." +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:27 +msgid "No forks available yet." +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:28 msgid "No gists available yet." msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:29 -msgid "No pull requests available yet." -msgstr "" - -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:30 -msgid "No repositories available yet." -msgstr "" - #: rhodecode/public/js/rhodecode/i18n/js_translations.js:31 -msgid "No repository groups available yet." +msgid "No pull requests available yet." +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:32 +msgid "No repositories available yet." msgstr "" #: rhodecode/public/js/rhodecode/i18n/js_translations.js:33 -msgid "No ssh keys available yet." -msgstr "" - -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:34 -msgid "No tags available yet." +msgid "No repository groups available yet." msgstr "" #: rhodecode/public/js/rhodecode/i18n/js_translations.js:35 -msgid "No user groups available yet." +msgid "No ssh keys available yet." msgstr "" #: rhodecode/public/js/rhodecode/i18n/js_translations.js:36 +msgid "No tags available yet." +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:37 +msgid "No user groups available yet." +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:38 msgid "No users available yet." msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:39 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:42 #: rhodecode/templates/changelog/changelog.mako:59 msgid "Open new pull request" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:40 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:43 msgid "Open new pull request for selected commit" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:46 -msgid "Saving..." -msgstr "" - #: rhodecode/public/js/rhodecode/i18n/js_translations.js:49 -#: rhodecode/public/js/src/i18n_messages.js:6 -#: rhodecode/templates/admin/settings/settings_email.mako:48 -msgid "Send" +msgid "Saving..." msgstr "" #: rhodecode/public/js/rhodecode/i18n/js_translations.js:52 -msgid "Show at Commit " -msgstr "" - -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:54 -msgid "Show selected commit __S" +#: rhodecode/public/js/src/i18n_messages.js:6 +#: rhodecode/templates/admin/settings/settings_email.mako:48 +msgid "Send" msgstr "" #: rhodecode/public/js/rhodecode/i18n/js_translations.js:55 +msgid "Show at Commit " +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:57 +msgid "Show selected commit __S" +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:58 msgid "Show selected commits __S ... __E" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:61 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:64 #: rhodecode/public/js/src/i18n_messages.js:7 msgid "Switch to chat" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:62 -#: rhodecode/public/js/src/i18n_messages.js:8 -msgid "Switch to comment" -msgstr "" - #: rhodecode/public/js/rhodecode/i18n/js_translations.js:65 +#: rhodecode/public/js/src/i18n_messages.js:8 +msgid "Switch to comment" +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:68 msgid "There are currently no open pull requests requiring your participation." msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:67 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:70 msgid "Updating..." msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:73 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:77 #: rhodecode/templates/admin/auth/auth_settings.mako:71 msgid "disabled" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:74 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:78 #: rhodecode/templates/admin/auth/auth_settings.mako:71 msgid "enabled" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:76 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:80 msgid "files" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:81 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:85 #: rhodecode/templates/pullrequests/pullrequest.mako:140 msgid "loading..." msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:86 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:90 msgid "specify commit" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:89 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:93 msgid "{0} active out of {1} users" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:94 +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:98 msgid "{0} days" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:96 -msgid "{0} hours" -msgstr "" - -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:99 -msgid "{0} months" -msgstr "" - #: rhodecode/public/js/rhodecode/i18n/js_translations.js:100 +msgid "{0} hours" +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:103 +msgid "{0} months" +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:104 msgid "{0} out of {1} ssh keys" msgstr "" -#: rhodecode/public/js/rhodecode/i18n/js_translations.js:101 -msgid "{0} out of {1} users" -msgstr "" - #: rhodecode/public/js/rhodecode/i18n/js_translations.js:105 +msgid "{0} out of {1} users" +msgstr "" + +#: rhodecode/public/js/rhodecode/i18n/js_translations.js:109 msgid "{0} years" msgstr "" @@ -4707,12 +4723,17 @@ msgstr "" msgid "Edit Repository Group" msgstr "" -#: rhodecode/templates/index_base.mako:97 -#: rhodecode/templates/index_base.mako:125 +#: rhodecode/templates/index_base.mako:68 +msgid "No repositories or repositories groups exists here." +msgstr "" + +#: rhodecode/templates/index_base.mako:86 +#: rhodecode/templates/index_base.mako:116 #: rhodecode/templates/admin/gists/index.mako:112 #: rhodecode/templates/admin/integrations/list.mako:106 #: rhodecode/templates/admin/my_account/my_account_pullrequests.mako:55 #: rhodecode/templates/admin/my_account/my_account_repos.mako:31 +#: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:39 #: rhodecode/templates/admin/my_account/my_account_watched.mako:31 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:53 #: rhodecode/templates/admin/repos/repo_add_base.mako:9 @@ -4729,13 +4750,14 @@ msgstr "" msgid "Name" msgstr "" -#: rhodecode/templates/index_base.mako:100 -#: rhodecode/templates/index_base.mako:128 +#: rhodecode/templates/index_base.mako:89 +#: rhodecode/templates/index_base.mako:119 #: rhodecode/templates/admin/gists/index.mako:114 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:15 #: rhodecode/templates/admin/my_account/my_account_auth_tokens.mako:71 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:10 #: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:55 +#: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:44 #: rhodecode/templates/admin/permissions/permissions_ssh_keys.mako:49 #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:45 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:55 @@ -4765,20 +4787,21 @@ msgstr "" #: rhodecode/templates/forks/forks.mako:72 #: rhodecode/templates/pullrequests/pullrequest.mako:54 #: rhodecode/templates/pullrequests/pullrequest_show.mako:169 -#: rhodecode/templates/pullrequests/pullrequest_show.mako:493 -#: rhodecode/templates/summary/components.mako:82 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:481 +#: rhodecode/templates/summary/components.mako:88 msgid "Description" msgstr "" -#: rhodecode/templates/index_base.mako:103 -#: rhodecode/templates/index_base.mako:131 +#: rhodecode/templates/index_base.mako:92 +#: rhodecode/templates/index_base.mako:122 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:59 #: rhodecode/templates/admin/repos/repos.mako:60 msgid "Last Change" msgstr "" -#: rhodecode/templates/index_base.mako:105 -#: rhodecode/templates/index_base.mako:136 +#: rhodecode/templates/index_base.mako:94 +#: rhodecode/templates/index_base.mako:127 +#: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:50 #: rhodecode/templates/admin/repo_groups/repo_group_edit_advanced.mako:5 #: rhodecode/templates/admin/repo_groups/repo_group_edit_settings.mako:37 #: rhodecode/templates/admin/repo_groups/repo_groups.mako:63 @@ -4790,11 +4813,11 @@ msgstr "" #: rhodecode/templates/admin/user_groups/user_groups.mako:71 #: rhodecode/templates/admin/users/user_edit_groups.mako:65 #: rhodecode/templates/forks/forks.mako:68 -#: rhodecode/templates/summary/components.mako:203 +#: rhodecode/templates/summary/components.mako:209 msgid "Owner" msgstr "" -#: rhodecode/templates/index_base.mako:134 +#: rhodecode/templates/index_base.mako:125 #: rhodecode/templates/admin/my_account/my_account_repos.mako:35 #: rhodecode/templates/admin/my_account/my_account_watched.mako:35 #: rhodecode/templates/admin/repos/repos.mako:63 @@ -4806,7 +4829,7 @@ msgstr "" #: rhodecode/templates/email_templates/commit_comment.mako:49 #: rhodecode/templates/email_templates/commit_comment.mako:88 #: rhodecode/templates/files/file_authors_box.mako:31 -#: rhodecode/templates/pullrequests/pullrequest_show.mako:491 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:479 #: rhodecode/templates/search/search_commit.mako:6 #: rhodecode/templates/summary/summary_commits.mako:8 #: rhodecode/templates/tags/tags.mako:66 @@ -4823,7 +4846,7 @@ msgid "Home" msgstr "" #: rhodecode/templates/login.mako:5 rhodecode/templates/login.mako:35 -#: rhodecode/templates/login.mako:75 rhodecode/templates/base/base.mako:341 +#: rhodecode/templates/login.mako:75 rhodecode/templates/base/base.mako:343 #: rhodecode/templates/debug_style/login.html:60 msgid "Sign In" msgstr "" @@ -4845,7 +4868,7 @@ msgid "Password reset is disabled. Pleas msgstr "" #: rhodecode/templates/login.mako:68 rhodecode/templates/password_reset.mako:37 -#: rhodecode/templates/base/base.mako:46 +#: rhodecode/templates/base/base.mako:48 #: rhodecode/templates/errors/error_document.mako:63 msgid "Support" msgstr "" @@ -4998,7 +5021,7 @@ msgid "Repository" msgstr "" #: rhodecode/templates/admin/admin_audit_logs.mako:5 -#: rhodecode/templates/base/base.mako:75 +#: rhodecode/templates/base/base.mako:77 msgid "Admin audit logs" msgstr "" @@ -5179,7 +5202,7 @@ msgstr "" #: rhodecode/templates/admin/gists/edit.mako:102 #: rhodecode/templates/base/issue_tracker_settings.mako:73 -#: rhodecode/templates/changeset/changeset_file_comment.mako:390 +#: rhodecode/templates/changeset/changeset_file_comment.mako:391 #: rhodecode/templates/codeblocks/diffs.mako:70 #: rhodecode/templates/files/files_add.mako:108 #: rhodecode/templates/files/files_delete.mako:69 @@ -5251,7 +5274,7 @@ msgstr "" #: rhodecode/templates/changeset/changeset.mako:203 #: rhodecode/templates/compare/compare_commits.mako:18 #: rhodecode/templates/files/files_browser_tree.mako:9 -#: rhodecode/templates/pullrequests/pullrequest_show.mako:490 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:478 #: rhodecode/templates/pullrequests/pullrequests.mako:112 #: rhodecode/templates/search/search_commit.mako:16 #: rhodecode/templates/summary/summary_commits.mako:11 @@ -5354,7 +5377,7 @@ msgstr "" #: rhodecode/templates/admin/repos/repo_edit.mako:46 #: rhodecode/templates/admin/settings/settings.mako:14 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:33 -#: rhodecode/templates/base/base.mako:84 rhodecode/templates/base/base.mako:249 +#: rhodecode/templates/base/base.mako:86 rhodecode/templates/base/base.mako:251 msgid "Settings" msgstr "" @@ -5457,7 +5480,7 @@ msgid "No description available" msgstr "" #: rhodecode/templates/admin/my_account/my_account.mako:5 -#: rhodecode/templates/base/base.mako:355 +#: rhodecode/templates/base/base.mako:357 msgid "My account" msgstr "" @@ -5485,35 +5508,40 @@ msgstr "" msgid "SSH Keys" msgstr "" -#: rhodecode/templates/admin/my_account/my_account.mako:36 -msgid "OAuth Identities" +#: rhodecode/templates/admin/my_account/my_account.mako:33 +#: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:5 +msgid "User Group Membership" msgstr "" #: rhodecode/templates/admin/my_account/my_account.mako:38 -#: rhodecode/templates/admin/users/user_edit.mako:44 -msgid "Emails" +msgid "OAuth Identities" msgstr "" #: rhodecode/templates/admin/my_account/my_account.mako:40 -msgid "Watched" -msgstr "" - -#: rhodecode/templates/admin/my_account/my_account.mako:41 -#: rhodecode/templates/admin/notifications/notifications_show_all.mako:43 -#: rhodecode/templates/base/base.mako:239 -msgid "Pull Requests" +#: rhodecode/templates/admin/users/user_edit.mako:44 +msgid "Emails" msgstr "" #: rhodecode/templates/admin/my_account/my_account.mako:42 +msgid "Watched" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.mako:43 +#: rhodecode/templates/admin/notifications/notifications_show_all.mako:43 +#: rhodecode/templates/base/base.mako:241 +msgid "Pull Requests" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account.mako:44 #: rhodecode/templates/admin/permissions/permissions.mako:14 #: rhodecode/templates/admin/repo_groups/repo_group_edit.mako:49 #: rhodecode/templates/admin/repos/repo_edit.mako:49 #: rhodecode/templates/admin/user_groups/user_group_edit.mako:34 -#: rhodecode/templates/base/base.mako:80 +#: rhodecode/templates/base/base.mako:82 msgid "Permissions" msgstr "" -#: rhodecode/templates/admin/my_account/my_account.mako:43 +#: rhodecode/templates/admin/my_account/my_account.mako:45 msgid "Live Notifications" msgstr "" @@ -5730,6 +5758,23 @@ msgstr "" msgid "Public key, begins with 'ssh-rsa', 'ssh-dss', 'ssh-ed25519', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', or 'ecdsa-sha2-nistp521'" msgstr "" +#: rhodecode/templates/admin/my_account/my_account_ssh_keys.mako:71 +#: rhodecode/templates/admin/users/user_edit_ssh_keys.mako:66 +msgid "Click add to use this generate SSH key" +msgstr "" + +#: rhodecode/templates/admin/my_account/my_account_user_group_membership.mako:49 +#: rhodecode/templates/admin/repos/repo_edit_caches.mako:41 +#: rhodecode/templates/admin/user_groups/user_group_add.mako:52 +#: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:51 +#: rhodecode/templates/admin/user_groups/user_groups.mako:69 +#: rhodecode/templates/admin/users/user_add.mako:97 +#: rhodecode/templates/admin/users/user_edit_groups.mako:64 +#: rhodecode/templates/admin/users/user_edit_profile.mako:90 +#: rhodecode/templates/admin/users/users.mako:74 +msgid "Active" +msgstr "" + #: rhodecode/templates/admin/my_account/my_account_watched.mako:3 msgid "Your Watched Repositories" msgstr "" @@ -5926,7 +5971,7 @@ msgstr "" #: rhodecode/templates/admin/repo_groups/repo_group_add.mako:14 #: rhodecode/templates/admin/users/user_edit_advanced.mako:12 -#: rhodecode/templates/base/base.mako:77 rhodecode/templates/base/base.mako:151 +#: rhodecode/templates/base/base.mako:79 rhodecode/templates/base/base.mako:153 msgid "Repository groups" msgstr "" @@ -6110,7 +6155,7 @@ msgid "Import Existing Repository ?" msgstr "" #: rhodecode/templates/admin/repos/repo_add_base.mako:23 -#: rhodecode/templates/base/base.mako:196 +#: rhodecode/templates/base/base.mako:198 msgid "Clone from" msgstr "" @@ -6184,7 +6229,7 @@ msgid "Remote" msgstr "" #: rhodecode/templates/admin/repos/repo_edit.mako:72 -#: rhodecode/templates/summary/components.mako:143 +#: rhodecode/templates/summary/components.mako:149 msgid "Statistics" msgstr "" @@ -6209,103 +6254,107 @@ msgstr "" msgid "Cached Commit id" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:14 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:9 +msgid "Attached scoped tokens" +msgstr "" + +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:15 #, python-format msgid "Repository: %s" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:24 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:25 msgid "Fork Reference" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:30 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:31 #, python-format msgid "This repository is a fork of %(repo_link)s" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:36 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:37 msgid "Set" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:39 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:40 msgid "Manually set this repository as a fork of another from the list" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:48 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:49 msgid "Public Journal Visibility" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:55 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:56 msgid "Remove from Public Journal" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:59 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:60 msgid "Add to Public Journal" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:64 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:65 msgid "All actions made on this repository will be visible to everyone following the public journal." msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:73 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:74 msgid "Locking state" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:82 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:83 msgid "This Repository is not currently locked." msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:89 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:90 msgid "Confirm to unlock repository." msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:91 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:92 msgid "Unlock repository" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:96 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:97 msgid "Confirm to lock repository." msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:98 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:99 msgid "Lock Repository" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:104 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:105 msgid "Force repository locking. This only works when anonymous access is disabled. Pulling from the repository locks the repository to that user until the same user pushes to that repository again." msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:113 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:114 msgid "Delete repository" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:124 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:125 msgid "Detach forks" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:129 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:130 msgid "Delete forks" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:138 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:139 #: rhodecode/templates/data_table/_dt_elements.mako:172 #, python-format msgid "Confirm to delete this repository: %s" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:140 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:141 msgid "Delete This Repository" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:145 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:146 msgid "This repository will be renamed in a special way in order to make it inaccessible to RhodeCode Enterprise and its VCS systems. If you need to fully delete it from the file system, please do it manually, or with rhodecode-cleanup-repos command available in rhodecode-tools." msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:179 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:180 msgid "Change repository" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:179 +#: rhodecode/templates/admin/repos/repo_edit_advanced.mako:180 msgid "Pick repository" msgstr "" @@ -6349,17 +6398,6 @@ msgstr "" msgid "Key" msgstr "" -#: rhodecode/templates/admin/repos/repo_edit_caches.mako:41 -#: rhodecode/templates/admin/user_groups/user_group_add.mako:52 -#: rhodecode/templates/admin/user_groups/user_group_edit_settings.mako:51 -#: rhodecode/templates/admin/user_groups/user_groups.mako:69 -#: rhodecode/templates/admin/users/user_add.mako:97 -#: rhodecode/templates/admin/users/user_edit_groups.mako:64 -#: rhodecode/templates/admin/users/user_edit_profile.mako:90 -#: rhodecode/templates/admin/users/users.mako:74 -msgid "Active" -msgstr "" - #: rhodecode/templates/admin/repos/repo_edit_fields.mako:3 msgid "Custom extra fields for this repository" msgstr "" @@ -6513,7 +6551,7 @@ msgid "Settings for Repository: %s" msgstr "" #: rhodecode/templates/admin/repos/repo_edit_settings.mako:22 -msgid "Non-changeable id" +msgid "permalink id" msgstr "" #: rhodecode/templates/admin/repos/repo_edit_settings.mako:22 @@ -6699,7 +6737,7 @@ msgstr "" #: rhodecode/templates/admin/settings/settings_global.mako:139 #: rhodecode/templates/admin/settings/settings_labs.mako:48 #: rhodecode/templates/admin/settings/settings_vcs.mako:13 -#: rhodecode/templates/admin/settings/settings_visual.mako:210 +#: rhodecode/templates/admin/settings/settings_visual.mako:214 msgid "Save settings" msgstr "" @@ -6977,6 +7015,14 @@ msgstr "" msgid "Gunicorn process management" msgstr "" +#: rhodecode/templates/admin/settings/settings_process_management.mako:11 +msgid "start auto refresh" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_process_management.mako:12 +msgid "stop auto refresh" +msgstr "" + #: rhodecode/templates/admin/settings/settings_search.mako:3 msgid "RhodeCode Full Text Search" msgstr "" @@ -7025,11 +7071,6 @@ msgstr "" msgid "Cleanup sessions" msgstr "" -#: rhodecode/templates/admin/settings/settings_supervisor_tail.mako:1 -#, python-format -msgid "Last %(size)s bytes of process logs, use ?offset=[num] GET param to set custom size" -msgstr "" - #: rhodecode/templates/admin/settings/settings_system.mako:11 msgid "create summary snapshot" msgstr "" @@ -7174,24 +7215,26 @@ msgid "Default renderer used to render c msgstr "" #: rhodecode/templates/admin/settings/settings_visual.mako:170 -msgid "Clone URL" -msgstr "" - -#: rhodecode/templates/admin/settings/settings_visual.mako:179 +msgid "Clone URL templates" +msgstr "" + +#: rhodecode/templates/admin/settings/settings_visual.mako:181 msgid "" "Schema of clone url construction eg. '{scheme}://{user}@{netloc}/{repo}', available vars:\n" " {scheme} 'http' or 'https' sent from running RhodeCode server,\n" " {user} current user username,\n" +" {sys_user} current system user running this process, usefull for ssh,\n" +" {hostname} hostname of this server running RhodeCode,\n" " {netloc} network location/server host of running RhodeCode server,\n" " {repo} full repository name,\n" " {repoid} ID of repository, can be used to contruct clone-by-id" msgstr "" -#: rhodecode/templates/admin/settings/settings_visual.mako:192 +#: rhodecode/templates/admin/settings/settings_visual.mako:196 msgid "Custom Support Link" msgstr "" -#: rhodecode/templates/admin/settings/settings_visual.mako:200 +#: rhodecode/templates/admin/settings/settings_visual.mako:204 #, python-format msgid "" "Custom url for the support link located at the bottom.\n" @@ -7206,7 +7249,7 @@ msgstr "" #: rhodecode/templates/admin/user_groups/user_group_add.mako:13 #: rhodecode/templates/admin/users/user_edit_advanced.mako:13 -#: rhodecode/templates/base/base.mako:79 rhodecode/templates/base/base.mako:154 +#: rhodecode/templates/base/base.mako:81 rhodecode/templates/base/base.mako:156 msgid "User groups" msgstr "" @@ -7350,7 +7393,7 @@ msgstr "" #: rhodecode/templates/admin/users/user_add.mako:13 #: rhodecode/templates/admin/users/user_edit.mako:14 -#: rhodecode/templates/base/base.mako:78 +#: rhodecode/templates/base/base.mako:80 msgid "Users" msgstr "" @@ -7604,13 +7647,17 @@ msgstr "" msgid "Private key" msgstr "" -#: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:23 +#: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:25 msgid "Public key" msgstr "" -#: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:34 #: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:36 -msgid "Add this generated key" +#: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:38 +msgid "Use this generated key" +msgstr "" + +#: rhodecode/templates/admin/users/user_edit_ssh_keys_generate.mako:40 +msgid "Confirmation required on the next screen" msgstr "" #: rhodecode/templates/admin/users/users.mako:5 @@ -7621,174 +7668,174 @@ msgstr "" msgid "Auth type" msgstr "" -#: rhodecode/templates/base/base.mako:53 +#: rhodecode/templates/base/base.mako:55 #, python-format msgid "RhodeCode instance id: %s" msgstr "" -#: rhodecode/templates/base/base.mako:81 -msgid "Authentication" -msgstr "" - #: rhodecode/templates/base/base.mako:83 +msgid "Authentication" +msgstr "" + +#: rhodecode/templates/base/base.mako:85 msgid "Defaults" msgstr "" -#: rhodecode/templates/base/base.mako:101 +#: rhodecode/templates/base/base.mako:103 #: rhodecode/templates/files/files_pjax.mako:24 #: rhodecode/templates/summary/components.mako:42 msgid "Show More" msgstr "" -#: rhodecode/templates/base/base.mako:188 +#: rhodecode/templates/base/base.mako:190 msgid "Fork of" msgstr "" -#: rhodecode/templates/base/base.mako:205 +#: rhodecode/templates/base/base.mako:207 #, python-format msgid "Repository locked by %(user)s" msgstr "" -#: rhodecode/templates/base/base.mako:210 +#: rhodecode/templates/base/base.mako:212 msgid "Repository not locked. Pull repository to lock it." msgstr "" -#: rhodecode/templates/base/base.mako:228 +#: rhodecode/templates/base/base.mako:230 #: rhodecode/templates/data_table/_dt_elements.mako:46 #: rhodecode/templates/data_table/_dt_elements.mako:47 #: rhodecode/templates/data_table/_dt_elements.mako:197 msgid "Summary" msgstr "" -#: rhodecode/templates/base/base.mako:229 +#: rhodecode/templates/base/base.mako:231 #: rhodecode/templates/data_table/_dt_elements.mako:51 #: rhodecode/templates/data_table/_dt_elements.mako:52 msgid "Changelog" msgstr "" -#: rhodecode/templates/base/base.mako:230 +#: rhodecode/templates/base/base.mako:232 #: rhodecode/templates/data_table/_dt_elements.mako:56 #: rhodecode/templates/data_table/_dt_elements.mako:57 #: rhodecode/templates/files/files.mako:15 msgid "Files" msgstr "" -#: rhodecode/templates/base/base.mako:231 +#: rhodecode/templates/base/base.mako:233 #: rhodecode/templates/bookmarks/bookmarks.mako:68 #: rhodecode/templates/branches/branches.mako:67 #: rhodecode/templates/tags/tags.mako:68 msgid "Compare" msgstr "" -#: rhodecode/templates/base/base.mako:235 +#: rhodecode/templates/base/base.mako:237 #, python-format msgid "Show Pull Requests for %s" msgstr "" -#: rhodecode/templates/base/base.mako:245 +#: rhodecode/templates/base/base.mako:247 msgid "Options" msgstr "" -#: rhodecode/templates/base/base.mako:253 +#: rhodecode/templates/base/base.mako:255 #: rhodecode/templates/changelog/changelog.mako:40 #, python-format msgid "Compare fork with %s" msgstr "" -#: rhodecode/templates/base/base.mako:267 -#: rhodecode/templates/base/base.mako:411 +#: rhodecode/templates/base/base.mako:269 +#: rhodecode/templates/base/base.mako:413 #: rhodecode/templates/search/search.mako:64 msgid "Search" msgstr "" -#: rhodecode/templates/base/base.mako:271 -msgid "Unlock" -msgstr "" - #: rhodecode/templates/base/base.mako:273 +msgid "Unlock" +msgstr "" + +#: rhodecode/templates/base/base.mako:275 msgid "Lock" msgstr "" -#: rhodecode/templates/base/base.mako:278 +#: rhodecode/templates/base/base.mako:280 #: rhodecode/templates/data_table/_dt_elements.mako:61 #: rhodecode/templates/data_table/_dt_elements.mako:62 msgid "Fork" msgstr "" -#: rhodecode/templates/base/base.mako:279 +#: rhodecode/templates/base/base.mako:281 msgid "Create Pull Request" msgstr "" -#: rhodecode/templates/base/base.mako:301 +#: rhodecode/templates/base/base.mako:303 msgid "Sign in" msgstr "" -#: rhodecode/templates/base/base.mako:309 +#: rhodecode/templates/base/base.mako:311 #: rhodecode/templates/debug_style/login.html:28 msgid "Sign in to your account" msgstr "" -#: rhodecode/templates/base/base.mako:326 +#: rhodecode/templates/base/base.mako:328 #: rhodecode/templates/debug_style/login.html:46 msgid "(Forgot password?)" msgstr "" -#: rhodecode/templates/base/base.mako:336 -msgid "Don't have an account?" -msgstr "" - #: rhodecode/templates/base/base.mako:338 +msgid "Don't have an account?" +msgstr "" + +#: rhodecode/templates/base/base.mako:340 msgid "Using external auth? Sign In here." msgstr "" -#: rhodecode/templates/base/base.mako:357 +#: rhodecode/templates/base/base.mako:359 msgid "My personal group" msgstr "" -#: rhodecode/templates/base/base.mako:361 +#: rhodecode/templates/base/base.mako:363 msgid "Sign Out" msgstr "" -#: rhodecode/templates/base/base.mako:393 +#: rhodecode/templates/base/base.mako:395 msgid "Show activity journal" msgstr "" -#: rhodecode/templates/base/base.mako:394 +#: rhodecode/templates/base/base.mako:396 #: rhodecode/templates/journal/journal.mako:4 #: rhodecode/templates/journal/journal.mako:15 msgid "Journal" msgstr "" -#: rhodecode/templates/base/base.mako:399 +#: rhodecode/templates/base/base.mako:401 msgid "Show Public activity journal" msgstr "" -#: rhodecode/templates/base/base.mako:400 +#: rhodecode/templates/base/base.mako:402 msgid "Public journal" msgstr "" -#: rhodecode/templates/base/base.mako:405 +#: rhodecode/templates/base/base.mako:407 msgid "Show Gists" msgstr "" -#: rhodecode/templates/base/base.mako:406 +#: rhodecode/templates/base/base.mako:408 msgid "Gists" msgstr "" -#: rhodecode/templates/base/base.mako:410 +#: rhodecode/templates/base/base.mako:412 msgid "Search in repositories you have access to" msgstr "" -#: rhodecode/templates/base/base.mako:416 +#: rhodecode/templates/base/base.mako:418 msgid "Admin settings" msgstr "" -#: rhodecode/templates/base/base.mako:423 +#: rhodecode/templates/base/base.mako:425 msgid "Delegated Admin settings" msgstr "" -#: rhodecode/templates/base/base.mako:433 -#: rhodecode/templates/base/base.mako:434 +#: rhodecode/templates/base/base.mako:435 +#: rhodecode/templates/base/base.mako:436 #: rhodecode/templates/debug_style/alerts.html:5 #: rhodecode/templates/debug_style/buttons.html:5 #: rhodecode/templates/debug_style/code-block.html:6 @@ -7810,15 +7857,15 @@ msgstr "" msgid "Style" msgstr "" -#: rhodecode/templates/base/base.mako:491 +#: rhodecode/templates/base/base.mako:493 msgid "Go to" msgstr "" -#: rhodecode/templates/base/base.mako:544 +#: rhodecode/templates/base/base.mako:546 msgid "Keyboard shortcuts" msgstr "" -#: rhodecode/templates/base/base.mako:552 +#: rhodecode/templates/base/base.mako:554 msgid "Site-wide shortcuts" msgstr "" @@ -7910,8 +7957,8 @@ msgid "Confirm to remove this pattern:" msgstr "" #: rhodecode/templates/base/issue_tracker_settings.mako:191 -#: rhodecode/templates/changeset/changeset_file_comment.mako:274 -#: rhodecode/templates/changeset/changeset_file_comment.mako:324 +#: rhodecode/templates/changeset/changeset_file_comment.mako:275 +#: rhodecode/templates/changeset/changeset_file_comment.mako:325 #: rhodecode/templates/files/files_add.mako:84 #: rhodecode/templates/files/files_add.mako:230 #: rhodecode/templates/files/files_edit.mako:85 @@ -8228,10 +8275,10 @@ msgid "Compare Selected Bookmarks" msgstr "" #: rhodecode/templates/bookmarks/bookmarks_data.mako:13 -#: rhodecode/templates/changelog/changelog_elements.mako:115 +#: rhodecode/templates/changelog/changelog_elements.mako:121 #: rhodecode/templates/changeset/changeset.mako:115 #: rhodecode/templates/files/base.mako:10 -#: rhodecode/templates/summary/summary_commits.mako:62 +#: rhodecode/templates/summary/summary_commits.mako:68 #, python-format msgid "Bookmark %s" msgstr "" @@ -8250,10 +8297,10 @@ msgid "Compare Selected Branches" msgstr "" #: rhodecode/templates/branches/branches_data.mako:12 -#: rhodecode/templates/changelog/changelog_elements.mako:107 +#: rhodecode/templates/changelog/changelog_elements.mako:113 #: rhodecode/templates/changeset/changeset.mako:128 #: rhodecode/templates/files/base.mako:23 -#: rhodecode/templates/summary/summary_commits.mako:76 +#: rhodecode/templates/summary/summary_commits.mako:82 #, python-format msgid "Branch %s" msgstr "" @@ -8318,79 +8365,79 @@ msgstr "" msgid "load previous" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:26 -#: rhodecode/templates/summary/summary_commits.mako:21 +#: rhodecode/templates/changelog/changelog_elements.mako:32 +#: rhodecode/templates/summary/summary_commits.mako:27 #, python-format msgid "" "Commit status: %s\n" "Click to open associated pull request #%s" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:30 -#: rhodecode/templates/summary/summary_commits.mako:25 -msgid "Commit status: {}" -msgstr "" - #: rhodecode/templates/changelog/changelog_elements.mako:36 #: rhodecode/templates/summary/summary_commits.mako:31 +msgid "Commit status: {}" +msgstr "" + +#: rhodecode/templates/changelog/changelog_elements.mako:42 +#: rhodecode/templates/summary/summary_commits.mako:37 msgid "Commit status: Not Reviewed" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:41 -#: rhodecode/templates/summary/summary_commits.mako:36 +#: rhodecode/templates/changelog/changelog_elements.mako:47 +#: rhodecode/templates/summary/summary_commits.mako:42 msgid "Commit has comments" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:52 +#: rhodecode/templates/changelog/changelog_elements.mako:58 #: rhodecode/templates/changeset/changeset.mako:42 msgid "Copy the full commit id" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:59 +#: rhodecode/templates/changelog/changelog_elements.mako:65 #: rhodecode/templates/changeset/changeset.mako:44 msgid "Commit phase" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:66 -#: rhodecode/templates/changelog/changelog_elements.mako:73 +#: rhodecode/templates/changelog/changelog_elements.mako:72 +#: rhodecode/templates/changelog/changelog_elements.mako:79 #: rhodecode/templates/changeset/changeset.mako:50 #: rhodecode/templates/changeset/changeset.mako:57 msgid "Evolve State" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:66 +#: rhodecode/templates/changelog/changelog_elements.mako:72 #: rhodecode/templates/changeset/changeset.mako:50 msgid "obsolete" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:73 +#: rhodecode/templates/changelog/changelog_elements.mako:79 #: rhodecode/templates/changeset/changeset.mako:57 msgid "hidden" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:77 -#: rhodecode/templates/compare/compare_commits.mako:45 -#: rhodecode/templates/pullrequests/pullrequest_show.mako:528 +#: rhodecode/templates/changelog/changelog_elements.mako:83 +#: rhodecode/templates/compare/compare_commits.mako:50 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:516 #: rhodecode/templates/search/search_commit.mako:36 msgid "Expand commit message" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:101 +#: rhodecode/templates/changelog/changelog_elements.mako:107 #: rhodecode/templates/changeset/changeset.mako:109 #: rhodecode/templates/files/base.mako:4 msgid "merge" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:123 +#: rhodecode/templates/changelog/changelog_elements.mako:129 #: rhodecode/templates/changeset/changeset.mako:122 #: rhodecode/templates/files/base.mako:17 -#: rhodecode/templates/summary/summary_commits.mako:69 +#: rhodecode/templates/summary/summary_commits.mako:75 #: rhodecode/templates/tags/tags_data.mako:12 #, python-format msgid "Tag %s" msgstr "" -#: rhodecode/templates/changelog/changelog_elements.mako:137 +#: rhodecode/templates/changelog/changelog_elements.mako:143 msgid "load next" msgstr "" @@ -8425,7 +8472,7 @@ msgstr "" #: rhodecode/templates/changeset/changeset.mako:89 #: rhodecode/templates/changeset/changeset.mako:95 -#: rhodecode/templates/changeset/changeset_file_comment.mako:81 +#: rhodecode/templates/changeset/changeset_file_comment.mako:82 #: rhodecode/templates/compare/compare_diff.mako:159 msgid "Commit status" msgstr "" @@ -8441,8 +8488,8 @@ msgid "Diff options" msgstr "" #: rhodecode/templates/changeset/changeset.mako:142 -#: rhodecode/templates/codeblocks/diffs.mako:445 -#: rhodecode/templates/codeblocks/diffs.mako:448 +#: rhodecode/templates/codeblocks/diffs.mako:451 +#: rhodecode/templates/codeblocks/diffs.mako:454 msgid "Raw diff" msgstr "" @@ -8459,8 +8506,8 @@ msgid "Patch Diff" msgstr "" #: rhodecode/templates/changeset/changeset.mako:150 -#: rhodecode/templates/codeblocks/diffs.mako:452 -#: rhodecode/templates/codeblocks/diffs.mako:455 +#: rhodecode/templates/codeblocks/diffs.mako:458 +#: rhodecode/templates/codeblocks/diffs.mako:461 msgid "Download diff" msgstr "" @@ -8484,102 +8531,102 @@ msgstr "" msgid "No Parent Commits" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:32 +#: rhodecode/templates/changeset/changeset_file_comment.mako:33 msgid "Resolved by comment #{}" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:39 +#: rhodecode/templates/changeset/changeset_file_comment.mako:40 msgid "Click to resolve this comment" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:66 -#: rhodecode/templates/changeset/changeset_file_comment.mako:68 +#: rhodecode/templates/changeset/changeset_file_comment.mako:67 +#: rhodecode/templates/changeset/changeset_file_comment.mako:69 #, python-format msgid "pull request #%s" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:73 +#: rhodecode/templates/changeset/changeset_file_comment.mako:74 msgid "Status change on commit" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:88 +#: rhodecode/templates/changeset/changeset_file_comment.mako:89 msgid "resolves comment #{}" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:96 -msgid "Pull request author" -msgstr "" - #: rhodecode/templates/changeset/changeset_file_comment.mako:97 +msgid "Pull request author" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.mako:98 msgid "author" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:105 +#: rhodecode/templates/changeset/changeset_file_comment.mako:106 msgid "Outdated comment from pull request version {0}" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:109 -#: rhodecode/templates/changeset/changeset_file_comment.mako:124 +#: rhodecode/templates/changeset/changeset_file_comment.mako:110 +#: rhodecode/templates/changeset/changeset_file_comment.mako:125 msgid "Comment from pull request version {0}" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:121 +#: rhodecode/templates/changeset/changeset_file_comment.mako:122 msgid "Outdated comment from pull request version {}" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:151 -#: rhodecode/templates/changeset/changeset_file_comment.mako:154 -msgid "Prev" -msgstr "" - #: rhodecode/templates/changeset/changeset_file_comment.mako:152 #: rhodecode/templates/changeset/changeset_file_comment.mako:155 +msgid "Prev" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.mako:153 +#: rhodecode/templates/changeset/changeset_file_comment.mako:156 msgid "Next" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:190 +#: rhodecode/templates/changeset/changeset_file_comment.mako:191 msgid "Leave a comment on this Pull Request." msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:192 +#: rhodecode/templates/changeset/changeset_file_comment.mako:193 msgid "Leave a comment on {} commits in this range." msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:194 +#: rhodecode/templates/changeset/changeset_file_comment.mako:195 msgid "Leave a comment on this Commit." msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:282 -#: rhodecode/templates/codeblocks/diffs.mako:65 -msgid "You need to be logged in to leave comments." -msgstr "" - #: rhodecode/templates/changeset/changeset_file_comment.mako:283 #: rhodecode/templates/codeblocks/diffs.mako:65 +msgid "You need to be logged in to leave comments." +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.mako:284 +#: rhodecode/templates/codeblocks/diffs.mako:65 msgid "Login now" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:348 +#: rhodecode/templates/changeset/changeset_file_comment.mako:349 #, python-format msgid "Comments parsed using %s syntax with %s, and %s actions support." msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:350 -msgid "Use @username inside this text to send notification to this RhodeCode user" -msgstr "" - #: rhodecode/templates/changeset/changeset_file_comment.mako:351 +msgid "Use @username inside this text to send notification to this RhodeCode user" +msgstr "" + +#: rhodecode/templates/changeset/changeset_file_comment.mako:352 msgid "Start typing with / for certain actions to be triggered via text box." msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:368 +#: rhodecode/templates/changeset/changeset_file_comment.mako:369 #: rhodecode/templates/pullrequests/pullrequest_show.mako:15 #: rhodecode/templates/pullrequests/pullrequest_show.mako:159 #: rhodecode/templates/pullrequests/pullrequests.mako:52 msgid "Closed" msgstr "" -#: rhodecode/templates/changeset/changeset_file_comment.mako:398 +#: rhodecode/templates/changeset/changeset_file_comment.mako:399 #: rhodecode/templates/compare/compare_diff.mako:104 #: rhodecode/templates/compare/compare_diff.mako:112 #: rhodecode/templates/compare/compare_diff.mako:120 @@ -8675,70 +8722,70 @@ msgstr "" msgid "Hide them" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:284 +#: rhodecode/templates/codeblocks/diffs.mako:290 msgid "File was deleted in this version, and outdated comments were made on it" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:350 +#: rhodecode/templates/codeblocks/diffs.mako:356 #: rhodecode/templates/files/files_source.mako:19 msgid "Copy the full path" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:415 -#: rhodecode/templates/codeblocks/diffs.mako:431 +#: rhodecode/templates/codeblocks/diffs.mako:421 +#: rhodecode/templates/codeblocks/diffs.mako:437 #, python-format msgid "Show file at commit: %(commit_id)s" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:417 -#: rhodecode/templates/codeblocks/diffs.mako:424 +#: rhodecode/templates/codeblocks/diffs.mako:423 +#: rhodecode/templates/codeblocks/diffs.mako:430 msgid "Show file before" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:422 -#: rhodecode/templates/codeblocks/diffs.mako:438 +#: rhodecode/templates/codeblocks/diffs.mako:428 +#: rhodecode/templates/codeblocks/diffs.mako:444 #, python-format msgid "File no longer present at commit: %(commit_id)s" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:433 -#: rhodecode/templates/codeblocks/diffs.mako:440 +#: rhodecode/templates/codeblocks/diffs.mako:439 +#: rhodecode/templates/codeblocks/diffs.mako:446 msgid "Show file after" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:471 +#: rhodecode/templates/codeblocks/diffs.mako:477 msgid "Show comments" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:471 +#: rhodecode/templates/codeblocks/diffs.mako:477 msgid "Hide comments" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:643 -msgid "View side by side" -msgstr "" - -#: rhodecode/templates/codeblocks/diffs.mako:645 -msgid "Side by Side" -msgstr "" - #: rhodecode/templates/codeblocks/diffs.mako:649 +msgid "View side by side" +msgstr "" + +#: rhodecode/templates/codeblocks/diffs.mako:651 +msgid "Side by Side" +msgstr "" + +#: rhodecode/templates/codeblocks/diffs.mako:655 msgid "View unified" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:650 +#: rhodecode/templates/codeblocks/diffs.mako:656 msgid "Unified" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:660 +#: rhodecode/templates/codeblocks/diffs.mako:666 msgid "Expand All Files" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:664 +#: rhodecode/templates/codeblocks/diffs.mako:670 msgid "Collapse All Files" msgstr "" -#: rhodecode/templates/codeblocks/diffs.mako:668 +#: rhodecode/templates/codeblocks/diffs.mako:674 msgid "Wide Mode Diff" msgstr "" @@ -8755,11 +8802,11 @@ msgid "Compare was calculated based on t msgstr "" #: rhodecode/templates/compare/compare_commits.mako:17 -#: rhodecode/templates/pullrequests/pullrequest_show.mako:489 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:477 msgid "Time" msgstr "" -#: rhodecode/templates/compare/compare_commits.mako:73 +#: rhodecode/templates/compare/compare_commits.mako:78 msgid "No commits in this compare" msgstr "" @@ -9317,7 +9364,7 @@ msgid "Close File List" msgstr "" #: rhodecode/templates/files/files_browser.mako:25 -#: rhodecode/templates/summary/summary_commits.mako:103 +#: rhodecode/templates/summary/summary_commits.mako:109 msgid "Add New File" msgstr "" @@ -9593,12 +9640,12 @@ msgid "Pull request reviewers" msgstr "" #: rhodecode/templates/pullrequests/pullrequest.mako:150 -#: rhodecode/templates/pullrequests/pullrequest_show.mako:398 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:386 msgid "Add reviewer or reviewer group" msgstr "" #: rhodecode/templates/pullrequests/pullrequest.mako:302 -#: rhodecode/templates/pullrequests/pullrequest.mako:504 +#: rhodecode/templates/pullrequests/pullrequest.mako:508 msgid "Please select source and target" msgstr "" @@ -9606,19 +9653,19 @@ msgstr "" msgid "Loading compare ..." msgstr "" -#: rhodecode/templates/pullrequests/pullrequest.mako:361 +#: rhodecode/templates/pullrequests/pullrequest.mako:364 msgid "Show detailed compare." msgstr "" -#: rhodecode/templates/pullrequests/pullrequest.mako:368 +#: rhodecode/templates/pullrequests/pullrequest.mako:371 msgid "There are no commits to merge." msgstr "" -#: rhodecode/templates/pullrequests/pullrequest.mako:431 +#: rhodecode/templates/pullrequests/pullrequest.mako:435 msgid "Target repository" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest.mako:441 +#: rhodecode/templates/pullrequests/pullrequest.mako:445 msgid "Select commit reference" msgstr "" @@ -9679,8 +9726,7 @@ msgid "Merge" msgstr "" #: rhodecode/templates/pullrequests/pullrequest_show.mako:140 -#: rhodecode/templates/summary/components.mako:53 -#: rhodecode/templates/summary/components.mako:69 +#: rhodecode/templates/summary/components.mako:66 msgid "Copy the clone url" msgstr "" @@ -9760,77 +9806,73 @@ msgid "Pull request versions not availab msgstr "" #: rhodecode/templates/pullrequests/pullrequest_show.mako:306 -#: rhodecode/templates/pullrequests/pullrequest_show.mako:403 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:391 msgid "Save Changes" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:378 -msgid "Mandatory reviewer" -msgstr "" - -#: rhodecode/templates/pullrequests/pullrequest_show.mako:420 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:408 msgid "Missing requirements:" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:421 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:409 msgid "These commits cannot be displayed, because this repository uses the Mercurial largefiles extension, which was not enabled." msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:429 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:417 msgid "Missing commits" msgstr "" +#: rhodecode/templates/pullrequests/pullrequest_show.mako:418 +msgid "This pull request cannot be displayed, because one or more commits no longer exist in the source repository." +msgstr "" + +#: rhodecode/templates/pullrequests/pullrequest_show.mako:419 +msgid "Please update this pull request, push the commits back into the source repository, or consider closing this pull request." +msgstr "" + #: rhodecode/templates/pullrequests/pullrequest_show.mako:430 -msgid "This pull request cannot be displayed, because one or more commits no longer exist in the source repository." -msgstr "" - -#: rhodecode/templates/pullrequests/pullrequest_show.mako:431 -msgid "Please update this pull request, push the commits back into the source repository, or consider closing this pull request." -msgstr "" - -#: rhodecode/templates/pullrequests/pullrequest_show.mako:442 #, python-format msgid "Showing changes at v%d, commenting is disabled." msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:465 -#: rhodecode/templates/pullrequests/pullrequest_show.mako:467 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:453 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:455 msgid "Update commits" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:467 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:455 msgid "Update is disabled for current view" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:478 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:466 msgid "Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:482 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:470 msgid "commits added: {}, removed: {}" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:500 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:488 msgid "Commit added in displayed changes" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:502 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:490 msgid "Commit removed in displayed changes" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:605 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:593 msgid "there is {num} general comment from older versions" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:606 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:594 msgid "show it" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:608 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:596 msgid "there are {num} general comments from older versions" msgstr "" -#: rhodecode/templates/pullrequests/pullrequest_show.mako:609 +#: rhodecode/templates/pullrequests/pullrequest_show.mako:597 msgid "show them" msgstr "" @@ -9941,74 +9983,59 @@ msgstr "" msgid "File" msgstr "" -#: rhodecode/templates/summary/components.mako:49 -msgid "Read-only url" -msgstr "" - -#: rhodecode/templates/summary/components.mako:56 -#: rhodecode/templates/summary/components.mako:72 +#: rhodecode/templates/summary/components.mako:71 msgid "Copy the clone by id url" msgstr "" -#: rhodecode/templates/summary/components.mako:58 -#: rhodecode/templates/summary/components.mako:74 -msgid "Show by Name" -msgstr "" - -#: rhodecode/templates/summary/components.mako:59 -#: rhodecode/templates/summary/components.mako:75 -msgid "Show by ID" -msgstr "" - -#: rhodecode/templates/summary/components.mako:61 +#: rhodecode/templates/summary/components.mako:76 +msgid "Copy the clone by ssh url" +msgstr "" + +#: rhodecode/templates/summary/components.mako:80 msgid "SVN Protocol is disabled. To enable it, see the" msgstr "" -#: rhodecode/templates/summary/components.mako:61 +#: rhodecode/templates/summary/components.mako:80 msgid "documentation here" msgstr "" -#: rhodecode/templates/summary/components.mako:65 -msgid "Clone url" -msgstr "" - -#: rhodecode/templates/summary/components.mako:94 +#: rhodecode/templates/summary/components.mako:100 msgid "Information" msgstr "" -#: rhodecode/templates/summary/components.mako:110 +#: rhodecode/templates/summary/components.mako:116 msgid "Number of Repository Forks" msgstr "" -#: rhodecode/templates/summary/components.mako:118 +#: rhodecode/templates/summary/components.mako:124 msgid "Calculating Repository Size..." msgstr "" -#: rhodecode/templates/summary/components.mako:149 +#: rhodecode/templates/summary/components.mako:155 msgid "Calculating Code Statistics..." msgstr "" -#: rhodecode/templates/summary/components.mako:153 +#: rhodecode/templates/summary/components.mako:159 msgid "Statistics are disabled for this repository" msgstr "" -#: rhodecode/templates/summary/components.mako:156 +#: rhodecode/templates/summary/components.mako:162 msgid "enable statistics" msgstr "" -#: rhodecode/templates/summary/components.mako:167 -msgid "Downloads" -msgstr "" - #: rhodecode/templates/summary/components.mako:173 +msgid "Downloads" +msgstr "" + +#: rhodecode/templates/summary/components.mako:179 msgid "There are no downloads yet" msgstr "" -#: rhodecode/templates/summary/components.mako:177 +#: rhodecode/templates/summary/components.mako:183 msgid "Downloads are disabled for this repository" msgstr "" -#: rhodecode/templates/summary/components.mako:180 +#: rhodecode/templates/summary/components.mako:186 msgid "enable downloads" msgstr "" @@ -10041,15 +10068,15 @@ msgstr "" msgid "%s RSS feed" msgstr "" -#: rhodecode/templates/summary/summary_commits.mako:100 +#: rhodecode/templates/summary/summary_commits.mako:106 msgid "Add or upload files directly via RhodeCode:" msgstr "" -#: rhodecode/templates/summary/summary_commits.mako:111 +#: rhodecode/templates/summary/summary_commits.mako:117 msgid "Push new repo:" msgstr "" -#: rhodecode/templates/summary/summary_commits.mako:122 +#: rhodecode/templates/summary/summary_commits.mako:128 msgid "Existing repository?" msgstr "" @@ -10078,9 +10105,3 @@ msgstr "" msgid "hello" msgstr "" -#: rhodecode/tests/lib/test_ext_json.py:163 -msgid "singular" -msgid_plural "plural" -msgstr[0] "" -msgstr[1] "" - diff --git a/rhodecode/integrations/__init__.py b/rhodecode/integrations/__init__.py --- a/rhodecode/integrations/__init__.py +++ b/rhodecode/integrations/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 diff --git a/rhodecode/integrations/registry.py b/rhodecode/integrations/registry.py --- a/rhodecode/integrations/registry.py +++ b/rhodecode/integrations/registry.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -30,7 +30,7 @@ class IntegrationTypeRegistry(collection def register_integration_type(self, IntegrationType): key = IntegrationType.key if key in self: - log.warning( + log.debug( 'Overriding existing integration type %s (%s) with %s' % ( self[key], key, IntegrationType)) diff --git a/rhodecode/integrations/routes.py b/rhodecode/integrations/routes.py --- a/rhodecode/integrations/routes.py +++ b/rhodecode/integrations/routes.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 diff --git a/rhodecode/integrations/schema.py b/rhodecode/integrations/schema.py --- a/rhodecode/integrations/schema.py +++ b/rhodecode/integrations/schema.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 diff --git a/rhodecode/integrations/tests/__init__.py b/rhodecode/integrations/tests/__init__.py --- a/rhodecode/integrations/tests/__init__.py +++ b/rhodecode/integrations/tests/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2016-2017 RhodeCode GmbH +# Copyright (C) 2016-2018 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 diff --git a/rhodecode/integrations/tests/test_integrations.py b/rhodecode/integrations/tests/test_integrations.py --- a/rhodecode/integrations/tests/test_integrations.py +++ b/rhodecode/integrations/tests/test_integrations.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/integrations/types/__init__.py b/rhodecode/integrations/types/__init__.py --- a/rhodecode/integrations/types/__init__.py +++ b/rhodecode/integrations/types/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 diff --git a/rhodecode/integrations/types/base.py b/rhodecode/integrations/types/base.py --- a/rhodecode/integrations/types/base.py +++ b/rhodecode/integrations/types/base.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 diff --git a/rhodecode/integrations/types/email.py b/rhodecode/integrations/types/email.py --- a/rhodecode/integrations/types/email.py +++ b/rhodecode/integrations/types/email.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -208,6 +208,7 @@ email_icon = ''' ''' + class EmailSettingsSchema(colander.Schema): @colander.instantiate(validator=colander.Length(min=1)) class recipients(colander.SequenceSchema): @@ -251,8 +252,12 @@ def repo_push_handler(data, settings): commit_num = len(data['push']['commits']) server_url = data['server_url'] - if commit_num == 0: - subject = '[{repo_name}] {author} pushed {commit_num} commit on branches: {branches}'.format( + if commit_num == 1: + if data['push']['branches']: + _subject = '[{repo_name}] {author} pushed {commit_num} commit on branches: {branches}' + else: + _subject = '[{repo_name}] {author} pushed {commit_num} commit' + subject = _subject.format( author=data['actor']['username'], repo_name=data['repo']['repo_name'], commit_num=commit_num, @@ -260,7 +265,11 @@ def repo_push_handler(data, settings): branch['name'] for branch in data['push']['branches']) ) else: - subject = '[{repo_name}] {author} pushed {commit_num} commits on branches: {branches}'.format( + if data['push']['branches']: + _subject = '[{repo_name}] {author} pushed {commit_num} commits on branches: {branches}' + else: + _subject = '[{repo_name}] {author} pushed {commit_num} commits' + subject = _subject.format( author=data['actor']['username'], repo_name=data['repo']['repo_name'], commit_num=commit_num, diff --git a/rhodecode/integrations/types/hipchat.py b/rhodecode/integrations/types/hipchat.py --- a/rhodecode/integrations/types/hipchat.py +++ b/rhodecode/integrations/types/hipchat.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -20,18 +20,16 @@ from __future__ import unicode_literals import deform -import re import logging import requests import colander import textwrap -from celery.task import task +from collections import OrderedDict from mako.template import Template - from rhodecode import events from rhodecode.translation import _ from rhodecode.lib import helpers as h -from rhodecode.lib.celerylib import run_task +from rhodecode.lib.celerylib import run_task, async_task, RequestContextTask from rhodecode.lib.colander_utils import strip_whitespace from rhodecode.integrations.types.base import IntegrationTypeBase @@ -218,7 +216,7 @@ class HipchatIntegrationType(Integration branch_data = {branch['name']: branch for branch in data['push']['branches']} - branches_commits = {} + branches_commits = OrderedDict() for commit in data['push']['commits']: if commit['branch'] not in branches_commits: branch_commits = {'branch': branch_data[commit['branch']], @@ -243,7 +241,7 @@ class HipchatIntegrationType(Integration ) -@task(ignore_result=True) +@async_task(ignore_result=True, base=RequestContextTask) def post_text_to_hipchat(settings, text): log.debug('sending %s to hipchat %s' % (text, settings['server_url'])) resp = requests.post(settings['server_url'], json={ diff --git a/rhodecode/integrations/types/slack.py b/rhodecode/integrations/types/slack.py --- a/rhodecode/integrations/types/slack.py +++ b/rhodecode/integrations/types/slack.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -27,13 +27,13 @@ import logging import deform import requests import colander -from celery.task import task from mako.template import Template +from collections import OrderedDict from rhodecode import events from rhodecode.translation import _ from rhodecode.lib import helpers as h -from rhodecode.lib.celerylib import run_task +from rhodecode.lib.celerylib import run_task, async_task, RequestContextTask from rhodecode.lib.colander_utils import strip_whitespace from rhodecode.integrations.types.base import IntegrationTypeBase @@ -247,7 +247,7 @@ class SlackIntegrationType(IntegrationTy branch_data = {branch['name']: branch for branch in data['push']['branches']} - branches_commits = {} + branches_commits = OrderedDict() for commit in data['push']['commits']: if commit['branch'] not in branches_commits: branch_commits = {'branch': branch_data[commit['branch']], @@ -265,7 +265,7 @@ class SlackIntegrationType(IntegrationTy %for branch, branch_commits in branches_commits.items(): ${len(branch_commits['commits'])} ${'commit' if len(branch_commits['commits']) == 1 else 'commits'} on branch: <${branch_commits['branch']['url']}|${branch_commits['branch']['name']}> %for commit in branch_commits['commits']: - `<${commit['url']}|${commit['short_id']}>` - ${commit['message_html_title']|html_to_slack_links} + `<${commit['url']}|${commit['short_id']}>` - ${commit['message_html']|html_to_slack_links} %endfor %endfor ''')) @@ -296,7 +296,7 @@ def html_to_slack_links(message): r'<\1|\2>', message) -@task(ignore_result=True) +@async_task(ignore_result=True, base=RequestContextTask) def post_text_to_slack(settings, title, text, fields=None, overrides=None): log.debug('sending %s (%s) to slack %s' % ( title, text, settings['service'])) diff --git a/rhodecode/integrations/types/webhook.py b/rhodecode/integrations/types/webhook.py --- a/rhodecode/integrations/types/webhook.py +++ b/rhodecode/integrations/types/webhook.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -28,16 +28,17 @@ import logging import requests import requests.adapters import colander -from celery.task import task from requests.packages.urllib3.util.retry import Retry import rhodecode from rhodecode import events from rhodecode.translation import _ from rhodecode.integrations.types.base import IntegrationTypeBase +from rhodecode.lib.celerylib import run_task, async_task, RequestContextTask log = logging.getLogger(__name__) + # updating this required to update the `common_vars` passed in url calling func WEBHOOK_URL_VARS = [ 'repo_name', @@ -109,6 +110,11 @@ class WebhookHandler(object): branches_commits = OrderedDict() for commit in data['push']['commits']: + if commit.get('git_ref_change'): + # special case for GIT that allows creating tags, + # deleting branches without associated commit + continue + if commit['branch'] not in branches_commits: branch_commits = {'branch': branch_data[commit['branch']], 'commits': []} @@ -312,11 +318,47 @@ class WebhookIntegrationType(Integration url_calls = handler(event, data) log.debug('webhook: calling following urls: %s', [x[0] for x in url_calls]) - post_to_webhook(url_calls, self.settings) + + run_task(post_to_webhook, url_calls, self.settings) -@task(ignore_result=True) +@async_task(ignore_result=True, base=RequestContextTask) def post_to_webhook(url_calls, settings): + """ + Example data:: + + {'actor': {'user_id': 2, 'username': u'admin'}, + 'actor_ip': u'192.168.157.1', + 'name': 'repo-push', + 'push': {'branches': [{'name': u'default', + 'url': 'http://rc.local:8080/hg-repo/changelog?branch=default'}], + 'commits': [{'author': u'Marcin Kuzminski ', + 'branch': u'default', + 'date': datetime.datetime(2017, 11, 30, 12, 59, 48), + 'issues': [], + 'mentions': [], + 'message': u'commit Thu 30 Nov 2017 13:59:48 CET', + 'message_html': u'commit Thu 30 Nov 2017 13:59:48 CET', + 'message_html_title': u'commit Thu 30 Nov 2017 13:59:48 CET', + 'parents': [{'raw_id': '431b772a5353dad9974b810dd3707d79e3a7f6e0'}], + 'permalink_url': u'http://rc.local:8080/_7/changeset/a815cc738b9651eb5ffbcfb1ce6ccd7c701a5ddf', + 'raw_id': 'a815cc738b9651eb5ffbcfb1ce6ccd7c701a5ddf', + 'refs': {'bookmarks': [], 'branches': [u'default'], 'tags': [u'tip']}, + 'reviewers': [], + 'revision': 9L, + 'short_id': 'a815cc738b96', + 'url': u'http://rc.local:8080/hg-repo/changeset/a815cc738b9651eb5ffbcfb1ce6ccd7c701a5ddf'}], + 'issues': {}}, + 'repo': {'extra_fields': '', + 'permalink_url': u'http://rc.local:8080/_7', + 'repo_id': 7, + 'repo_name': u'hg-repo', + 'repo_type': u'hg', + 'url': u'http://rc.local:8080/hg-repo'}, + 'server_url': u'http://rc.local:8080', + 'utc_timestamp': datetime.datetime(2017, 11, 30, 13, 0, 1, 569276) + + """ max_retries = 3 retries = Retry( total=max_retries, @@ -341,6 +383,8 @@ def post_to_webhook(url_calls, settings) log.debug('calling Webhook with method: %s, and auth:%s', call_method, auth) + if settings.get('log_data'): + log.debug('calling webhook with data: %s', data) resp = call_method(url, json={ 'token': token, 'event': data diff --git a/rhodecode/integrations/views.py b/rhodecode/integrations/views.py --- a/rhodecode/integrations/views.py +++ b/rhodecode/integrations/views.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2012-2017 RhodeCode GmbH +# Copyright (C) 2012-2018 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 @@ -32,7 +32,7 @@ from rhodecode.lib.auth import ( LoginRequired, CSRFRequired, HasPermissionAnyDecorator, HasRepoPermissionAnyDecorator, HasRepoGroupPermissionAnyDecorator) from rhodecode.lib.utils2 import safe_int -from rhodecode.lib.helpers import Page +from rhodecode.lib import helpers as h from rhodecode.model.db import Repository, RepoGroup, Session, Integration from rhodecode.model.scm import ScmModel from rhodecode.model.integration import IntegrationModel @@ -110,7 +110,7 @@ class IntegrationSettingsViewBase(BaseAp return False - def _get_local_tmpl_context(self, include_app_defaults=False): + def _get_local_tmpl_context(self, include_app_defaults=True): _ = self.request.translate c = super(IntegrationSettingsViewBase, self)._get_local_tmpl_context( include_app_defaults=include_app_defaults) @@ -169,10 +169,10 @@ class IntegrationSettingsViewBase(BaseAp _ = self.request.translate Session().delete(integration) Session().commit() - self.request.session.flash( + h.flash( _('Integration {integration_name} deleted successfully.').format( integration_name=integration.name), - queue='success') + category='success') if self.repo: redirect_to = self.request.route_path( @@ -208,6 +208,7 @@ class IntegrationSettingsViewBase(BaseAp integrations.append((IntType, integration)) sort_arg = self.request.GET.get('sort', 'name:asc') + sort_dir = 'asc' if ':' in sort_arg: sort_field, sort_dir = sort_arg.split(':') else: @@ -223,7 +224,7 @@ class IntegrationSettingsViewBase(BaseAp self.request.path, self.request.GET) page = safe_int(self.request.GET.get('page', 1), 1) - integrations = Page( + integrations = h.Page( integrations, page=page, items_per_page=10, url=page_url) c.rev_sort_dir = sort_dir != 'desc' and 'desc' or 'asc' @@ -297,10 +298,10 @@ class IntegrationSettingsViewBase(BaseAp try: valid_data = form.validate_pstruct(pstruct) except deform.ValidationFailure as e: - self.request.session.flash( + h.flash( _('Errors exist when saving integration settings. ' 'Please check the form inputs.'), - queue='error') + category='error') return self._settings_get(form=e) if not self.integration: @@ -322,10 +323,10 @@ class IntegrationSettingsViewBase(BaseAp self.integration.settings = valid_data['settings'] Session().commit() # Display success message and redirect. - self.request.session.flash( + h.flash( _('Integration {integration_name} updated successfully.').format( integration_name=self.IntegrationType.display_name), - queue='success') + category='success') # if integration scope changes, we must redirect to the right place # keeping in mind if the original view was for /repo/ or /_admin/ @@ -366,7 +367,7 @@ class GlobalIntegrationsView(Integration c.repo = self.repo c.repo_group = self.repo_group c.navlist = navigation_list(self.request) - self._register_global_c(c) + return c @LoginRequired() @@ -403,7 +404,6 @@ class RepoIntegrationsView(IntegrationSe c.repo_name = self.db_repo.repo_name c.repository_pull_requests = ScmModel().get_pull_requests(self.repo) - self._register_global_c(c) return c @LoginRequired() @@ -434,7 +434,7 @@ class RepoGroupIntegrationsView(Integrat c.repo = self.repo c.repo_group = self.repo_group c.navlist = navigation_list(self.request) - self._register_global_c(c) + return c @LoginRequired() diff --git a/rhodecode/lib/__init__.py b/rhodecode/lib/__init__.py --- a/rhodecode/lib/__init__.py +++ b/rhodecode/lib/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 diff --git a/rhodecode/lib/action_parser.py b/rhodecode/lib/action_parser.py --- a/rhodecode/lib/action_parser.py +++ b/rhodecode/lib/action_parser.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -20,7 +20,6 @@ import logging -from pylons.i18n.translation import _ from webhelpers.html.builder import literal from webhelpers.html.tags import link_to @@ -32,7 +31,7 @@ from rhodecode.lib.vcs.exceptions import log = logging.getLogger(__name__) -def action_parser(user_log, feed=False, parse_cs=False): +def action_parser(request, user_log, feed=False, parse_cs=False): """ This helper will action_map the specified string action into translated fancy names with icons and links @@ -42,11 +41,11 @@ def action_parser(user_log, feed=False, :param parse_cs: parse Changesets into VCS instances """ if user_log.version == 'v2': - ap = AuditLogParser(user_log) + ap = AuditLogParser(request, user_log) return ap.callbacks() else: # old style - ap = ActionParser(user_log, feed=False, parse_commits=False) + ap = ActionParser(request, user_log, feed=False, parse_commits=False) return ap.callbacks() @@ -55,10 +54,11 @@ class ActionParser(object): commits_limit = 3 # display this amount always commits_top_limit = 50 # show up to this amount of commits hidden - def __init__(self, user_log, feed=False, parse_commits=False): + def __init__(self, request, user_log, feed=False, parse_commits=False): self.user_log = user_log self.feed = feed self.parse_commits = parse_commits + self.request = request self.action = user_log.action self.action_params = ' ' @@ -86,7 +86,7 @@ class ActionParser(object): @property def action_map(self): - + _ = self.request.translate # action : translated str, callback(extractor), icon action_map = { 'user_deleted_repo': ( @@ -166,6 +166,7 @@ class ActionParser(object): def get_fork_name(self): from rhodecode.lib import helpers as h + _ = self.request.translate repo_name = self.action_params _url = h.route_path('repo_summary', repo_name=repo_name) return _('fork name %s') % link_to(self.action_params, _url) @@ -180,6 +181,7 @@ class ActionParser(object): def get_pull_request(self): from rhodecode.lib import helpers as h + _ = self.request.translate pull_request_id = self.action_params if self.is_deleted(): repo_name = self.user_log.repository_name @@ -201,6 +203,7 @@ class ActionParser(object): def get_cs_links(self): from rhodecode.lib import helpers as h + _ = self.request.translate if self.is_deleted(): return self.action_params @@ -277,7 +280,9 @@ class ActionParser(object): def lnk(self, commit_or_id, repo_name): from rhodecode.lib.helpers import tooltip from rhodecode.lib import helpers as h - + _ = self.request.translate + title = '' + lazy_cs = True if isinstance(commit_or_id, (BaseCommit, AttributeDict)): lazy_cs = True if (getattr(commit_or_id, 'op', None) and @@ -312,8 +317,9 @@ class ActionParser(object): class AuditLogParser(object): - def __init__(self, audit_log_entry): + def __init__(self, request, audit_log_entry): self.audit_log_entry = audit_log_entry + self.request = request def get_icon(self, action): return 'icon-rhodecode' diff --git a/rhodecode/lib/app_globals.py b/rhodecode/lib/app_globals.py deleted file mode 100644 --- a/rhodecode/lib/app_globals.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (C) 2010-2017 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 . -# -# 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/ - -""" -The application's Globals object -""" - -from beaker.cache import CacheManager -from beaker.util import parse_cache_config_options - - -class Globals(object): - """ - Globals acts as a container for objects available throughout the - life of the application - """ - - def __init__(self, config): - """One instance of Globals is created during application - initialization and is available during requests via the - 'app_globals' variable - - """ - self.cache = CacheManager(**parse_cache_config_options(config)) - self.available_permissions = None # propagated after init_model diff --git a/rhodecode/lib/audit_logger.py b/rhodecode/lib/audit_logger.py --- a/rhodecode/lib/audit_logger.py +++ b/rhodecode/lib/audit_logger.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2017-2017 RhodeCode GmbH +# Copyright (C) 2017-2018 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 @@ -33,6 +33,7 @@ ACTIONS_V1 = { 'user.login.success': {'user_agent': ''}, 'user.login.failure': {'user_agent': ''}, 'user.logout': {'user_agent': ''}, + 'user.register': {}, 'user.password.reset_request': {}, 'user.push': {'user_agent': '', 'commit_ids': []}, 'user.pull': {'user_agent': ''}, diff --git a/rhodecode/lib/auth.py b/rhodecode/lib/auth.py --- a/rhodecode/lib/auth.py +++ b/rhodecode/lib/auth.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -34,11 +34,8 @@ import traceback from functools import wraps import ipaddress -from beaker.cache import cache_region + from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound -from pylons.i18n.translation import _ -# NOTE(marcink): this has to be removed only after pyramid migration, -# replace with _ = request.translate from sqlalchemy.orm.exc import ObjectDeletedError from sqlalchemy.orm import joinedload from zope.cachedescriptors.property import Lazy as LazyProperty @@ -921,7 +918,6 @@ class AuthUser(object): self._api_key = api_key self.api_key = None - self.feed_token = '' self.username = username self.ip_addr = ip_addr self.name = '' @@ -1222,6 +1218,10 @@ class AuthUser(object): def personal_repo_group(self): return RepoGroup.get_user_personal_repo_group(self.user_id) + @LazyProperty + def feed_token(self): + return self.get_instance().feed_token + @classmethod def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default): allowed_ips = AuthUser.get_allowed_ips( @@ -1325,7 +1325,7 @@ def get_csrf_token(session, force_new=Fa Return the current authentication token, creating one if one doesn't already exist and the save_if_missing flag is present. - :param session: pass in the pylons session, else we use the global ones + :param session: pass in the pyramid session, else we use the global ones :param force_new: force to re-generate the token and store it in session :param save_if_missing: save the newly generated token if it's missing in session @@ -1344,11 +1344,6 @@ def get_csrf_token(session, force_new=Fa def get_request(perm_class_instance): from pyramid.threadlocal import get_current_request pyramid_request = get_current_request() - if not pyramid_request: - # return global request of pylons in case pyramid isn't available - # NOTE(marcink): this should be removed after migration to pyramid - from pylons import request - return request return pyramid_request @@ -1436,6 +1431,7 @@ class LoginRequired(object): cls = fargs[0] user = cls._rhodecode_user request = self._get_request() + _ = request.translate loc = "%s:%s" % (cls.__class__.__name__, func.__name__) log.debug('Starting login restriction checks for user: %s' % (user,)) @@ -1525,7 +1521,7 @@ class NotAnonymous(object): cls = fargs[0] self.user = cls._rhodecode_user request = self._get_request() - + _ = request.translate log.debug('Checking if user is not anonymous @%s' % cls) anonymous = self.user.username == User.DEFAULT_USER @@ -1560,6 +1556,8 @@ class PermsDecorator(object): import rhodecode.lib.helpers as h cls = fargs[0] _user = cls._rhodecode_user + request = self._get_request() + _ = request.translate log.debug('checking %s permissions %s for %s %s', self.__class__.__name__, self.required_perms, cls, _user) diff --git a/rhodecode/lib/base.py b/rhodecode/lib/base.py --- a/rhodecode/lib/base.py +++ b/rhodecode/lib/base.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2010-2017 RhodeCode GmbH +# Copyright (C) 2010-2018 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 @@ -29,7 +29,6 @@ import socket import markupsafe import ipaddress -import pyramid.threadlocal from paste.auth.basic import AuthBasicAuthenticator from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden, get_exception @@ -41,53 +40,16 @@ from rhodecode.lib import auth, utils2 from rhodecode.lib import helpers as h from rhodecode.lib.auth import AuthUser, CookieStoreWrapper from rhodecode.lib.exceptions import UserCreationError -from rhodecode.lib.utils import ( - get_repo_slug, set_rhodecode_config, password_changed, - get_enabled_hook_classes) +from rhodecode.lib.utils import (password_changed, get_enabled_hook_classes) from rhodecode.lib.utils2 import ( str2bool, safe_unicode, AttributeDict, safe_int, md5, aslist, safe_str) -from rhodecode.model import meta from rhodecode.model.db import Repository, User, ChangesetComment from rhodecode.model.notification import NotificationModel -from rhodecode.model.scm import ScmModel from rhodecode.model.settings import VcsSettingsModel, SettingsModel -# NOTE(marcink): remove after base controller is no longer required -from pylons.controllers import WSGIController -from pylons.i18n import translation - log = logging.getLogger(__name__) -# hack to make the migration to pyramid easier -def render(template_name, extra_vars=None, cache_key=None, - cache_type=None, cache_expire=None): - """Render a template with Mako - - Accepts the cache options ``cache_key``, ``cache_type``, and - ``cache_expire``. - - """ - from pylons.templating import literal - from pylons.templating import cached_template, pylons_globals - - # Create a render callable for the cache function - def render_template(): - # Pull in extra vars if needed - globs = extra_vars or {} - - # Second, get the globals - globs.update(pylons_globals()) - - globs['_ungettext'] = globs['ungettext'] - # Grab a template reference - template = globs['app_globals'].mako_lookup.get_template(template_name) - - return literal(template.render_unicode(**globs)) - - return cached_template(template_name, render_template, cache_key=cache_key, - cache_type=cache_type, cache_expire=cache_expire) - def _filter_proxy(ip): """ Passed in IP addresses in HEADERS can be in a special format of multiple @@ -207,19 +169,20 @@ def vcs_operation_context( make_lock = None locked_by = [None, None, None] is_anonymous = username == User.DEFAULT_USER + user = User.get_by_username(username) if not is_anonymous and check_locking: log.debug('Checking locking on repository "%s"', repo_name) - user = User.get_by_username(username) repo = Repository.get_by_repo_name(repo_name) make_lock, __, locked_by = repo.get_locking_state( action, user.user_id) - + user_id = user.user_id settings_model = VcsSettingsModel(repo=repo_name) ui_settings = settings_model.get_ui_settings() extras = { 'ip': get_ip_addr(environ), 'username': username, + 'user_id': user_id, 'action': action, 'repository': repo_name, 'scm': scm, @@ -310,14 +273,10 @@ def get_current_lang(request): def attach_context_attributes(context, request, user_id): """ - Attach variables into template context called `c`, please note that - request could be pylons or pyramid request in here. + Attach variables into template context called `c`. """ - # NOTE(marcink): remove check after pyramid migration - if hasattr(request, 'registry'): - config = request.registry.settings - else: - from pylons import config + config = request.registry.settings + rc_config = SettingsModel().get_all_settings(cache=True) @@ -367,10 +326,14 @@ def attach_context_attributes(context, r if request.GET.get('default_encoding'): context.default_encodings.insert(0, request.GET.get('default_encoding')) context.clone_uri_tmpl = rc_config.get('rhodecode_clone_uri_tmpl') + context.clone_uri_ssh_tmpl = rc_config.get('rhodecode_clone_uri_ssh_tmpl') # INI stored context.labs_active = str2bool( config.get('labs_settings_active', 'false')) + context.ssh_enabled = str2bool( + config.get('ssh.generate_authorized_keyfile', 'false')) + context.visual.allow_repo_location_change = str2bool( config.get('allow_repo_location_change', True)) context.visual.allow_custom_hooks_settings = str2bool( @@ -418,10 +381,6 @@ def attach_context_attributes(context, r } # END CONFIG VARS - # TODO: This dosn't work when called from pylons compatibility tween. - # Fix this and remove it from base controller. - # context.repo_name = get_repo_slug(request) # can be empty - diffmode = 'sideside' if request.GET.get('diffmode'): if request.GET['diffmode'] == 'unified': @@ -439,20 +398,15 @@ def attach_context_attributes(context, r context.backends.sort() context.unread_notifications = NotificationModel().get_unread_cnt_for_user(user_id) - # NOTE(marcink): when migrated to pyramid we don't need to set this anymore, - # given request will ALWAYS be pyramid one - pyramid_request = pyramid.threadlocal.get_current_request() - context.pyramid_request = pyramid_request - # web case - if hasattr(pyramid_request, 'user'): - context.auth_user = pyramid_request.user - context.rhodecode_user = pyramid_request.user + if hasattr(request, 'user'): + context.auth_user = request.user + context.rhodecode_user = request.user # api case - if hasattr(pyramid_request, 'rpc_user'): - context.auth_user = pyramid_request.rpc_user - context.rhodecode_user = pyramid_request.rpc_user + if hasattr(request, 'rpc_user'): + context.auth_user = request.rpc_user + context.rhodecode_user = request.rpc_user # attach the whole call context to the request request.call_context = context @@ -486,6 +440,8 @@ def get_auth_user(request): # AuthUser auth_user = AuthUser(ip_addr=ip_addr) + # in case someone changes a password for user it triggers session + # flush and forces a re-login if password_changed(auth_user, session): session.invalidate() cookie_store = CookieStoreWrapper(session.get('rhodecode_user')) @@ -500,82 +456,6 @@ def get_auth_user(request): return auth_user -class BaseController(WSGIController): - - def __before__(self): - """ - __before__ is called before controller methods and after __call__ - """ - # on each call propagate settings calls into global settings. - from pylons import config - from pylons import tmpl_context as c, request, url - set_rhodecode_config(config) - attach_context_attributes(c, request, self._rhodecode_user.user_id) - - # TODO: Remove this when fixed in attach_context_attributes() - c.repo_name = get_repo_slug(request) # can be empty - - self.cut_off_limit_diff = safe_int(config.get('cut_off_limit_diff')) - self.cut_off_limit_file = safe_int(config.get('cut_off_limit_file')) - self.sa = meta.Session - self.scm_model = ScmModel(self.sa) - - # set user language - user_lang = getattr(c.pyramid_request, '_LOCALE_', None) - if user_lang: - translation.set_lang(user_lang) - log.debug('set language to %s for user %s', - user_lang, self._rhodecode_user) - - def _dispatch_redirect(self, with_url, environ, start_response): - from webob.exc import HTTPFound - resp = HTTPFound(with_url) - environ['SCRIPT_NAME'] = '' # handle prefix middleware - environ['PATH_INFO'] = with_url - return resp(environ, start_response) - - def __call__(self, environ, start_response): - """Invoke the Controller""" - # WSGIController.__call__ dispatches to the Controller method - # the request is routed to. This routing information is - # available in environ['pylons.routes_dict'] - from rhodecode.lib import helpers as h - from pylons import tmpl_context as c, request, url - - # Provide the Pylons context to Pyramid's debugtoolbar if it asks - if environ.get('debugtoolbar.wants_pylons_context', False): - environ['debugtoolbar.pylons_context'] = c._current_obj() - - _route_name = '.'.join([environ['pylons.routes_dict']['controller'], - environ['pylons.routes_dict']['action']]) - - self.rc_config = SettingsModel().get_all_settings(cache=True) - self.ip_addr = get_ip_addr(environ) - - # The rhodecode auth user is looked up and passed through the - # environ by the pylons compatibility tween in pyramid. - # So we can just grab it from there. - auth_user = environ['rc_auth_user'] - - # set globals for auth user - request.user = auth_user - self._rhodecode_user = auth_user - - log.info('IP: %s User: %s accessed %s [%s]' % ( - self.ip_addr, auth_user, safe_unicode(get_access_path(environ)), - _route_name) - ) - - user_obj = auth_user.get_instance() - if user_obj and user_obj.user_data.get('force_password_change'): - h.flash('You are required to change your password', 'warning', - ignore_duplicate=True) - return self._dispatch_redirect( - url('my_account_password'), environ, start_response) - - return WSGIController.__call__(self, environ, start_response) - - def h_filter(s): """ Custom filter for Mako templates. Mako by standard uses `markupsafe.escape` @@ -593,8 +473,13 @@ def add_events_routes(config): outside of pyramid context, we need to bootstrap request with some routing registered """ + + from rhodecode.apps._base import ADMIN_PREFIX + config.add_route(name='home', pattern='/') + config.add_route(name='login', pattern=ADMIN_PREFIX + '/login') + config.add_route(name='logout', pattern=ADMIN_PREFIX + '/logout') config.add_route(name='repo_summary', pattern='/{repo_name}') config.add_route(name='repo_summary_explicit', pattern='/{repo_name}/summary') config.add_route(name='repo_group_home', pattern='/{repo_group_name}') @@ -603,13 +488,29 @@ def add_events_routes(config): pattern='/{repo_name}/pull-request/{pull_request_id}') config.add_route(name='pull_requests_global', pattern='/pull-request/{pull_request_id}') - config.add_route(name='repo_commit', pattern='/{repo_name}/changeset/{commit_id}') + config.add_route(name='repo_files', pattern='/{repo_name}/files/{commit_id}/{f_path}') +def bootstrap_config(request): + import pyramid.testing + registry = pyramid.testing.Registry('RcTestRegistry') + + config = pyramid.testing.setUp(registry=registry, request=request) + + # allow pyramid lookup in testing + config.include('pyramid_mako') + config.include('pyramid_beaker') + config.include('rhodecode.lib.caches') + + add_events_routes(config) + + return config + + def bootstrap_request(**kwargs): import pyramid.testing @@ -621,6 +522,19 @@ def bootstrap_request(**kwargs): def translate(self, msg): return msg + def plularize(self, singular, plural, n): + return singular + + def get_partial_renderer(self, tmpl_name): + + from rhodecode.lib.partial_renderer import get_partial_renderer + return get_partial_renderer(request=self, tmpl_name=tmpl_name) + + _call_context = {} + @property + def call_context(self): + return self._call_context + class TestDummySession(pyramid.testing.DummySession): def save(*arg, **kw): pass @@ -628,7 +542,5 @@ def bootstrap_request(**kwargs): request = TestRequest(**kwargs) request.session = TestDummySession() - config = pyramid.testing.setUp(request=request) - add_events_routes(config) return request diff --git a/rhodecode/lib/bleach_whitelist.py b/rhodecode/lib/bleach_whitelist.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/bleach_whitelist.py @@ -0,0 +1,403 @@ +all_tags = [ + "a", "abbr", "acronym", "address", "applet", "area", "article", "aside", "audio", + "b", "base", "basefont", "bdi", "bdo", "bgsound", "big", "blink", "blockquote", "body", "br", "button", + "canvas", "caption", "center", "cite", "code", "col", "colgroup", "command", "content", + "data", "datalist", "dd", "del", "detals", "dfn", "dialog", "dir", "div", "dl", "dt", + "element", "em", "embed", + "fieldset", "figcaption", "figure", "font", "footer", "form", "frame", "frameset", + "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", + "i", "iframe", "image", "img", "input", "ins", "isindex", + "kbd", "keygen", + "label", "legend", "li", "link", "listing", + "main", "map", "mark", "marquee", "menu", "menuitem", "meta", "meter", "multicol", + "nav", "nobr", "noembed", "noframes", "noscript", + "object", "ol", "optgroup", "option", "output", + "p", "param", "picture", "plaintext", "pre", "progress", + "q", + "rp", "rt", "ruby", + "s", "samp", "script", "section", "select", "shadow", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", + "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "tt", + "u", "ul", + "var", "video", + "wbr", + "xmp", +] + +# List tags that, if included in a page, could break markup or open XSS. +generally_xss_unsafe = [ + "applet", "audio", + "bgsound", "body", + "canvas", + "embed", + "frame", "frameset", + "head", "html", + "iframe", + "link", + "meta", + "object", + "param", + "source", "script", + "ruby", "rt", + "title", "track", + "video", + "xmp" +] + +# Tags that, if included on the page, will probably not break markup or open +# XSS. Note that these must be combined with attribute whitelisting, or things +# like and