Show More
The requested changes are too big and content was truncated. Show full diff
@@ -0,0 +1,50 b'' | |||||
|
1 | .. _gunicorn-ssl-support: | |||
|
2 | ||||
|
3 | ||||
|
4 | Gunicorn SSL support | |||
|
5 | -------------------- | |||
|
6 | ||||
|
7 | ||||
|
8 | :term:`Gunicorn` wsgi server allows users to use HTTPS connection directly | |||
|
9 | without a need to use HTTP server like Nginx or Apache. To Configure | |||
|
10 | SSL support directly with :term:`Gunicorn` you need to simply add the key | |||
|
11 | and certificate paths to your configuration file. | |||
|
12 | ||||
|
13 | 1. Open the :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. | |||
|
14 | 2. In the ``[server:main]`` section, add two new variables | |||
|
15 | called `certfile` and `keyfile`. | |||
|
16 | ||||
|
17 | .. code-block:: ini | |||
|
18 | ||||
|
19 | [server:main] | |||
|
20 | host = 127.0.0.1 | |||
|
21 | port = 10002 | |||
|
22 | use = egg:gunicorn#main | |||
|
23 | workers = 1 | |||
|
24 | threads = 1 | |||
|
25 | proc_name = RhodeCodeEnterprise | |||
|
26 | worker_class = sync | |||
|
27 | max_requests = 1000 | |||
|
28 | timeout = 3600 | |||
|
29 | # adding ssl support | |||
|
30 | certfile = /home/ssl/my_server_com.pem | |||
|
31 | keyfile = /home/ssl/my_server_com.key | |||
|
32 | ||||
|
33 | 4. Save your changes. | |||
|
34 | 5. Restart your |RCE| instance, using the following command: | |||
|
35 | ||||
|
36 | .. code-block:: bash | |||
|
37 | ||||
|
38 | $ rccontrol restart enterprise-1 | |||
|
39 | ||||
|
40 | After this is enabled you can *only* access your instances via https:// | |||
|
41 | protocol. Check out more docs here `Gunicorn SSL Docs`_ | |||
|
42 | ||||
|
43 | .. note:: | |||
|
44 | ||||
|
45 | This change only can be applied to |RCE|. VCSServer doesn't support SSL | |||
|
46 | and should be only used with http protocol. Because only |RCE| is available | |||
|
47 | externally all communication will still be over SSL even without VCSServer | |||
|
48 | SSL enabled. | |||
|
49 | ||||
|
50 | .. _Gunicorn SSL Docs: http://docs.gunicorn.org/en/stable/settings.html#ssl |
@@ -0,0 +1,178 b'' | |||||
|
1 | |RCE| 4.10.0 |RNS| | |||
|
2 | ------------------ | |||
|
3 | ||||
|
4 | Release Date | |||
|
5 | ^^^^^^^^^^^^ | |||
|
6 | ||||
|
7 | - 2017-11-02 | |||
|
8 | ||||
|
9 | ||||
|
10 | New Features | |||
|
11 | ^^^^^^^^^^^^ | |||
|
12 | ||||
|
13 | - SSH (Beta): added support for authentication via SSH keys. It's possible | |||
|
14 | to use SSH key based authentication instead of HTTP. Users are allowed to | |||
|
15 | store multiple keys and use them to push/pull code via SSH. | |||
|
16 | - Pull requests: store and show a merge strategy. Pull request strategy will | |||
|
17 | be also now shown in the UI. | |||
|
18 | Close/delete branch are shown if that option is selected. | |||
|
19 | - Pull requests: Add option to close a branch before merging for Mercurial. | |||
|
20 | - Processes page. RhodeCode will show a list of all current workers with | |||
|
21 | CPU and Memory usage. | |||
|
22 | It's also possible to restart each worker from the web interface. | |||
|
23 | - Auth tokens: allow specifying a custom expiration date from UI. | |||
|
24 | - Integrations: webhook, allow to set a custom header. | |||
|
25 | - Integrations: webhook, add possibility to specify username and password. | |||
|
26 | - UI: added copy-to-clipboard for commits, file paths, gist/clone urls. | |||
|
27 | - UI: improve support for meta-tags in repository description: | |||
|
28 | Tags are extracted to the beginning of the description during rendering. | |||
|
29 | Show helpers in proper places in groups/repos/forks with all available tags. | |||
|
30 | Add a new deprecated tag. | |||
|
31 | - UI: commits page, hide evolve commits. | |||
|
32 | Now optionally it's possible to show them via a new link on changelog page. | |||
|
33 | - Audit logs: allow showing individual entries for audit log. | |||
|
34 | - Audit logs: expose repo related audit logs in repository view. | |||
|
35 | - User sessions: get ability to count memcached sessions. | |||
|
36 | - Core: added support for REDIS based user sessions and cache backend. | |||
|
37 | - Core: added support for Golang go-import functionality. | |||
|
38 | - SVN: allow specifying alternative template file for mod_dav config. | |||
|
39 | - Markup: make relative links pin to raw files for images/files as links. | |||
|
40 | Allows building relative MD/RST links that go to rendered content | |||
|
41 | - Auth: allow binding the whitelist views to specific auth tokens. This allows | |||
|
42 | to access only specific pages via given auth token. E.g possible to expose | |||
|
43 | raw diff/raw file content only for specific single token. | |||
|
44 | The new format is `viewName@TOKEN` | |||
|
45 | - Channelstream: push events with comments on single commits. Users will get | |||
|
46 | live notification for events on single commits too. | |||
|
47 | ||||
|
48 | ||||
|
49 | General | |||
|
50 | ^^^^^^^ | |||
|
51 | ||||
|
52 | - License: add helper to show alternative application method for license via | |||
|
53 | ishell. | |||
|
54 | - http: set REMOTE_USER and REMOTE_HOST http variables in order for more | |||
|
55 | Mercurial extensions compatibility. | |||
|
56 | - User/User groups: show if users or user groups are a part of review rules. | |||
|
57 | - Permissions: new improved visual permissions summary. Show exactly how | |||
|
58 | permissions were inherited, and which rule overwrote the other. | |||
|
59 | - Permissions: added new JSON endpoint to extract permissions as JSON data | |||
|
60 | for 3rd party processing. This allows access for reporting tools without | |||
|
61 | giving any ADMIN API access to fetch permissions. | |||
|
62 | - Pyramid: ported all controllers to Pyramid, with python3 compatible code. | |||
|
63 | - Gunicorn: allow custom logger to be set for a consistent formatting of | |||
|
64 | Gunicorn logs with RhodeCode logs. | |||
|
65 | - Search: per-repo search shouldn't require admin permissions. Read is enough | |||
|
66 | because we access the repo data only. | |||
|
67 | - Git: updated to 2.13.5 release | |||
|
68 | - Mercurial: updated to 4.2.3 release. | |||
|
69 | - Mercurial Evolve: updated to 6.6.0 release. | |||
|
70 | - Dependencies: bumped pysqlite to Mako to 1.0.7 | |||
|
71 | - Dependencies: bumped pysqlite to 2.8.3 | |||
|
72 | - Dependencies: bumped psycopg2 to 2.7.1 | |||
|
73 | - Dependencies: bumped docutils to 0.13.1 | |||
|
74 | - Dependencies: bumped simplejson to 3.11.1 | |||
|
75 | - Dependencies: bumped alembic to 0.9.2 | |||
|
76 | - Dependencies: bumped Beaker to 1.9.0 | |||
|
77 | - Dependencies: bumped Markdown to 2.6.8 | |||
|
78 | - Dependencies: bumped dogpile.cache to 0.6.4 | |||
|
79 | - Dependencies: bumped colander to 1.3.3 | |||
|
80 | - Dependencies: bumped appenlight_client to 0.6.21 | |||
|
81 | - Dependencies: bumped cprofileV to 1.0.7 | |||
|
82 | - Dependencies: bumped ipdb to 0.10.3 | |||
|
83 | - Dependencies: bumped supervisor to 3.3.2 | |||
|
84 | - Dependencies: bumped subprocess32 to 3.2.7 | |||
|
85 | - Dependencies: bumped pathlib2 to 2.3.0. | |||
|
86 | - Dependencies: bumped gunicorn==19.7.1 | |||
|
87 | - Dependencies: bumped gevent to 1.2.2 together with greenlet to 0.4.12 | |||
|
88 | - Dependencies: bumped venusian to 1.1.0 | |||
|
89 | - Dependencies: bumped ptyprocess to 0.5.2 | |||
|
90 | - Dependencies: bumped testpath to 0.3.1 | |||
|
91 | - Dependencies: bumped Pyramid to 1.9.1 | |||
|
92 | - Dependencies: bumped supervisor to 3.3.3 | |||
|
93 | - Dependencies: bumped sqlalchemy to version 1.1.11 | |||
|
94 | ||||
|
95 | ||||
|
96 | Security | |||
|
97 | ^^^^^^^^ | |||
|
98 | ||||
|
99 | - Security: use no-referrer for outside link to stop leaking potential | |||
|
100 | parameters such as auth token stored inside GET flags. | |||
|
101 | - Auth tokens: always check permissions to scope tokens to prevent resource | |||
|
102 | discovery of private repos. | |||
|
103 | - Strip: fix XSS in repo strip view. | |||
|
104 | - Files: prevent XSS in fake errors message on filenodes. | |||
|
105 | - Files: remove right-to-left override character for display in files. | |||
|
106 | This allows faking the name a bit, we in this particular place want to | |||
|
107 | skip the override for enhanced security. | |||
|
108 | - Repo forks: security, check for access to fork_id parameter to prevent | |||
|
109 | resource discovery. | |||
|
110 | - Pull requests: security double check permissions on injected forms of | |||
|
111 | source and target repositories. Fixes resource discovery. | |||
|
112 | - Pull requests: security, prevent from injecting comments to other pull | |||
|
113 | requests for users don't have access to. | |||
|
114 | ||||
|
115 | ||||
|
116 | Performance | |||
|
117 | ^^^^^^^^^^^ | |||
|
118 | ||||
|
119 | - Goto-switcher: use special commit: prefix to explicitly search for commits. | |||
|
120 | previous solution could make the go-to switcher slow in case of larger search | |||
|
121 | index present. | |||
|
122 | - Goto-switcher: optimized performance and query capabilities. | |||
|
123 | - Diffs: use whole chunk diff to calculate if it's oversized or not. | |||
|
124 | This fixes an issue if a file is added that has very large number of small | |||
|
125 | lines. In this case the time to detect if the diff should be limited was | |||
|
126 | very long and CPU intensive. | |||
|
127 | - Markup: use cached version of http pattern for urlify_text. This | |||
|
128 | increases performance because we don't have to compile the pattern each time | |||
|
129 | we execute this commonly used function. | |||
|
130 | - Changelog: fix and optimize loading of chunks for file history. | |||
|
131 | - Vcs: reduce sql queries used during pull/push operations. | |||
|
132 | - Auth: use cache_ttl from a plugin to also cache calculated permissions. | |||
|
133 | This gives a 30% speed increase in operations like svn commit. | |||
|
134 | ||||
|
135 | ||||
|
136 | Fixes | |||
|
137 | ^^^^^ | |||
|
138 | ||||
|
139 | - Initial-gravatars: fix case of dot being present before @domain. | |||
|
140 | - Vcs: report 404 for shadow repos that are not existing anymore. | |||
|
141 | - RSS/Atom Feeds: generate entries with proper unique ids. | |||
|
142 | - DB: use LONGTEXT for mysql in user_logs. Fixes problem with mysql rejecting | |||
|
143 | insert because of too long json data. | |||
|
144 | - Pull request: add missing audit data for pull_request.close action. | |||
|
145 | - User groups: properly set add/delete members for usage in audit data. | |||
|
146 | - Repo, auth-tokens: UX, set VCS scope if repo scopped token is selected. | |||
|
147 | - Changelog: fix and optimize loading of chunks for file history. | |||
|
148 | - Error reporting: improve handling of exception that are non-standard. | |||
|
149 | Inject traceback information into unhandled exceptions. | |||
|
150 | - Users: add additional information why user with pending reviews | |||
|
151 | shouldn't be deleted. | |||
|
152 | - Auth ldap: improve messages when users failed to authenticate via LDAP. | |||
|
153 | - Sqlalchemy: enabled connection ping. | |||
|
154 | should fix potential issues with Mysql server has gone away issues. | |||
|
155 | - License page: fix usage of url() that could prevent from using convert license. | |||
|
156 | - Permissions: use same way of sorting of user_group permissions like user ones. | |||
|
157 | ||||
|
158 | ||||
|
159 | Upgrade notes | |||
|
160 | ^^^^^^^^^^^^^ | |||
|
161 | ||||
|
162 | - Searching for commits in goto-switcher must be now prefixed with | |||
|
163 | commit:<hash> | |||
|
164 | - Because of pyramid porting view names have changed, and we made a backward | |||
|
165 | compatibility mapping for most common ones only. | |||
|
166 | We recommend reviewing your whitelist view access list. | |||
|
167 | There's a new dedicated page with ALL views listed under admin > permissions | |||
|
168 | Please take a look in there to port any non-standard views for whitelist access. | |||
|
169 | ||||
|
170 | - SSH support is implemented via combination of internal, and installed hooks. | |||
|
171 | A file called `hgrc_rhodecode` is added to each repository that was used with | |||
|
172 | SSH access. This file is then imported inside main hgrc file, it contains | |||
|
173 | some Mercurial hooks for ACL checks. | |||
|
174 | This breaks full backward compatibility with releases prior to 4.10.0. | |||
|
175 | If you install 4.10+, enable SSH module and use SSH with a Mercurial repo, then | |||
|
176 | rollback used version to 4.9.1. In such case one additional actions is required. | |||
|
177 | Remove following line from `hgrc` file stored inside the repository: | |||
|
178 | `%include hgrc_rhodecode` |
@@ -0,0 +1,176 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2010-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import os | |||
|
22 | import pytest | |||
|
23 | ||||
|
24 | from rhodecode.apps._base import ADMIN_PREFIX | |||
|
25 | from rhodecode.lib import helpers as h | |||
|
26 | from rhodecode.model.db import Repository, UserRepoToPerm, User | |||
|
27 | from rhodecode.model.meta import Session | |||
|
28 | from rhodecode.model.repo_group import RepoGroupModel | |||
|
29 | from rhodecode.tests import ( | |||
|
30 | assert_session_flash, TEST_USER_REGULAR_LOGIN, TESTS_TMP_PATH, TestController) | |||
|
31 | from rhodecode.tests.fixture import Fixture | |||
|
32 | ||||
|
33 | fixture = Fixture() | |||
|
34 | ||||
|
35 | ||||
|
36 | def route_path(name, params=None, **kwargs): | |||
|
37 | import urllib | |||
|
38 | ||||
|
39 | base_url = { | |||
|
40 | 'repo_groups': ADMIN_PREFIX + '/repo_groups', | |||
|
41 | 'repo_group_new': ADMIN_PREFIX + '/repo_group/new', | |||
|
42 | 'repo_group_create': ADMIN_PREFIX + '/repo_group/create', | |||
|
43 | ||||
|
44 | }[name].format(**kwargs) | |||
|
45 | ||||
|
46 | if params: | |||
|
47 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |||
|
48 | return base_url | |||
|
49 | ||||
|
50 | ||||
|
51 | def _get_permission_for_user(user, repo): | |||
|
52 | perm = UserRepoToPerm.query()\ | |||
|
53 | .filter(UserRepoToPerm.repository == | |||
|
54 | Repository.get_by_repo_name(repo))\ | |||
|
55 | .filter(UserRepoToPerm.user == User.get_by_username(user))\ | |||
|
56 | .all() | |||
|
57 | return perm | |||
|
58 | ||||
|
59 | ||||
|
60 | @pytest.mark.usefixtures("app") | |||
|
61 | class TestAdminRepositoryGroups(object): | |||
|
62 | def test_show_repo_groups(self, autologin_user): | |||
|
63 | response = self.app.get(route_path('repo_groups')) | |||
|
64 | response.mustcontain('data: []') | |||
|
65 | ||||
|
66 | def test_show_repo_groups_after_creating_group(self, autologin_user): | |||
|
67 | fixture.create_repo_group('test_repo_group') | |||
|
68 | response = self.app.get(route_path('repo_groups')) | |||
|
69 | response.mustcontain('"name_raw": "test_repo_group"') | |||
|
70 | fixture.destroy_repo_group('test_repo_group') | |||
|
71 | ||||
|
72 | def test_new(self, autologin_user): | |||
|
73 | self.app.get(route_path('repo_group_new')) | |||
|
74 | ||||
|
75 | def test_new_with_parent_group(self, autologin_user, user_util): | |||
|
76 | gr = user_util.create_repo_group() | |||
|
77 | ||||
|
78 | self.app.get(route_path('repo_group_new'), | |||
|
79 | params=dict(parent_group=gr.group_name)) | |||
|
80 | ||||
|
81 | def test_new_by_regular_user_no_permission(self, autologin_regular_user): | |||
|
82 | self.app.get(route_path('repo_group_new'), status=403) | |||
|
83 | ||||
|
84 | @pytest.mark.parametrize('repo_group_name', [ | |||
|
85 | 'git_repo', | |||
|
86 | 'git_repo_ąć', | |||
|
87 | 'hg_repo', | |||
|
88 | '12345', | |||
|
89 | 'hg_repo_ąć', | |||
|
90 | ]) | |||
|
91 | def test_create(self, autologin_user, repo_group_name, csrf_token): | |||
|
92 | repo_group_name_unicode = repo_group_name.decode('utf8') | |||
|
93 | description = 'description for newly created repo group' | |||
|
94 | ||||
|
95 | response = self.app.post( | |||
|
96 | route_path('repo_group_create'), | |||
|
97 | fixture._get_group_create_params( | |||
|
98 | group_name=repo_group_name, | |||
|
99 | group_description=description, | |||
|
100 | csrf_token=csrf_token)) | |||
|
101 | ||||
|
102 | # run the check page that triggers the flash message | |||
|
103 | repo_gr_url = h.route_path( | |||
|
104 | 'repo_group_home', repo_group_name=repo_group_name) | |||
|
105 | ||||
|
106 | assert_session_flash( | |||
|
107 | response, | |||
|
108 | 'Created repository group <a href="%s">%s</a>' % ( | |||
|
109 | repo_gr_url, repo_group_name_unicode)) | |||
|
110 | ||||
|
111 | # # test if the repo group was created in the database | |||
|
112 | new_repo_group = RepoGroupModel()._get_repo_group( | |||
|
113 | repo_group_name_unicode) | |||
|
114 | assert new_repo_group is not None | |||
|
115 | ||||
|
116 | assert new_repo_group.group_name == repo_group_name_unicode | |||
|
117 | assert new_repo_group.group_description == description | |||
|
118 | ||||
|
119 | # test if the repository is visible in the list ? | |||
|
120 | response = self.app.get(repo_gr_url) | |||
|
121 | response.mustcontain(repo_group_name) | |||
|
122 | ||||
|
123 | # test if the repository group was created on filesystem | |||
|
124 | is_on_filesystem = os.path.isdir( | |||
|
125 | os.path.join(TESTS_TMP_PATH, repo_group_name)) | |||
|
126 | if not is_on_filesystem: | |||
|
127 | self.fail('no repo group %s in filesystem' % repo_group_name) | |||
|
128 | ||||
|
129 | RepoGroupModel().delete(repo_group_name_unicode) | |||
|
130 | Session().commit() | |||
|
131 | ||||
|
132 | @pytest.mark.parametrize('repo_group_name', [ | |||
|
133 | 'git_repo', | |||
|
134 | 'git_repo_ąć', | |||
|
135 | 'hg_repo', | |||
|
136 | '12345', | |||
|
137 | 'hg_repo_ąć', | |||
|
138 | ]) | |||
|
139 | def test_create_subgroup(self, autologin_user, user_util, repo_group_name, csrf_token): | |||
|
140 | parent_group = user_util.create_repo_group() | |||
|
141 | parent_group_name = parent_group.group_name | |||
|
142 | ||||
|
143 | expected_group_name = '{}/{}'.format( | |||
|
144 | parent_group_name, repo_group_name) | |||
|
145 | expected_group_name_unicode = expected_group_name.decode('utf8') | |||
|
146 | ||||
|
147 | try: | |||
|
148 | response = self.app.post( | |||
|
149 | route_path('repo_group_create'), | |||
|
150 | fixture._get_group_create_params( | |||
|
151 | group_name=repo_group_name, | |||
|
152 | group_parent_id=parent_group.group_id, | |||
|
153 | group_description='Test desciption', | |||
|
154 | csrf_token=csrf_token)) | |||
|
155 | ||||
|
156 | assert_session_flash( | |||
|
157 | response, | |||
|
158 | u'Created repository group <a href="%s">%s</a>' % ( | |||
|
159 | h.route_path('repo_group_home', | |||
|
160 | repo_group_name=expected_group_name), | |||
|
161 | expected_group_name_unicode)) | |||
|
162 | finally: | |||
|
163 | RepoGroupModel().delete(expected_group_name_unicode) | |||
|
164 | Session().commit() | |||
|
165 | ||||
|
166 | def test_user_with_creation_permissions_cannot_create_subgroups( | |||
|
167 | self, autologin_regular_user, user_util): | |||
|
168 | ||||
|
169 | user_util.grant_user_permission( | |||
|
170 | TEST_USER_REGULAR_LOGIN, 'hg.repogroup.create.true') | |||
|
171 | parent_group = user_util.create_repo_group() | |||
|
172 | parent_group_id = parent_group.group_id | |||
|
173 | self.app.get( | |||
|
174 | route_path('repo_group_new', | |||
|
175 | params=dict(parent_group=parent_group_id), ), | |||
|
176 | status=403) |
@@ -0,0 +1,170 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2010-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import pytest | |||
|
22 | ||||
|
23 | from rhodecode.model.db import UserGroup, User | |||
|
24 | from rhodecode.model.meta import Session | |||
|
25 | ||||
|
26 | from rhodecode.tests import ( | |||
|
27 | TestController, TEST_USER_REGULAR_LOGIN, assert_session_flash) | |||
|
28 | from rhodecode.tests.fixture import Fixture | |||
|
29 | ||||
|
30 | fixture = Fixture() | |||
|
31 | ||||
|
32 | ||||
|
33 | def route_path(name, params=None, **kwargs): | |||
|
34 | import urllib | |||
|
35 | from rhodecode.apps._base import ADMIN_PREFIX | |||
|
36 | ||||
|
37 | base_url = { | |||
|
38 | 'user_groups': ADMIN_PREFIX + '/user_groups', | |||
|
39 | 'user_groups_data': ADMIN_PREFIX + '/user_groups_data', | |||
|
40 | 'user_group_members_data': ADMIN_PREFIX + '/user_groups/{user_group_id}/members', | |||
|
41 | 'user_groups_new': ADMIN_PREFIX + '/user_groups/new', | |||
|
42 | 'user_groups_create': ADMIN_PREFIX + '/user_groups/create', | |||
|
43 | 'edit_user_group': ADMIN_PREFIX + '/user_groups/{user_group_id}/edit', | |||
|
44 | }[name].format(**kwargs) | |||
|
45 | ||||
|
46 | if params: | |||
|
47 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |||
|
48 | return base_url | |||
|
49 | ||||
|
50 | ||||
|
51 | class TestAdminUserGroupsView(TestController): | |||
|
52 | ||||
|
53 | def test_show_users(self): | |||
|
54 | self.log_user() | |||
|
55 | self.app.get(route_path('user_groups')) | |||
|
56 | ||||
|
57 | def test_show_user_groups_data(self, xhr_header): | |||
|
58 | self.log_user() | |||
|
59 | response = self.app.get(route_path( | |||
|
60 | 'user_groups_data'), extra_environ=xhr_header) | |||
|
61 | ||||
|
62 | all_user_groups = UserGroup.query().count() | |||
|
63 | assert response.json['recordsTotal'] == all_user_groups | |||
|
64 | ||||
|
65 | def test_show_user_groups_data_filtered(self, xhr_header): | |||
|
66 | self.log_user() | |||
|
67 | response = self.app.get(route_path( | |||
|
68 | 'user_groups_data', params={'search[value]': 'empty_search'}), | |||
|
69 | extra_environ=xhr_header) | |||
|
70 | ||||
|
71 | all_user_groups = UserGroup.query().count() | |||
|
72 | assert response.json['recordsTotal'] == all_user_groups | |||
|
73 | assert response.json['recordsFiltered'] == 0 | |||
|
74 | ||||
|
75 | def test_usergroup_escape(self, user_util, xhr_header): | |||
|
76 | self.log_user() | |||
|
77 | ||||
|
78 | xss_img = '<img src="/image1" onload="alert(\'Hello, World!\');">' | |||
|
79 | user = user_util.create_user() | |||
|
80 | user.name = xss_img | |||
|
81 | user.lastname = xss_img | |||
|
82 | Session().add(user) | |||
|
83 | Session().commit() | |||
|
84 | ||||
|
85 | user_group = user_util.create_user_group() | |||
|
86 | ||||
|
87 | user_group.users_group_name = xss_img | |||
|
88 | user_group.user_group_description = '<strong onload="alert();">DESC</strong>' | |||
|
89 | ||||
|
90 | response = self.app.get( | |||
|
91 | route_path('user_groups_data'), extra_environ=xhr_header) | |||
|
92 | ||||
|
93 | response.mustcontain( | |||
|
94 | '<strong onload="alert();">DESC</strong>') | |||
|
95 | response.mustcontain( | |||
|
96 | '<img src="/image1" onload="' | |||
|
97 | 'alert('Hello, World!');">') | |||
|
98 | ||||
|
99 | def test_edit_user_group_autocomplete_empty_members(self, xhr_header, user_util): | |||
|
100 | self.log_user() | |||
|
101 | ug = user_util.create_user_group() | |||
|
102 | response = self.app.get( | |||
|
103 | route_path('user_group_members_data', user_group_id=ug.users_group_id), | |||
|
104 | extra_environ=xhr_header) | |||
|
105 | ||||
|
106 | assert response.json == {'members': []} | |||
|
107 | ||||
|
108 | def test_edit_user_group_autocomplete_members(self, xhr_header, user_util): | |||
|
109 | self.log_user() | |||
|
110 | members = [u.user_id for u in User.get_all()] | |||
|
111 | ug = user_util.create_user_group(members=members) | |||
|
112 | response = self.app.get( | |||
|
113 | route_path('user_group_members_data', | |||
|
114 | user_group_id=ug.users_group_id), | |||
|
115 | extra_environ=xhr_header) | |||
|
116 | ||||
|
117 | assert len(response.json['members']) == len(members) | |||
|
118 | ||||
|
119 | def test_creation_page(self): | |||
|
120 | self.log_user() | |||
|
121 | self.app.get(route_path('user_groups_new'), status=200) | |||
|
122 | ||||
|
123 | def test_create(self): | |||
|
124 | from rhodecode.lib import helpers as h | |||
|
125 | ||||
|
126 | self.log_user() | |||
|
127 | users_group_name = 'test_user_group' | |||
|
128 | response = self.app.post(route_path('user_groups_create'), { | |||
|
129 | 'users_group_name': users_group_name, | |||
|
130 | 'user_group_description': 'DESC', | |||
|
131 | 'active': True, | |||
|
132 | 'csrf_token': self.csrf_token}) | |||
|
133 | ||||
|
134 | user_group_id = UserGroup.get_by_group_name( | |||
|
135 | users_group_name).users_group_id | |||
|
136 | ||||
|
137 | user_group_link = h.link_to( | |||
|
138 | users_group_name, | |||
|
139 | route_path('edit_user_group', user_group_id=user_group_id)) | |||
|
140 | ||||
|
141 | assert_session_flash( | |||
|
142 | response, | |||
|
143 | 'Created user group %s' % user_group_link) | |||
|
144 | ||||
|
145 | fixture.destroy_user_group(users_group_name) | |||
|
146 | ||||
|
147 | def test_create_with_empty_name(self): | |||
|
148 | self.log_user() | |||
|
149 | ||||
|
150 | response = self.app.post(route_path('user_groups_create'), { | |||
|
151 | 'users_group_name': '', | |||
|
152 | 'user_group_description': 'DESC', | |||
|
153 | 'active': True, | |||
|
154 | 'csrf_token': self.csrf_token}, status=200) | |||
|
155 | ||||
|
156 | response.mustcontain('Please enter a value') | |||
|
157 | ||||
|
158 | def test_create_duplicate(self, user_util): | |||
|
159 | self.log_user() | |||
|
160 | ||||
|
161 | user_group = user_util.create_user_group() | |||
|
162 | duplicate_name = user_group.users_group_name | |||
|
163 | response = self.app.post(route_path('user_groups_create'), { | |||
|
164 | 'users_group_name': duplicate_name, | |||
|
165 | 'user_group_description': 'DESC', | |||
|
166 | 'active': True, | |||
|
167 | 'csrf_token': self.csrf_token}, status=200) | |||
|
168 | ||||
|
169 | response.mustcontain( | |||
|
170 | 'User group `{}` already exists'.format(user_group.users_group_name)) |
@@ -0,0 +1,173 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2010-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import pytest | |||
|
22 | ||||
|
23 | from rhodecode.model.db import User, UserSshKeys | |||
|
24 | ||||
|
25 | from rhodecode.tests import TestController, assert_session_flash | |||
|
26 | from rhodecode.tests.fixture import Fixture | |||
|
27 | ||||
|
28 | fixture = Fixture() | |||
|
29 | ||||
|
30 | ||||
|
31 | def route_path(name, params=None, **kwargs): | |||
|
32 | import urllib | |||
|
33 | from rhodecode.apps._base import ADMIN_PREFIX | |||
|
34 | ||||
|
35 | base_url = { | |||
|
36 | 'edit_user_ssh_keys': | |||
|
37 | ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys', | |||
|
38 | 'edit_user_ssh_keys_generate_keypair': | |||
|
39 | ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys/generate', | |||
|
40 | 'edit_user_ssh_keys_add': | |||
|
41 | ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys/new', | |||
|
42 | 'edit_user_ssh_keys_delete': | |||
|
43 | ADMIN_PREFIX + '/users/{user_id}/edit/ssh_keys/delete', | |||
|
44 | ||||
|
45 | }[name].format(**kwargs) | |||
|
46 | ||||
|
47 | if params: | |||
|
48 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |||
|
49 | return base_url | |||
|
50 | ||||
|
51 | ||||
|
52 | class TestAdminUsersSshKeysView(TestController): | |||
|
53 | INVALID_KEY = """\ | |||
|
54 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDk+77sjDzVeB6vevJsuZds1iNU5 | |||
|
55 | LANOa5CU5G/9JYIA6RYsWWMO7mbsR82IUckdqOHmxSykfR1D1TdluyIpQLrwgH5kb | |||
|
56 | n8FkVI8zBMCKakxowvN67B0R7b1BT4PPzW2JlOXei/m9W12ZY484VTow6/B+kf2Q8 | |||
|
57 | cP8tmCJmKWZma5Em7OTUhvjyQVNz3v7HfeY5Hq0Ci4ECJ59hepFDabJvtAXg9XrI6 | |||
|
58 | jvdphZTc30I4fG8+hBHzpeFxUGvSGNtXPUbwaAY8j/oHYrTpMgkj6pUEFsiKfC5zP | |||
|
59 | qPFR5HyKTCHW0nFUJnZsbyFT5hMiF/hZkJc9A0ZbdSvJwCRQ/g3bmdL | |||
|
60 | your_email@example.com | |||
|
61 | """ | |||
|
62 | VALID_KEY = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDk+77sjDzVeB6vev' \ | |||
|
63 | 'JsuZds1iNU5LANOa5CU5G/9JYIA6RYsWWMO7mbsR82IUckdqOHmxSy' \ | |||
|
64 | 'kfR1D1TdluyIpQLrwgH5kbn8FkVI8zBMCKakxowvN67B0R7b1BT4PP' \ | |||
|
65 | 'zW2JlOXei/m9W12ZY484VTow6/B+kf2Q8cP8tmCJmKWZma5Em7OTUh' \ | |||
|
66 | 'vjyQVNz3v7HfeY5Hq0Ci4ECJ59hepFDabJvtAXg9XrI6jvdphZTc30' \ | |||
|
67 | 'I4fG8+hBHzpeFxUGvSGNtXPUbwaAY8j/oHYrTpMgkj6pUEFsiKfC5zPq' \ | |||
|
68 | 'PFR5HyKTCHW0nFUJnZsbyFT5hMiF/hZkJc9A0ZbdSvJwCRQ/g3bmdL ' \ | |||
|
69 | 'your_email@example.com' | |||
|
70 | ||||
|
71 | def test_ssh_keys_default_user(self): | |||
|
72 | self.log_user() | |||
|
73 | user = User.get_default_user() | |||
|
74 | self.app.get( | |||
|
75 | route_path('edit_user_ssh_keys', user_id=user.user_id), | |||
|
76 | status=302) | |||
|
77 | ||||
|
78 | def test_add_ssh_key_error(self, user_util): | |||
|
79 | self.log_user() | |||
|
80 | user = user_util.create_user() | |||
|
81 | user_id = user.user_id | |||
|
82 | ||||
|
83 | key_data = self.INVALID_KEY | |||
|
84 | ||||
|
85 | desc = 'MY SSH KEY' | |||
|
86 | response = self.app.post( | |||
|
87 | route_path('edit_user_ssh_keys_add', user_id=user_id), | |||
|
88 | {'description': desc, 'key_data': key_data, | |||
|
89 | 'csrf_token': self.csrf_token}) | |||
|
90 | assert_session_flash(response, 'An error occurred during ssh ' | |||
|
91 | 'key saving: Unable to decode the key') | |||
|
92 | ||||
|
93 | def test_ssh_key_duplicate(self, user_util): | |||
|
94 | self.log_user() | |||
|
95 | user = user_util.create_user() | |||
|
96 | user_id = user.user_id | |||
|
97 | ||||
|
98 | key_data = self.VALID_KEY | |||
|
99 | ||||
|
100 | desc = 'MY SSH KEY' | |||
|
101 | response = self.app.post( | |||
|
102 | route_path('edit_user_ssh_keys_add', user_id=user_id), | |||
|
103 | {'description': desc, 'key_data': key_data, | |||
|
104 | 'csrf_token': self.csrf_token}) | |||
|
105 | assert_session_flash(response, 'Ssh Key successfully created') | |||
|
106 | response.follow() # flush session flash | |||
|
107 | ||||
|
108 | # add the same key AGAIN | |||
|
109 | desc = 'MY SSH KEY' | |||
|
110 | response = self.app.post( | |||
|
111 | route_path('edit_user_ssh_keys_add', user_id=user_id), | |||
|
112 | {'description': desc, 'key_data': key_data, | |||
|
113 | 'csrf_token': self.csrf_token}) | |||
|
114 | assert_session_flash(response, 'An error occurred during ssh key ' | |||
|
115 | 'saving: Such key already exists, ' | |||
|
116 | 'please use a different one') | |||
|
117 | ||||
|
118 | def test_add_ssh_key(self, user_util): | |||
|
119 | self.log_user() | |||
|
120 | user = user_util.create_user() | |||
|
121 | user_id = user.user_id | |||
|
122 | ||||
|
123 | key_data = self.VALID_KEY | |||
|
124 | ||||
|
125 | desc = 'MY SSH KEY' | |||
|
126 | response = self.app.post( | |||
|
127 | route_path('edit_user_ssh_keys_add', user_id=user_id), | |||
|
128 | {'description': desc, 'key_data': key_data, | |||
|
129 | 'csrf_token': self.csrf_token}) | |||
|
130 | assert_session_flash(response, 'Ssh Key successfully created') | |||
|
131 | ||||
|
132 | response = response.follow() | |||
|
133 | response.mustcontain(desc) | |||
|
134 | ||||
|
135 | def test_delete_ssh_key(self, user_util): | |||
|
136 | self.log_user() | |||
|
137 | user = user_util.create_user() | |||
|
138 | user_id = user.user_id | |||
|
139 | ||||
|
140 | key_data = self.VALID_KEY | |||
|
141 | ||||
|
142 | desc = 'MY SSH KEY' | |||
|
143 | response = self.app.post( | |||
|
144 | route_path('edit_user_ssh_keys_add', user_id=user_id), | |||
|
145 | {'description': desc, 'key_data': key_data, | |||
|
146 | 'csrf_token': self.csrf_token}) | |||
|
147 | assert_session_flash(response, 'Ssh Key successfully created') | |||
|
148 | response = response.follow() # flush the Session flash | |||
|
149 | ||||
|
150 | # now delete our key | |||
|
151 | keys = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).all() | |||
|
152 | assert 1 == len(keys) | |||
|
153 | ||||
|
154 | response = self.app.post( | |||
|
155 | route_path('edit_user_ssh_keys_delete', user_id=user_id), | |||
|
156 | {'del_ssh_key': keys[0].ssh_key_id, | |||
|
157 | 'csrf_token': self.csrf_token}) | |||
|
158 | ||||
|
159 | assert_session_flash(response, 'Ssh key successfully deleted') | |||
|
160 | keys = UserSshKeys.query().filter(UserSshKeys.user_id == user_id).all() | |||
|
161 | assert 0 == len(keys) | |||
|
162 | ||||
|
163 | def test_generate_keypair(self, user_util): | |||
|
164 | self.log_user() | |||
|
165 | user = user_util.create_user() | |||
|
166 | user_id = user.user_id | |||
|
167 | ||||
|
168 | response = self.app.get( | |||
|
169 | route_path('edit_user_ssh_keys_generate_keypair', user_id=user_id)) | |||
|
170 | ||||
|
171 | response.mustcontain('Private key') | |||
|
172 | response.mustcontain('Public key') | |||
|
173 | response.mustcontain('-----BEGIN RSA PRIVATE KEY-----') |
@@ -0,0 +1,111 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | ||||
|
23 | import formencode | |||
|
24 | import formencode.htmlfill | |||
|
25 | ||||
|
26 | from pyramid.view import view_config | |||
|
27 | from pyramid.httpexceptions import HTTPFound | |||
|
28 | from pyramid.renderers import render | |||
|
29 | from pyramid.response import Response | |||
|
30 | ||||
|
31 | from rhodecode.apps._base import BaseAppView | |||
|
32 | from rhodecode.lib.auth import ( | |||
|
33 | LoginRequired, HasPermissionAllDecorator, CSRFRequired) | |||
|
34 | from rhodecode.lib import helpers as h | |||
|
35 | from rhodecode.model.forms import DefaultsForm | |||
|
36 | from rhodecode.model.meta import Session | |||
|
37 | from rhodecode import BACKENDS | |||
|
38 | from rhodecode.model.settings import SettingsModel | |||
|
39 | ||||
|
40 | log = logging.getLogger(__name__) | |||
|
41 | ||||
|
42 | ||||
|
43 | class AdminDefaultSettingsView(BaseAppView): | |||
|
44 | def load_default_context(self): | |||
|
45 | c = self._get_local_tmpl_context() | |||
|
46 | ||||
|
47 | self._register_global_c(c) | |||
|
48 | return c | |||
|
49 | ||||
|
50 | @LoginRequired() | |||
|
51 | @HasPermissionAllDecorator('hg.admin') | |||
|
52 | @view_config( | |||
|
53 | route_name='admin_defaults_repositories', request_method='GET', | |||
|
54 | renderer='rhodecode:templates/admin/defaults/defaults.mako') | |||
|
55 | def defaults_repository_show(self): | |||
|
56 | c = self.load_default_context() | |||
|
57 | c.backends = BACKENDS.keys() | |||
|
58 | c.active = 'repositories' | |||
|
59 | defaults = SettingsModel().get_default_repo_settings() | |||
|
60 | ||||
|
61 | data = render( | |||
|
62 | 'rhodecode:templates/admin/defaults/defaults.mako', | |||
|
63 | self._get_template_context(c), self.request) | |||
|
64 | html = formencode.htmlfill.render( | |||
|
65 | data, | |||
|
66 | defaults=defaults, | |||
|
67 | encoding="UTF-8", | |||
|
68 | force_defaults=False | |||
|
69 | ) | |||
|
70 | return Response(html) | |||
|
71 | ||||
|
72 | @LoginRequired() | |||
|
73 | @HasPermissionAllDecorator('hg.admin') | |||
|
74 | @CSRFRequired() | |||
|
75 | @view_config( | |||
|
76 | route_name='admin_defaults_repositories_update', request_method='POST', | |||
|
77 | renderer='rhodecode:templates/admin/defaults/defaults.mako') | |||
|
78 | def defaults_repository_update(self): | |||
|
79 | _ = self.request.translate | |||
|
80 | c = self.load_default_context() | |||
|
81 | c.active = 'repositories' | |||
|
82 | form = DefaultsForm()() | |||
|
83 | ||||
|
84 | try: | |||
|
85 | form_result = form.to_python(dict(self.request.POST)) | |||
|
86 | for k, v in form_result.iteritems(): | |||
|
87 | setting = SettingsModel().create_or_update_setting(k, v) | |||
|
88 | Session().add(setting) | |||
|
89 | Session().commit() | |||
|
90 | h.flash(_('Default settings updated successfully'), | |||
|
91 | category='success') | |||
|
92 | ||||
|
93 | except formencode.Invalid as errors: | |||
|
94 | data = render( | |||
|
95 | 'rhodecode:templates/admin/defaults/defaults.mako', | |||
|
96 | self._get_template_context(c), self.request) | |||
|
97 | html = formencode.htmlfill.render( | |||
|
98 | data, | |||
|
99 | defaults=errors.value, | |||
|
100 | errors=errors.error_dict or {}, | |||
|
101 | prefix_error=False, | |||
|
102 | encoding="UTF-8", | |||
|
103 | force_defaults=False | |||
|
104 | ) | |||
|
105 | return Response(html) | |||
|
106 | except Exception: | |||
|
107 | log.exception('Exception in update action') | |||
|
108 | h.flash(_('Error occurred during update of default values'), | |||
|
109 | category='error') | |||
|
110 | ||||
|
111 | raise HTTPFound(h.route_path('admin_defaults_repositories')) |
@@ -0,0 +1,482 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import re | |||
|
22 | import logging | |||
|
23 | import formencode | |||
|
24 | import formencode.htmlfill | |||
|
25 | import datetime | |||
|
26 | from pyramid.interfaces import IRoutesMapper | |||
|
27 | ||||
|
28 | from pyramid.view import view_config | |||
|
29 | from pyramid.httpexceptions import HTTPFound | |||
|
30 | from pyramid.renderers import render | |||
|
31 | from pyramid.response import Response | |||
|
32 | ||||
|
33 | from rhodecode.apps._base import BaseAppView, DataGridAppView | |||
|
34 | from rhodecode.apps.ssh_support import SshKeyFileChangeEvent | |||
|
35 | from rhodecode.events import trigger | |||
|
36 | ||||
|
37 | from rhodecode.lib import helpers as h | |||
|
38 | from rhodecode.lib.auth import ( | |||
|
39 | LoginRequired, HasPermissionAllDecorator, CSRFRequired) | |||
|
40 | from rhodecode.lib.utils2 import aslist, safe_unicode | |||
|
41 | from rhodecode.model.db import ( | |||
|
42 | or_, coalesce, User, UserIpMap, UserSshKeys) | |||
|
43 | from rhodecode.model.forms import ( | |||
|
44 | ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm) | |||
|
45 | from rhodecode.model.meta import Session | |||
|
46 | from rhodecode.model.permission import PermissionModel | |||
|
47 | from rhodecode.model.settings import SettingsModel | |||
|
48 | ||||
|
49 | ||||
|
50 | log = logging.getLogger(__name__) | |||
|
51 | ||||
|
52 | ||||
|
53 | class AdminPermissionsView(BaseAppView, DataGridAppView): | |||
|
54 | def load_default_context(self): | |||
|
55 | c = self._get_local_tmpl_context() | |||
|
56 | ||||
|
57 | self._register_global_c(c) | |||
|
58 | PermissionModel().set_global_permission_choices( | |||
|
59 | c, gettext_translator=self.request.translate) | |||
|
60 | return c | |||
|
61 | ||||
|
62 | @LoginRequired() | |||
|
63 | @HasPermissionAllDecorator('hg.admin') | |||
|
64 | @view_config( | |||
|
65 | route_name='admin_permissions_application', request_method='GET', | |||
|
66 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
67 | def permissions_application(self): | |||
|
68 | c = self.load_default_context() | |||
|
69 | c.active = 'application' | |||
|
70 | ||||
|
71 | c.user = User.get_default_user(refresh=True) | |||
|
72 | ||||
|
73 | app_settings = SettingsModel().get_all_settings() | |||
|
74 | defaults = { | |||
|
75 | 'anonymous': c.user.active, | |||
|
76 | 'default_register_message': app_settings.get( | |||
|
77 | 'rhodecode_register_message') | |||
|
78 | } | |||
|
79 | defaults.update(c.user.get_default_perms()) | |||
|
80 | ||||
|
81 | data = render('rhodecode:templates/admin/permissions/permissions.mako', | |||
|
82 | self._get_template_context(c), self.request) | |||
|
83 | html = formencode.htmlfill.render( | |||
|
84 | data, | |||
|
85 | defaults=defaults, | |||
|
86 | encoding="UTF-8", | |||
|
87 | force_defaults=False | |||
|
88 | ) | |||
|
89 | return Response(html) | |||
|
90 | ||||
|
91 | @LoginRequired() | |||
|
92 | @HasPermissionAllDecorator('hg.admin') | |||
|
93 | @CSRFRequired() | |||
|
94 | @view_config( | |||
|
95 | route_name='admin_permissions_application_update', request_method='POST', | |||
|
96 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
97 | def permissions_application_update(self): | |||
|
98 | _ = self.request.translate | |||
|
99 | c = self.load_default_context() | |||
|
100 | c.active = 'application' | |||
|
101 | ||||
|
102 | _form = ApplicationPermissionsForm( | |||
|
103 | [x[0] for x in c.register_choices], | |||
|
104 | [x[0] for x in c.password_reset_choices], | |||
|
105 | [x[0] for x in c.extern_activate_choices])() | |||
|
106 | ||||
|
107 | try: | |||
|
108 | form_result = _form.to_python(dict(self.request.POST)) | |||
|
109 | form_result.update({'perm_user_name': User.DEFAULT_USER}) | |||
|
110 | PermissionModel().update_application_permissions(form_result) | |||
|
111 | ||||
|
112 | settings = [ | |||
|
113 | ('register_message', 'default_register_message'), | |||
|
114 | ] | |||
|
115 | for setting, form_key in settings: | |||
|
116 | sett = SettingsModel().create_or_update_setting( | |||
|
117 | setting, form_result[form_key]) | |||
|
118 | Session().add(sett) | |||
|
119 | ||||
|
120 | Session().commit() | |||
|
121 | h.flash(_('Application permissions updated successfully'), | |||
|
122 | category='success') | |||
|
123 | ||||
|
124 | except formencode.Invalid as errors: | |||
|
125 | defaults = errors.value | |||
|
126 | ||||
|
127 | data = render( | |||
|
128 | 'rhodecode:templates/admin/permissions/permissions.mako', | |||
|
129 | self._get_template_context(c), self.request) | |||
|
130 | html = formencode.htmlfill.render( | |||
|
131 | data, | |||
|
132 | defaults=defaults, | |||
|
133 | errors=errors.error_dict or {}, | |||
|
134 | prefix_error=False, | |||
|
135 | encoding="UTF-8", | |||
|
136 | force_defaults=False | |||
|
137 | ) | |||
|
138 | return Response(html) | |||
|
139 | ||||
|
140 | except Exception: | |||
|
141 | log.exception("Exception during update of permissions") | |||
|
142 | h.flash(_('Error occurred during update of permissions'), | |||
|
143 | category='error') | |||
|
144 | ||||
|
145 | raise HTTPFound(h.route_path('admin_permissions_application')) | |||
|
146 | ||||
|
147 | @LoginRequired() | |||
|
148 | @HasPermissionAllDecorator('hg.admin') | |||
|
149 | @view_config( | |||
|
150 | route_name='admin_permissions_object', request_method='GET', | |||
|
151 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
152 | def permissions_objects(self): | |||
|
153 | c = self.load_default_context() | |||
|
154 | c.active = 'objects' | |||
|
155 | ||||
|
156 | c.user = User.get_default_user(refresh=True) | |||
|
157 | defaults = {} | |||
|
158 | defaults.update(c.user.get_default_perms()) | |||
|
159 | ||||
|
160 | data = render( | |||
|
161 | 'rhodecode:templates/admin/permissions/permissions.mako', | |||
|
162 | self._get_template_context(c), self.request) | |||
|
163 | html = formencode.htmlfill.render( | |||
|
164 | data, | |||
|
165 | defaults=defaults, | |||
|
166 | encoding="UTF-8", | |||
|
167 | force_defaults=False | |||
|
168 | ) | |||
|
169 | return Response(html) | |||
|
170 | ||||
|
171 | @LoginRequired() | |||
|
172 | @HasPermissionAllDecorator('hg.admin') | |||
|
173 | @CSRFRequired() | |||
|
174 | @view_config( | |||
|
175 | route_name='admin_permissions_object_update', request_method='POST', | |||
|
176 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
177 | def permissions_objects_update(self): | |||
|
178 | _ = self.request.translate | |||
|
179 | c = self.load_default_context() | |||
|
180 | c.active = 'objects' | |||
|
181 | ||||
|
182 | _form = ObjectPermissionsForm( | |||
|
183 | [x[0] for x in c.repo_perms_choices], | |||
|
184 | [x[0] for x in c.group_perms_choices], | |||
|
185 | [x[0] for x in c.user_group_perms_choices])() | |||
|
186 | ||||
|
187 | try: | |||
|
188 | form_result = _form.to_python(dict(self.request.POST)) | |||
|
189 | form_result.update({'perm_user_name': User.DEFAULT_USER}) | |||
|
190 | PermissionModel().update_object_permissions(form_result) | |||
|
191 | ||||
|
192 | Session().commit() | |||
|
193 | h.flash(_('Object permissions updated successfully'), | |||
|
194 | category='success') | |||
|
195 | ||||
|
196 | except formencode.Invalid as errors: | |||
|
197 | defaults = errors.value | |||
|
198 | ||||
|
199 | data = render( | |||
|
200 | 'rhodecode:templates/admin/permissions/permissions.mako', | |||
|
201 | self._get_template_context(c), self.request) | |||
|
202 | html = formencode.htmlfill.render( | |||
|
203 | data, | |||
|
204 | defaults=defaults, | |||
|
205 | errors=errors.error_dict or {}, | |||
|
206 | prefix_error=False, | |||
|
207 | encoding="UTF-8", | |||
|
208 | force_defaults=False | |||
|
209 | ) | |||
|
210 | return Response(html) | |||
|
211 | except Exception: | |||
|
212 | log.exception("Exception during update of permissions") | |||
|
213 | h.flash(_('Error occurred during update of permissions'), | |||
|
214 | category='error') | |||
|
215 | ||||
|
216 | raise HTTPFound(h.route_path('admin_permissions_object')) | |||
|
217 | ||||
|
218 | @LoginRequired() | |||
|
219 | @HasPermissionAllDecorator('hg.admin') | |||
|
220 | @view_config( | |||
|
221 | route_name='admin_permissions_global', request_method='GET', | |||
|
222 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
223 | def permissions_global(self): | |||
|
224 | c = self.load_default_context() | |||
|
225 | c.active = 'global' | |||
|
226 | ||||
|
227 | c.user = User.get_default_user(refresh=True) | |||
|
228 | defaults = {} | |||
|
229 | defaults.update(c.user.get_default_perms()) | |||
|
230 | ||||
|
231 | data = render( | |||
|
232 | 'rhodecode:templates/admin/permissions/permissions.mako', | |||
|
233 | self._get_template_context(c), self.request) | |||
|
234 | html = formencode.htmlfill.render( | |||
|
235 | data, | |||
|
236 | defaults=defaults, | |||
|
237 | encoding="UTF-8", | |||
|
238 | force_defaults=False | |||
|
239 | ) | |||
|
240 | return Response(html) | |||
|
241 | ||||
|
242 | @LoginRequired() | |||
|
243 | @HasPermissionAllDecorator('hg.admin') | |||
|
244 | @CSRFRequired() | |||
|
245 | @view_config( | |||
|
246 | route_name='admin_permissions_global_update', request_method='POST', | |||
|
247 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
248 | def permissions_global_update(self): | |||
|
249 | _ = self.request.translate | |||
|
250 | c = self.load_default_context() | |||
|
251 | c.active = 'global' | |||
|
252 | ||||
|
253 | _form = UserPermissionsForm( | |||
|
254 | [x[0] for x in c.repo_create_choices], | |||
|
255 | [x[0] for x in c.repo_create_on_write_choices], | |||
|
256 | [x[0] for x in c.repo_group_create_choices], | |||
|
257 | [x[0] for x in c.user_group_create_choices], | |||
|
258 | [x[0] for x in c.fork_choices], | |||
|
259 | [x[0] for x in c.inherit_default_permission_choices])() | |||
|
260 | ||||
|
261 | try: | |||
|
262 | form_result = _form.to_python(dict(self.request.POST)) | |||
|
263 | form_result.update({'perm_user_name': User.DEFAULT_USER}) | |||
|
264 | PermissionModel().update_user_permissions(form_result) | |||
|
265 | ||||
|
266 | Session().commit() | |||
|
267 | h.flash(_('Global permissions updated successfully'), | |||
|
268 | category='success') | |||
|
269 | ||||
|
270 | except formencode.Invalid as errors: | |||
|
271 | defaults = errors.value | |||
|
272 | ||||
|
273 | data = render( | |||
|
274 | 'rhodecode:templates/admin/permissions/permissions.mako', | |||
|
275 | self._get_template_context(c), self.request) | |||
|
276 | html = formencode.htmlfill.render( | |||
|
277 | data, | |||
|
278 | defaults=defaults, | |||
|
279 | errors=errors.error_dict or {}, | |||
|
280 | prefix_error=False, | |||
|
281 | encoding="UTF-8", | |||
|
282 | force_defaults=False | |||
|
283 | ) | |||
|
284 | return Response(html) | |||
|
285 | except Exception: | |||
|
286 | log.exception("Exception during update of permissions") | |||
|
287 | h.flash(_('Error occurred during update of permissions'), | |||
|
288 | category='error') | |||
|
289 | ||||
|
290 | raise HTTPFound(h.route_path('admin_permissions_global')) | |||
|
291 | ||||
|
292 | @LoginRequired() | |||
|
293 | @HasPermissionAllDecorator('hg.admin') | |||
|
294 | @view_config( | |||
|
295 | route_name='admin_permissions_ips', request_method='GET', | |||
|
296 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
297 | def permissions_ips(self): | |||
|
298 | c = self.load_default_context() | |||
|
299 | c.active = 'ips' | |||
|
300 | ||||
|
301 | c.user = User.get_default_user(refresh=True) | |||
|
302 | c.user_ip_map = ( | |||
|
303 | UserIpMap.query().filter(UserIpMap.user == c.user).all()) | |||
|
304 | ||||
|
305 | return self._get_template_context(c) | |||
|
306 | ||||
|
307 | @LoginRequired() | |||
|
308 | @HasPermissionAllDecorator('hg.admin') | |||
|
309 | @view_config( | |||
|
310 | route_name='admin_permissions_overview', request_method='GET', | |||
|
311 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
312 | def permissions_overview(self): | |||
|
313 | c = self.load_default_context() | |||
|
314 | c.active = 'perms' | |||
|
315 | ||||
|
316 | c.user = User.get_default_user(refresh=True) | |||
|
317 | c.perm_user = c.user.AuthUser() | |||
|
318 | return self._get_template_context(c) | |||
|
319 | ||||
|
320 | @LoginRequired() | |||
|
321 | @HasPermissionAllDecorator('hg.admin') | |||
|
322 | @view_config( | |||
|
323 | route_name='admin_permissions_auth_token_access', request_method='GET', | |||
|
324 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
325 | def auth_token_access(self): | |||
|
326 | from rhodecode import CONFIG | |||
|
327 | ||||
|
328 | c = self.load_default_context() | |||
|
329 | c.active = 'auth_token_access' | |||
|
330 | ||||
|
331 | c.user = User.get_default_user(refresh=True) | |||
|
332 | c.perm_user = c.user.AuthUser() | |||
|
333 | ||||
|
334 | mapper = self.request.registry.queryUtility(IRoutesMapper) | |||
|
335 | c.view_data = [] | |||
|
336 | ||||
|
337 | _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)') | |||
|
338 | introspector = self.request.registry.introspector | |||
|
339 | ||||
|
340 | view_intr = {} | |||
|
341 | for view_data in introspector.get_category('views'): | |||
|
342 | intr = view_data['introspectable'] | |||
|
343 | ||||
|
344 | if 'route_name' in intr and intr['attr']: | |||
|
345 | view_intr[intr['route_name']] = '{}:{}'.format( | |||
|
346 | str(intr['derived_callable'].func_name), intr['attr'] | |||
|
347 | ) | |||
|
348 | ||||
|
349 | c.whitelist_key = 'api_access_controllers_whitelist' | |||
|
350 | c.whitelist_file = CONFIG.get('__file__') | |||
|
351 | whitelist_views = aslist( | |||
|
352 | CONFIG.get(c.whitelist_key), sep=',') | |||
|
353 | ||||
|
354 | for route_info in mapper.get_routes(): | |||
|
355 | if not route_info.name.startswith('__'): | |||
|
356 | routepath = route_info.pattern | |||
|
357 | ||||
|
358 | def replace(matchobj): | |||
|
359 | if matchobj.group(1): | |||
|
360 | return "{%s}" % matchobj.group(1).split(':')[0] | |||
|
361 | else: | |||
|
362 | return "{%s}" % matchobj.group(2) | |||
|
363 | ||||
|
364 | routepath = _argument_prog.sub(replace, routepath) | |||
|
365 | ||||
|
366 | if not routepath.startswith('/'): | |||
|
367 | routepath = '/' + routepath | |||
|
368 | ||||
|
369 | view_fqn = view_intr.get(route_info.name, 'NOT AVAILABLE') | |||
|
370 | active = view_fqn in whitelist_views | |||
|
371 | c.view_data.append((route_info.name, view_fqn, routepath, active)) | |||
|
372 | ||||
|
373 | c.whitelist_views = whitelist_views | |||
|
374 | return self._get_template_context(c) | |||
|
375 | ||||
|
376 | def ssh_enabled(self): | |||
|
377 | return self.request.registry.settings.get( | |||
|
378 | 'ssh.generate_authorized_keyfile') | |||
|
379 | ||||
|
380 | @LoginRequired() | |||
|
381 | @HasPermissionAllDecorator('hg.admin') | |||
|
382 | @view_config( | |||
|
383 | route_name='admin_permissions_ssh_keys', request_method='GET', | |||
|
384 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
385 | def ssh_keys(self): | |||
|
386 | c = self.load_default_context() | |||
|
387 | c.active = 'ssh_keys' | |||
|
388 | c.ssh_enabled = self.ssh_enabled() | |||
|
389 | return self._get_template_context(c) | |||
|
390 | ||||
|
391 | @LoginRequired() | |||
|
392 | @HasPermissionAllDecorator('hg.admin') | |||
|
393 | @view_config( | |||
|
394 | route_name='admin_permissions_ssh_keys_data', request_method='GET', | |||
|
395 | renderer='json_ext', xhr=True) | |||
|
396 | def ssh_keys_data(self): | |||
|
397 | _ = self.request.translate | |||
|
398 | column_map = { | |||
|
399 | 'fingerprint': 'ssh_key_fingerprint', | |||
|
400 | 'username': User.username | |||
|
401 | } | |||
|
402 | draw, start, limit = self._extract_chunk(self.request) | |||
|
403 | search_q, order_by, order_dir = self._extract_ordering( | |||
|
404 | self.request, column_map=column_map) | |||
|
405 | ||||
|
406 | ssh_keys_data_total_count = UserSshKeys.query()\ | |||
|
407 | .count() | |||
|
408 | ||||
|
409 | # json generate | |||
|
410 | base_q = UserSshKeys.query().join(UserSshKeys.user) | |||
|
411 | ||||
|
412 | if search_q: | |||
|
413 | like_expression = u'%{}%'.format(safe_unicode(search_q)) | |||
|
414 | base_q = base_q.filter(or_( | |||
|
415 | User.username.ilike(like_expression), | |||
|
416 | UserSshKeys.ssh_key_fingerprint.ilike(like_expression), | |||
|
417 | )) | |||
|
418 | ||||
|
419 | users_data_total_filtered_count = base_q.count() | |||
|
420 | ||||
|
421 | sort_col = self._get_order_col(order_by, UserSshKeys) | |||
|
422 | if sort_col: | |||
|
423 | if order_dir == 'asc': | |||
|
424 | # handle null values properly to order by NULL last | |||
|
425 | if order_by in ['created_on']: | |||
|
426 | sort_col = coalesce(sort_col, datetime.date.max) | |||
|
427 | sort_col = sort_col.asc() | |||
|
428 | else: | |||
|
429 | # handle null values properly to order by NULL last | |||
|
430 | if order_by in ['created_on']: | |||
|
431 | sort_col = coalesce(sort_col, datetime.date.min) | |||
|
432 | sort_col = sort_col.desc() | |||
|
433 | ||||
|
434 | base_q = base_q.order_by(sort_col) | |||
|
435 | base_q = base_q.offset(start).limit(limit) | |||
|
436 | ||||
|
437 | ssh_keys = base_q.all() | |||
|
438 | ||||
|
439 | ssh_keys_data = [] | |||
|
440 | for ssh_key in ssh_keys: | |||
|
441 | ssh_keys_data.append({ | |||
|
442 | "username": h.gravatar_with_user(self.request, ssh_key.user.username), | |||
|
443 | "fingerprint": ssh_key.ssh_key_fingerprint, | |||
|
444 | "description": ssh_key.description, | |||
|
445 | "created_on": h.format_date(ssh_key.created_on), | |||
|
446 | "accessed_on": h.format_date(ssh_key.accessed_on), | |||
|
447 | "action": h.link_to( | |||
|
448 | _('Edit'), h.route_path('edit_user_ssh_keys', | |||
|
449 | user_id=ssh_key.user.user_id)) | |||
|
450 | }) | |||
|
451 | ||||
|
452 | data = ({ | |||
|
453 | 'draw': draw, | |||
|
454 | 'data': ssh_keys_data, | |||
|
455 | 'recordsTotal': ssh_keys_data_total_count, | |||
|
456 | 'recordsFiltered': users_data_total_filtered_count, | |||
|
457 | }) | |||
|
458 | ||||
|
459 | return data | |||
|
460 | ||||
|
461 | @LoginRequired() | |||
|
462 | @HasPermissionAllDecorator('hg.admin') | |||
|
463 | @CSRFRequired() | |||
|
464 | @view_config( | |||
|
465 | route_name='admin_permissions_ssh_keys_update', request_method='POST', | |||
|
466 | renderer='rhodecode:templates/admin/permissions/permissions.mako') | |||
|
467 | def ssh_keys_update(self): | |||
|
468 | _ = self.request.translate | |||
|
469 | self.load_default_context() | |||
|
470 | ||||
|
471 | ssh_enabled = self.ssh_enabled() | |||
|
472 | key_file = self.request.registry.settings.get( | |||
|
473 | 'ssh.authorized_keys_file_path') | |||
|
474 | if ssh_enabled: | |||
|
475 | trigger(SshKeyFileChangeEvent(), self.request.registry) | |||
|
476 | h.flash(_('Updated SSH keys file: {}').format(key_file), | |||
|
477 | category='success') | |||
|
478 | else: | |||
|
479 | h.flash(_('SSH key support is disabled in .ini file'), | |||
|
480 | category='warning') | |||
|
481 | ||||
|
482 | raise HTTPFound(h.route_path('admin_permissions_ssh_keys')) |
@@ -0,0 +1,91 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | ||||
|
23 | import psutil | |||
|
24 | from pyramid.view import view_config | |||
|
25 | ||||
|
26 | from rhodecode.apps._base import BaseAppView | |||
|
27 | from rhodecode.apps.admin.navigation import navigation_list | |||
|
28 | from rhodecode.lib.auth import ( | |||
|
29 | LoginRequired, HasPermissionAllDecorator, CSRFRequired) | |||
|
30 | from rhodecode.lib.utils2 import safe_int | |||
|
31 | ||||
|
32 | log = logging.getLogger(__name__) | |||
|
33 | ||||
|
34 | ||||
|
35 | class AdminProcessManagementView(BaseAppView): | |||
|
36 | def load_default_context(self): | |||
|
37 | c = self._get_local_tmpl_context() | |||
|
38 | self._register_global_c(c) | |||
|
39 | return c | |||
|
40 | ||||
|
41 | @LoginRequired() | |||
|
42 | @HasPermissionAllDecorator('hg.admin') | |||
|
43 | @view_config( | |||
|
44 | route_name='admin_settings_process_management', request_method='GET', | |||
|
45 | renderer='rhodecode:templates/admin/settings/settings.mako') | |||
|
46 | def process_management(self): | |||
|
47 | _ = self.request.translate | |||
|
48 | c = self.load_default_context() | |||
|
49 | ||||
|
50 | c.active = 'process_management' | |||
|
51 | c.navlist = navigation_list(self.request) | |||
|
52 | c.gunicorn_processes = ( | |||
|
53 | p for p in psutil.process_iter() if 'gunicorn' in p.name()) | |||
|
54 | return self._get_template_context(c) | |||
|
55 | ||||
|
56 | @LoginRequired() | |||
|
57 | @HasPermissionAllDecorator('hg.admin') | |||
|
58 | @CSRFRequired() | |||
|
59 | @view_config( | |||
|
60 | route_name='admin_settings_process_management_signal', | |||
|
61 | request_method='POST', renderer='json_ext') | |||
|
62 | def process_management_signal(self): | |||
|
63 | pids = self.request.json.get('pids', []) | |||
|
64 | result = [] | |||
|
65 | def on_terminate(proc): | |||
|
66 | msg = "process `PID:{}` terminated with exit code {}".format( | |||
|
67 | proc.pid, proc.returncode) | |||
|
68 | result.append(msg) | |||
|
69 | ||||
|
70 | procs = [] | |||
|
71 | for pid in pids: | |||
|
72 | pid = safe_int(pid) | |||
|
73 | if pid: | |||
|
74 | try: | |||
|
75 | proc = psutil.Process(pid) | |||
|
76 | except psutil.NoSuchProcess: | |||
|
77 | continue | |||
|
78 | ||||
|
79 | children = proc.children(recursive=True) | |||
|
80 | if children: | |||
|
81 | print('Wont kill Master Process') | |||
|
82 | else: | |||
|
83 | procs.append(proc) | |||
|
84 | ||||
|
85 | for p in procs: | |||
|
86 | p.terminate() | |||
|
87 | gone, alive = psutil.wait_procs(procs, timeout=10, callback=on_terminate) | |||
|
88 | for p in alive: | |||
|
89 | p.kill() | |||
|
90 | ||||
|
91 | return {'result': result} |
@@ -0,0 +1,204 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | import formencode | |||
|
23 | import formencode.htmlfill | |||
|
24 | ||||
|
25 | from pyramid.httpexceptions import HTTPFound, HTTPForbidden | |||
|
26 | from pyramid.view import view_config | |||
|
27 | from pyramid.renderers import render | |||
|
28 | from pyramid.response import Response | |||
|
29 | ||||
|
30 | from rhodecode.apps._base import BaseAppView, DataGridAppView | |||
|
31 | ||||
|
32 | from rhodecode.lib.ext_json import json | |||
|
33 | from rhodecode.lib.auth import ( | |||
|
34 | LoginRequired, CSRFRequired, NotAnonymous, | |||
|
35 | HasPermissionAny, HasRepoGroupPermissionAny) | |||
|
36 | from rhodecode.lib import helpers as h, audit_logger | |||
|
37 | from rhodecode.lib.utils2 import safe_int, safe_unicode | |||
|
38 | from rhodecode.model.forms import RepoGroupForm | |||
|
39 | from rhodecode.model.repo_group import RepoGroupModel | |||
|
40 | from rhodecode.model.scm import RepoGroupList | |||
|
41 | from rhodecode.model.db import Session, RepoGroup | |||
|
42 | ||||
|
43 | log = logging.getLogger(__name__) | |||
|
44 | ||||
|
45 | ||||
|
46 | class AdminRepoGroupsView(BaseAppView, DataGridAppView): | |||
|
47 | ||||
|
48 | def load_default_context(self): | |||
|
49 | c = self._get_local_tmpl_context() | |||
|
50 | self._register_global_c(c) | |||
|
51 | return c | |||
|
52 | ||||
|
53 | def _load_form_data(self, c): | |||
|
54 | allow_empty_group = False | |||
|
55 | ||||
|
56 | if self._can_create_repo_group(): | |||
|
57 | # we're global admin, we're ok and we can create TOP level groups | |||
|
58 | allow_empty_group = True | |||
|
59 | ||||
|
60 | # override the choices for this form, we need to filter choices | |||
|
61 | # and display only those we have ADMIN right | |||
|
62 | groups_with_admin_rights = RepoGroupList( | |||
|
63 | RepoGroup.query().all(), | |||
|
64 | perm_set=['group.admin']) | |||
|
65 | c.repo_groups = RepoGroup.groups_choices( | |||
|
66 | groups=groups_with_admin_rights, | |||
|
67 | show_empty_group=allow_empty_group) | |||
|
68 | ||||
|
69 | def _can_create_repo_group(self, parent_group_id=None): | |||
|
70 | is_admin = HasPermissionAny('hg.admin')('group create controller') | |||
|
71 | create_repo_group = HasPermissionAny( | |||
|
72 | 'hg.repogroup.create.true')('group create controller') | |||
|
73 | if is_admin or (create_repo_group and not parent_group_id): | |||
|
74 | # we're global admin, or we have global repo group create | |||
|
75 | # permission | |||
|
76 | # we're ok and we can create TOP level groups | |||
|
77 | return True | |||
|
78 | elif parent_group_id: | |||
|
79 | # we check the permission if we can write to parent group | |||
|
80 | group = RepoGroup.get(parent_group_id) | |||
|
81 | group_name = group.group_name if group else None | |||
|
82 | if HasRepoGroupPermissionAny('group.admin')( | |||
|
83 | group_name, 'check if user is an admin of group'): | |||
|
84 | # we're an admin of passed in group, we're ok. | |||
|
85 | return True | |||
|
86 | else: | |||
|
87 | return False | |||
|
88 | return False | |||
|
89 | ||||
|
90 | @LoginRequired() | |||
|
91 | @NotAnonymous() | |||
|
92 | # perms check inside | |||
|
93 | @view_config( | |||
|
94 | route_name='repo_groups', request_method='GET', | |||
|
95 | renderer='rhodecode:templates/admin/repo_groups/repo_groups.mako') | |||
|
96 | def repo_group_list(self): | |||
|
97 | c = self.load_default_context() | |||
|
98 | ||||
|
99 | repo_group_list = RepoGroup.get_all_repo_groups() | |||
|
100 | repo_group_list_acl = RepoGroupList( | |||
|
101 | repo_group_list, perm_set=['group.admin']) | |||
|
102 | repo_group_data = RepoGroupModel().get_repo_groups_as_dict( | |||
|
103 | repo_group_list=repo_group_list_acl, admin=True) | |||
|
104 | c.data = json.dumps(repo_group_data) | |||
|
105 | return self._get_template_context(c) | |||
|
106 | ||||
|
107 | @LoginRequired() | |||
|
108 | @NotAnonymous() | |||
|
109 | # perm checks inside | |||
|
110 | @view_config( | |||
|
111 | route_name='repo_group_new', request_method='GET', | |||
|
112 | renderer='rhodecode:templates/admin/repo_groups/repo_group_add.mako') | |||
|
113 | def repo_group_new(self): | |||
|
114 | c = self.load_default_context() | |||
|
115 | ||||
|
116 | # perm check for admin, create_group perm or admin of parent_group | |||
|
117 | parent_group_id = safe_int(self.request.GET.get('parent_group')) | |||
|
118 | if not self._can_create_repo_group(parent_group_id): | |||
|
119 | raise HTTPForbidden() | |||
|
120 | ||||
|
121 | self._load_form_data(c) | |||
|
122 | ||||
|
123 | defaults = {} # Future proof for default of repo group | |||
|
124 | data = render( | |||
|
125 | 'rhodecode:templates/admin/repo_groups/repo_group_add.mako', | |||
|
126 | self._get_template_context(c), self.request) | |||
|
127 | html = formencode.htmlfill.render( | |||
|
128 | data, | |||
|
129 | defaults=defaults, | |||
|
130 | encoding="UTF-8", | |||
|
131 | force_defaults=False | |||
|
132 | ) | |||
|
133 | return Response(html) | |||
|
134 | ||||
|
135 | @LoginRequired() | |||
|
136 | @NotAnonymous() | |||
|
137 | @CSRFRequired() | |||
|
138 | # perm checks inside | |||
|
139 | @view_config( | |||
|
140 | route_name='repo_group_create', request_method='POST', | |||
|
141 | renderer='rhodecode:templates/admin/repo_groups/repo_group_add.mako') | |||
|
142 | def repo_group_create(self): | |||
|
143 | c = self.load_default_context() | |||
|
144 | _ = self.request.translate | |||
|
145 | ||||
|
146 | parent_group_id = safe_int(self.request.POST.get('group_parent_id')) | |||
|
147 | can_create = self._can_create_repo_group(parent_group_id) | |||
|
148 | ||||
|
149 | self._load_form_data(c) | |||
|
150 | # permissions for can create group based on parent_id are checked | |||
|
151 | # here in the Form | |||
|
152 | available_groups = map(lambda k: safe_unicode(k[0]), c.repo_groups) | |||
|
153 | repo_group_form = RepoGroupForm(available_groups=available_groups, | |||
|
154 | can_create_in_root=can_create)() | |||
|
155 | ||||
|
156 | repo_group_name = self.request.POST.get('group_name') | |||
|
157 | try: | |||
|
158 | owner = self._rhodecode_user | |||
|
159 | form_result = repo_group_form.to_python(dict(self.request.POST)) | |||
|
160 | repo_group = RepoGroupModel().create( | |||
|
161 | group_name=form_result['group_name_full'], | |||
|
162 | group_description=form_result['group_description'], | |||
|
163 | owner=owner.user_id, | |||
|
164 | copy_permissions=form_result['group_copy_permissions'] | |||
|
165 | ) | |||
|
166 | Session().flush() | |||
|
167 | ||||
|
168 | repo_group_data = repo_group.get_api_data() | |||
|
169 | audit_logger.store_web( | |||
|
170 | 'repo_group.create', action_data={'data': repo_group_data}, | |||
|
171 | user=self._rhodecode_user) | |||
|
172 | ||||
|
173 | Session().commit() | |||
|
174 | ||||
|
175 | _new_group_name = form_result['group_name_full'] | |||
|
176 | ||||
|
177 | repo_group_url = h.link_to( | |||
|
178 | _new_group_name, | |||
|
179 | h.route_path('repo_group_home', repo_group_name=_new_group_name)) | |||
|
180 | h.flash(h.literal(_('Created repository group %s') | |||
|
181 | % repo_group_url), category='success') | |||
|
182 | ||||
|
183 | except formencode.Invalid as errors: | |||
|
184 | data = render( | |||
|
185 | 'rhodecode:templates/admin/repo_groups/repo_group_add.mako', | |||
|
186 | self._get_template_context(c), self.request) | |||
|
187 | html = formencode.htmlfill.render( | |||
|
188 | data, | |||
|
189 | defaults=errors.value, | |||
|
190 | errors=errors.error_dict or {}, | |||
|
191 | prefix_error=False, | |||
|
192 | encoding="UTF-8", | |||
|
193 | force_defaults=False | |||
|
194 | ) | |||
|
195 | return Response(html) | |||
|
196 | except Exception: | |||
|
197 | log.exception("Exception during creation of repository group") | |||
|
198 | h.flash(_('Error occurred during creation of repository group %s') | |||
|
199 | % repo_group_name, category='error') | |||
|
200 | raise HTTPFound(h.route_path('home')) | |||
|
201 | ||||
|
202 | raise HTTPFound( | |||
|
203 | h.route_path('repo_group_home', | |||
|
204 | repo_group_name=form_result['group_name_full'])) |
@@ -0,0 +1,182 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | import formencode | |||
|
23 | import formencode.htmlfill | |||
|
24 | ||||
|
25 | from pyramid.httpexceptions import HTTPFound, HTTPForbidden | |||
|
26 | from pyramid.view import view_config | |||
|
27 | from pyramid.renderers import render | |||
|
28 | from pyramid.response import Response | |||
|
29 | ||||
|
30 | from rhodecode.apps._base import BaseAppView, DataGridAppView | |||
|
31 | ||||
|
32 | from rhodecode.lib.ext_json import json | |||
|
33 | from rhodecode.lib.auth import ( | |||
|
34 | LoginRequired, CSRFRequired, NotAnonymous, | |||
|
35 | HasPermissionAny, HasRepoGroupPermissionAny) | |||
|
36 | from rhodecode.lib import helpers as h | |||
|
37 | from rhodecode.lib.utils import repo_name_slug | |||
|
38 | from rhodecode.lib.utils2 import safe_int, safe_unicode | |||
|
39 | from rhodecode.model.forms import RepoForm | |||
|
40 | from rhodecode.model.repo import RepoModel | |||
|
41 | from rhodecode.model.scm import RepoList, RepoGroupList, ScmModel | |||
|
42 | from rhodecode.model.settings import SettingsModel | |||
|
43 | from rhodecode.model.db import Repository, RepoGroup | |||
|
44 | ||||
|
45 | log = logging.getLogger(__name__) | |||
|
46 | ||||
|
47 | ||||
|
48 | class AdminReposView(BaseAppView, DataGridAppView): | |||
|
49 | ||||
|
50 | def load_default_context(self): | |||
|
51 | c = self._get_local_tmpl_context() | |||
|
52 | self._register_global_c(c) | |||
|
53 | return c | |||
|
54 | ||||
|
55 | def _load_form_data(self, c): | |||
|
56 | acl_groups = RepoGroupList(RepoGroup.query().all(), | |||
|
57 | perm_set=['group.write', 'group.admin']) | |||
|
58 | c.repo_groups = RepoGroup.groups_choices(groups=acl_groups) | |||
|
59 | c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups) | |||
|
60 | c.landing_revs_choices, c.landing_revs = \ | |||
|
61 | ScmModel().get_repo_landing_revs() | |||
|
62 | c.personal_repo_group = self._rhodecode_user.personal_repo_group | |||
|
63 | ||||
|
64 | @LoginRequired() | |||
|
65 | @NotAnonymous() | |||
|
66 | # perms check inside | |||
|
67 | @view_config( | |||
|
68 | route_name='repos', request_method='GET', | |||
|
69 | renderer='rhodecode:templates/admin/repos/repos.mako') | |||
|
70 | def repository_list(self): | |||
|
71 | c = self.load_default_context() | |||
|
72 | ||||
|
73 | repo_list = Repository.get_all_repos() | |||
|
74 | c.repo_list = RepoList(repo_list, perm_set=['repository.admin']) | |||
|
75 | repos_data = RepoModel().get_repos_as_dict( | |||
|
76 | repo_list=c.repo_list, admin=True, super_user_actions=True) | |||
|
77 | # json used to render the grid | |||
|
78 | c.data = json.dumps(repos_data) | |||
|
79 | ||||
|
80 | return self._get_template_context(c) | |||
|
81 | ||||
|
82 | @LoginRequired() | |||
|
83 | @NotAnonymous() | |||
|
84 | # perms check inside | |||
|
85 | @view_config( | |||
|
86 | route_name='repo_new', request_method='GET', | |||
|
87 | renderer='rhodecode:templates/admin/repos/repo_add.mako') | |||
|
88 | def repository_new(self): | |||
|
89 | c = self.load_default_context() | |||
|
90 | ||||
|
91 | new_repo = self.request.GET.get('repo', '') | |||
|
92 | parent_group = safe_int(self.request.GET.get('parent_group')) | |||
|
93 | _gr = RepoGroup.get(parent_group) | |||
|
94 | ||||
|
95 | if not HasPermissionAny('hg.admin', 'hg.create.repository')(): | |||
|
96 | # you're not super admin nor have global create permissions, | |||
|
97 | # but maybe you have at least write permission to a parent group ? | |||
|
98 | ||||
|
99 | gr_name = _gr.group_name if _gr else None | |||
|
100 | # create repositories with write permission on group is set to true | |||
|
101 | create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')() | |||
|
102 | group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name) | |||
|
103 | group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name) | |||
|
104 | if not (group_admin or (group_write and create_on_write)): | |||
|
105 | raise HTTPForbidden() | |||
|
106 | ||||
|
107 | self._load_form_data(c) | |||
|
108 | c.new_repo = repo_name_slug(new_repo) | |||
|
109 | ||||
|
110 | # apply the defaults from defaults page | |||
|
111 | defaults = SettingsModel().get_default_repo_settings(strip_prefix=True) | |||
|
112 | # set checkbox to autochecked | |||
|
113 | defaults['repo_copy_permissions'] = True | |||
|
114 | ||||
|
115 | parent_group_choice = '-1' | |||
|
116 | if not self._rhodecode_user.is_admin and self._rhodecode_user.personal_repo_group: | |||
|
117 | parent_group_choice = self._rhodecode_user.personal_repo_group | |||
|
118 | ||||
|
119 | if parent_group and _gr: | |||
|
120 | if parent_group in [x[0] for x in c.repo_groups]: | |||
|
121 | parent_group_choice = safe_unicode(parent_group) | |||
|
122 | ||||
|
123 | defaults.update({'repo_group': parent_group_choice}) | |||
|
124 | ||||
|
125 | data = render('rhodecode:templates/admin/repos/repo_add.mako', | |||
|
126 | self._get_template_context(c), self.request) | |||
|
127 | html = formencode.htmlfill.render( | |||
|
128 | data, | |||
|
129 | defaults=defaults, | |||
|
130 | encoding="UTF-8", | |||
|
131 | force_defaults=False | |||
|
132 | ) | |||
|
133 | return Response(html) | |||
|
134 | ||||
|
135 | @LoginRequired() | |||
|
136 | @NotAnonymous() | |||
|
137 | @CSRFRequired() | |||
|
138 | # perms check inside | |||
|
139 | @view_config( | |||
|
140 | route_name='repo_create', request_method='POST', | |||
|
141 | renderer='rhodecode:templates/admin/repos/repos.mako') | |||
|
142 | def repository_create(self): | |||
|
143 | c = self.load_default_context() | |||
|
144 | ||||
|
145 | form_result = {} | |||
|
146 | task_id = None | |||
|
147 | self._load_form_data(c) | |||
|
148 | ||||
|
149 | try: | |||
|
150 | # CanWriteToGroup validators checks permissions of this POST | |||
|
151 | form_result = RepoForm(repo_groups=c.repo_groups_choices, | |||
|
152 | landing_revs=c.landing_revs_choices)()\ | |||
|
153 | .to_python(dict(self.request.POST)) | |||
|
154 | ||||
|
155 | # create is done sometimes async on celery, db transaction | |||
|
156 | # management is handled there. | |||
|
157 | task = RepoModel().create(form_result, self._rhodecode_user.user_id) | |||
|
158 | from celery.result import BaseAsyncResult | |||
|
159 | if isinstance(task, BaseAsyncResult): | |||
|
160 | task_id = task.task_id | |||
|
161 | except formencode.Invalid as errors: | |||
|
162 | data = render('rhodecode:templates/admin/repos/repo_add.mako', | |||
|
163 | self._get_template_context(c), self.request) | |||
|
164 | html = formencode.htmlfill.render( | |||
|
165 | data, | |||
|
166 | defaults=errors.value, | |||
|
167 | errors=errors.error_dict or {}, | |||
|
168 | prefix_error=False, | |||
|
169 | encoding="UTF-8", | |||
|
170 | force_defaults=False | |||
|
171 | ) | |||
|
172 | return Response(html) | |||
|
173 | ||||
|
174 | except Exception as e: | |||
|
175 | msg = self._log_creation_exception(e, form_result.get('repo_name')) | |||
|
176 | h.flash(msg, category='error') | |||
|
177 | raise HTTPFound(h.route_path('home')) | |||
|
178 | ||||
|
179 | raise HTTPFound( | |||
|
180 | h.route_path('repo_creating', | |||
|
181 | repo_name=form_result['repo_name_full'], | |||
|
182 | _query=dict(task_id=task_id))) |
@@ -0,0 +1,247 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | ||||
|
23 | import formencode | |||
|
24 | import formencode.htmlfill | |||
|
25 | ||||
|
26 | from pyramid.httpexceptions import HTTPFound | |||
|
27 | from pyramid.view import view_config | |||
|
28 | from pyramid.response import Response | |||
|
29 | from pyramid.renderers import render | |||
|
30 | ||||
|
31 | from rhodecode.apps._base import BaseAppView, DataGridAppView | |||
|
32 | from rhodecode.lib.auth import ( | |||
|
33 | LoginRequired, NotAnonymous, CSRFRequired, HasPermissionAnyDecorator) | |||
|
34 | from rhodecode.lib import helpers as h, audit_logger | |||
|
35 | from rhodecode.lib.utils2 import safe_unicode | |||
|
36 | ||||
|
37 | from rhodecode.model.forms import UserGroupForm | |||
|
38 | from rhodecode.model.permission import PermissionModel | |||
|
39 | from rhodecode.model.scm import UserGroupList | |||
|
40 | from rhodecode.model.db import ( | |||
|
41 | or_, count, User, UserGroup, UserGroupMember) | |||
|
42 | from rhodecode.model.meta import Session | |||
|
43 | from rhodecode.model.user_group import UserGroupModel | |||
|
44 | ||||
|
45 | log = logging.getLogger(__name__) | |||
|
46 | ||||
|
47 | ||||
|
48 | class AdminUserGroupsView(BaseAppView, DataGridAppView): | |||
|
49 | ||||
|
50 | def load_default_context(self): | |||
|
51 | c = self._get_local_tmpl_context() | |||
|
52 | ||||
|
53 | PermissionModel().set_global_permission_choices( | |||
|
54 | c, gettext_translator=self.request.translate) | |||
|
55 | ||||
|
56 | self._register_global_c(c) | |||
|
57 | return c | |||
|
58 | ||||
|
59 | # permission check in data loading of | |||
|
60 | # `user_groups_list_data` via UserGroupList | |||
|
61 | @LoginRequired() | |||
|
62 | @NotAnonymous() | |||
|
63 | @view_config( | |||
|
64 | route_name='user_groups', request_method='GET', | |||
|
65 | renderer='rhodecode:templates/admin/user_groups/user_groups.mako') | |||
|
66 | def user_groups_list(self): | |||
|
67 | c = self.load_default_context() | |||
|
68 | return self._get_template_context(c) | |||
|
69 | ||||
|
70 | # permission check inside | |||
|
71 | @LoginRequired() | |||
|
72 | @NotAnonymous() | |||
|
73 | @view_config( | |||
|
74 | route_name='user_groups_data', request_method='GET', | |||
|
75 | renderer='json_ext', xhr=True) | |||
|
76 | def user_groups_list_data(self): | |||
|
77 | column_map = { | |||
|
78 | 'active': 'users_group_active', | |||
|
79 | 'description': 'user_group_description', | |||
|
80 | 'members': 'members_total', | |||
|
81 | 'owner': 'user_username', | |||
|
82 | 'sync': 'group_data' | |||
|
83 | } | |||
|
84 | draw, start, limit = self._extract_chunk(self.request) | |||
|
85 | search_q, order_by, order_dir = self._extract_ordering( | |||
|
86 | self.request, column_map=column_map) | |||
|
87 | ||||
|
88 | _render = self.request.get_partial_renderer( | |||
|
89 | 'data_table/_dt_elements.mako') | |||
|
90 | ||||
|
91 | def user_group_name(user_group_id, user_group_name): | |||
|
92 | return _render("user_group_name", user_group_id, user_group_name) | |||
|
93 | ||||
|
94 | def user_group_actions(user_group_id, user_group_name): | |||
|
95 | return _render("user_group_actions", user_group_id, user_group_name) | |||
|
96 | ||||
|
97 | def user_profile(username): | |||
|
98 | return _render('user_profile', username) | |||
|
99 | ||||
|
100 | auth_user_group_list = UserGroupList( | |||
|
101 | UserGroup.query().all(), perm_set=['usergroup.admin']) | |||
|
102 | ||||
|
103 | allowed_ids = [-1] | |||
|
104 | for user_group in auth_user_group_list: | |||
|
105 | allowed_ids.append(user_group.users_group_id) | |||
|
106 | ||||
|
107 | user_groups_data_total_count = UserGroup.query()\ | |||
|
108 | .filter(UserGroup.users_group_id.in_(allowed_ids))\ | |||
|
109 | .count() | |||
|
110 | ||||
|
111 | member_count = count(UserGroupMember.user_id) | |||
|
112 | base_q = Session.query( | |||
|
113 | UserGroup.users_group_name, | |||
|
114 | UserGroup.user_group_description, | |||
|
115 | UserGroup.users_group_active, | |||
|
116 | UserGroup.users_group_id, | |||
|
117 | UserGroup.group_data, | |||
|
118 | User, | |||
|
119 | member_count.label('member_count') | |||
|
120 | ) \ | |||
|
121 | .filter(UserGroup.users_group_id.in_(allowed_ids)) \ | |||
|
122 | .outerjoin(UserGroupMember) \ | |||
|
123 | .join(User, User.user_id == UserGroup.user_id) \ | |||
|
124 | .group_by(UserGroup, User) | |||
|
125 | ||||
|
126 | if search_q: | |||
|
127 | like_expression = u'%{}%'.format(safe_unicode(search_q)) | |||
|
128 | base_q = base_q.filter(or_( | |||
|
129 | UserGroup.users_group_name.ilike(like_expression), | |||
|
130 | )) | |||
|
131 | ||||
|
132 | user_groups_data_total_filtered_count = base_q.count() | |||
|
133 | ||||
|
134 | if order_by == 'members_total': | |||
|
135 | sort_col = member_count | |||
|
136 | elif order_by == 'user_username': | |||
|
137 | sort_col = User.username | |||
|
138 | else: | |||
|
139 | sort_col = getattr(UserGroup, order_by, None) | |||
|
140 | ||||
|
141 | if isinstance(sort_col, count) or sort_col: | |||
|
142 | if order_dir == 'asc': | |||
|
143 | sort_col = sort_col.asc() | |||
|
144 | else: | |||
|
145 | sort_col = sort_col.desc() | |||
|
146 | ||||
|
147 | base_q = base_q.order_by(sort_col) | |||
|
148 | base_q = base_q.offset(start).limit(limit) | |||
|
149 | ||||
|
150 | # authenticated access to user groups | |||
|
151 | auth_user_group_list = base_q.all() | |||
|
152 | ||||
|
153 | user_groups_data = [] | |||
|
154 | for user_gr in auth_user_group_list: | |||
|
155 | user_groups_data.append({ | |||
|
156 | "users_group_name": user_group_name( | |||
|
157 | user_gr.users_group_id, h.escape(user_gr.users_group_name)), | |||
|
158 | "name_raw": h.escape(user_gr.users_group_name), | |||
|
159 | "description": h.escape(user_gr.user_group_description), | |||
|
160 | "members": user_gr.member_count, | |||
|
161 | # NOTE(marcink): because of advanced query we | |||
|
162 | # need to load it like that | |||
|
163 | "sync": UserGroup._load_group_data( | |||
|
164 | user_gr.group_data).get('extern_type'), | |||
|
165 | "active": h.bool2icon(user_gr.users_group_active), | |||
|
166 | "owner": user_profile(user_gr.User.username), | |||
|
167 | "action": user_group_actions( | |||
|
168 | user_gr.users_group_id, user_gr.users_group_name) | |||
|
169 | }) | |||
|
170 | ||||
|
171 | data = ({ | |||
|
172 | 'draw': draw, | |||
|
173 | 'data': user_groups_data, | |||
|
174 | 'recordsTotal': user_groups_data_total_count, | |||
|
175 | 'recordsFiltered': user_groups_data_total_filtered_count, | |||
|
176 | }) | |||
|
177 | ||||
|
178 | return data | |||
|
179 | ||||
|
180 | @LoginRequired() | |||
|
181 | @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') | |||
|
182 | @view_config( | |||
|
183 | route_name='user_groups_new', request_method='GET', | |||
|
184 | renderer='rhodecode:templates/admin/user_groups/user_group_add.mako') | |||
|
185 | def user_groups_new(self): | |||
|
186 | c = self.load_default_context() | |||
|
187 | return self._get_template_context(c) | |||
|
188 | ||||
|
189 | @LoginRequired() | |||
|
190 | @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true') | |||
|
191 | @CSRFRequired() | |||
|
192 | @view_config( | |||
|
193 | route_name='user_groups_create', request_method='POST', | |||
|
194 | renderer='rhodecode:templates/admin/user_groups/user_group_add.mako') | |||
|
195 | def user_groups_create(self): | |||
|
196 | _ = self.request.translate | |||
|
197 | c = self.load_default_context() | |||
|
198 | users_group_form = UserGroupForm()() | |||
|
199 | ||||
|
200 | user_group_name = self.request.POST.get('users_group_name') | |||
|
201 | try: | |||
|
202 | form_result = users_group_form.to_python(dict(self.request.POST)) | |||
|
203 | user_group = UserGroupModel().create( | |||
|
204 | name=form_result['users_group_name'], | |||
|
205 | description=form_result['user_group_description'], | |||
|
206 | owner=self._rhodecode_user.user_id, | |||
|
207 | active=form_result['users_group_active']) | |||
|
208 | Session().flush() | |||
|
209 | creation_data = user_group.get_api_data() | |||
|
210 | user_group_name = form_result['users_group_name'] | |||
|
211 | ||||
|
212 | audit_logger.store_web( | |||
|
213 | 'user_group.create', action_data={'data': creation_data}, | |||
|
214 | user=self._rhodecode_user) | |||
|
215 | ||||
|
216 | user_group_link = h.link_to( | |||
|
217 | h.escape(user_group_name), | |||
|
218 | h.route_path( | |||
|
219 | 'edit_user_group', user_group_id=user_group.users_group_id)) | |||
|
220 | h.flash(h.literal(_('Created user group %(user_group_link)s') | |||
|
221 | % {'user_group_link': user_group_link}), | |||
|
222 | category='success') | |||
|
223 | Session().commit() | |||
|
224 | user_group_id = user_group.users_group_id | |||
|
225 | except formencode.Invalid as errors: | |||
|
226 | ||||
|
227 | data = render( | |||
|
228 | 'rhodecode:templates/admin/user_groups/user_group_add.mako', | |||
|
229 | self._get_template_context(c), self.request) | |||
|
230 | html = formencode.htmlfill.render( | |||
|
231 | data, | |||
|
232 | defaults=errors.value, | |||
|
233 | errors=errors.error_dict or {}, | |||
|
234 | prefix_error=False, | |||
|
235 | encoding="UTF-8", | |||
|
236 | force_defaults=False | |||
|
237 | ) | |||
|
238 | return Response(html) | |||
|
239 | ||||
|
240 | except Exception: | |||
|
241 | log.exception("Exception creating user group") | |||
|
242 | h.flash(_('Error occurred during creation of user group %s') \ | |||
|
243 | % user_group_name, category='error') | |||
|
244 | raise HTTPFound(h.route_path('user_groups_new')) | |||
|
245 | ||||
|
246 | raise HTTPFound( | |||
|
247 | h.route_path('edit_user_group', user_group_id=user_group_id)) |
@@ -0,0 +1,42 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | from rhodecode.apps._base import ADMIN_PREFIX | |||
|
21 | from rhodecode.lib.utils2 import str2bool | |||
|
22 | ||||
|
23 | ||||
|
24 | def debug_style_enabled(info, request): | |||
|
25 | return str2bool(request.registry.settings.get('debug_style')) | |||
|
26 | ||||
|
27 | ||||
|
28 | def includeme(config): | |||
|
29 | config.add_route( | |||
|
30 | name='debug_style_home', | |||
|
31 | pattern=ADMIN_PREFIX + '/debug_style', | |||
|
32 | custom_predicates=(debug_style_enabled,)) | |||
|
33 | config.add_route( | |||
|
34 | name='debug_style_template', | |||
|
35 | pattern=ADMIN_PREFIX + '/debug_style/t/{t_path}', | |||
|
36 | custom_predicates=(debug_style_enabled,)) | |||
|
37 | ||||
|
38 | # Scan module for configuration decorators. | |||
|
39 | config.scan('.views', ignore='.tests') | |||
|
40 | ||||
|
41 | ||||
|
42 |
@@ -0,0 +1,59 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import os | |||
|
22 | import logging | |||
|
23 | ||||
|
24 | from pyramid.view import view_config | |||
|
25 | from pyramid.renderers import render_to_response | |||
|
26 | from rhodecode.apps._base import BaseAppView | |||
|
27 | ||||
|
28 | log = logging.getLogger(__name__) | |||
|
29 | ||||
|
30 | ||||
|
31 | class DebugStyleView(BaseAppView): | |||
|
32 | def load_default_context(self): | |||
|
33 | c = self._get_local_tmpl_context() | |||
|
34 | self._register_global_c(c) | |||
|
35 | return c | |||
|
36 | ||||
|
37 | @view_config( | |||
|
38 | route_name='debug_style_home', request_method='GET', | |||
|
39 | renderer=None) | |||
|
40 | def index(self): | |||
|
41 | c = self.load_default_context() | |||
|
42 | c.active = 'index' | |||
|
43 | ||||
|
44 | return render_to_response( | |||
|
45 | 'debug_style/index.html', self._get_template_context(c), | |||
|
46 | request=self.request) | |||
|
47 | ||||
|
48 | @view_config( | |||
|
49 | route_name='debug_style_template', request_method='GET', | |||
|
50 | renderer=None) | |||
|
51 | def template(self): | |||
|
52 | t_path = self.request.matchdict['t_path'] | |||
|
53 | c = self.load_default_context() | |||
|
54 | c.active = os.path.splitext(t_path)[0] | |||
|
55 | c.came_from = '' | |||
|
56 | ||||
|
57 | return render_to_response( | |||
|
58 | 'debug_style/' + t_path, self._get_template_context(c), | |||
|
59 | request=self.request) No newline at end of file |
@@ -0,0 +1,62 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | from rhodecode.apps._base import ADMIN_PREFIX | |||
|
21 | ||||
|
22 | ||||
|
23 | def admin_routes(config): | |||
|
24 | config.add_route( | |||
|
25 | name='gists_show', pattern='/gists') | |||
|
26 | config.add_route( | |||
|
27 | name='gists_new', pattern='/gists/new') | |||
|
28 | config.add_route( | |||
|
29 | name='gists_create', pattern='/gists/create') | |||
|
30 | ||||
|
31 | config.add_route( | |||
|
32 | name='gist_show', pattern='/gists/{gist_id}') | |||
|
33 | ||||
|
34 | config.add_route( | |||
|
35 | name='gist_delete', pattern='/gists/{gist_id}/delete') | |||
|
36 | ||||
|
37 | config.add_route( | |||
|
38 | name='gist_edit', pattern='/gists/{gist_id}/edit') | |||
|
39 | ||||
|
40 | config.add_route( | |||
|
41 | name='gist_edit_check_revision', | |||
|
42 | pattern='/gists/{gist_id}/edit/check_revision') | |||
|
43 | ||||
|
44 | config.add_route( | |||
|
45 | name='gist_update', pattern='/gists/{gist_id}/update') | |||
|
46 | ||||
|
47 | config.add_route( | |||
|
48 | name='gist_show_rev', | |||
|
49 | pattern='/gists/{gist_id}/{revision}') | |||
|
50 | config.add_route( | |||
|
51 | name='gist_show_formatted', | |||
|
52 | pattern='/gists/{gist_id}/{revision}/{format}') | |||
|
53 | ||||
|
54 | config.add_route( | |||
|
55 | name='gist_show_formatted_path', | |||
|
56 | pattern='/gists/{gist_id}/{revision}/{format}/{f_path:.*}') | |||
|
57 | ||||
|
58 | ||||
|
59 | def includeme(config): | |||
|
60 | config.include(admin_routes, route_prefix=ADMIN_PREFIX) | |||
|
61 | # Scan module for configuration decorators. | |||
|
62 | config.scan('.views', ignore='.tests') |
@@ -0,0 +1,20 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 |
@@ -0,0 +1,413 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2013-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import time | |||
|
22 | import logging | |||
|
23 | ||||
|
24 | import formencode | |||
|
25 | import formencode.htmlfill | |||
|
26 | import peppercorn | |||
|
27 | ||||
|
28 | from pyramid.httpexceptions import HTTPNotFound, HTTPFound | |||
|
29 | from pyramid.view import view_config | |||
|
30 | from pyramid.renderers import render | |||
|
31 | from pyramid.response import Response | |||
|
32 | ||||
|
33 | from rhodecode.apps._base import BaseAppView | |||
|
34 | from rhodecode.lib import helpers as h | |||
|
35 | from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired | |||
|
36 | from rhodecode.lib.utils2 import time_to_datetime | |||
|
37 | from rhodecode.lib.ext_json import json | |||
|
38 | from rhodecode.lib.vcs.exceptions import VCSError, NodeNotChangedError | |||
|
39 | from rhodecode.model.gist import GistModel | |||
|
40 | from rhodecode.model.meta import Session | |||
|
41 | from rhodecode.model.db import Gist, User, or_ | |||
|
42 | from rhodecode.model import validation_schema | |||
|
43 | from rhodecode.model.validation_schema.schemas import gist_schema | |||
|
44 | ||||
|
45 | ||||
|
46 | log = logging.getLogger(__name__) | |||
|
47 | ||||
|
48 | ||||
|
49 | class GistView(BaseAppView): | |||
|
50 | ||||
|
51 | def load_default_context(self): | |||
|
52 | _ = self.request.translate | |||
|
53 | c = self._get_local_tmpl_context() | |||
|
54 | c.user = c.auth_user.get_instance() | |||
|
55 | ||||
|
56 | c.lifetime_values = [ | |||
|
57 | (-1, _('forever')), | |||
|
58 | (5, _('5 minutes')), | |||
|
59 | (60, _('1 hour')), | |||
|
60 | (60 * 24, _('1 day')), | |||
|
61 | (60 * 24 * 30, _('1 month')), | |||
|
62 | ] | |||
|
63 | ||||
|
64 | c.lifetime_options = [(c.lifetime_values, _("Lifetime"))] | |||
|
65 | c.acl_options = [ | |||
|
66 | (Gist.ACL_LEVEL_PRIVATE, _("Requires registered account")), | |||
|
67 | (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users")) | |||
|
68 | ] | |||
|
69 | ||||
|
70 | self._register_global_c(c) | |||
|
71 | return c | |||
|
72 | ||||
|
73 | @LoginRequired() | |||
|
74 | @view_config( | |||
|
75 | route_name='gists_show', request_method='GET', | |||
|
76 | renderer='rhodecode:templates/admin/gists/index.mako') | |||
|
77 | def gist_show_all(self): | |||
|
78 | c = self.load_default_context() | |||
|
79 | ||||
|
80 | not_default_user = self._rhodecode_user.username != User.DEFAULT_USER | |||
|
81 | c.show_private = self.request.GET.get('private') and not_default_user | |||
|
82 | c.show_public = self.request.GET.get('public') and not_default_user | |||
|
83 | c.show_all = self.request.GET.get('all') and self._rhodecode_user.admin | |||
|
84 | ||||
|
85 | gists = _gists = Gist().query()\ | |||
|
86 | .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time()))\ | |||
|
87 | .order_by(Gist.created_on.desc()) | |||
|
88 | ||||
|
89 | c.active = 'public' | |||
|
90 | # MY private | |||
|
91 | if c.show_private and not c.show_public: | |||
|
92 | gists = _gists.filter(Gist.gist_type == Gist.GIST_PRIVATE)\ | |||
|
93 | .filter(Gist.gist_owner == self._rhodecode_user.user_id) | |||
|
94 | c.active = 'my_private' | |||
|
95 | # MY public | |||
|
96 | elif c.show_public and not c.show_private: | |||
|
97 | gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)\ | |||
|
98 | .filter(Gist.gist_owner == self._rhodecode_user.user_id) | |||
|
99 | c.active = 'my_public' | |||
|
100 | # MY public+private | |||
|
101 | elif c.show_private and c.show_public: | |||
|
102 | gists = _gists.filter(or_(Gist.gist_type == Gist.GIST_PUBLIC, | |||
|
103 | Gist.gist_type == Gist.GIST_PRIVATE))\ | |||
|
104 | .filter(Gist.gist_owner == self._rhodecode_user.user_id) | |||
|
105 | c.active = 'my_all' | |||
|
106 | # Show all by super-admin | |||
|
107 | elif c.show_all: | |||
|
108 | c.active = 'all' | |||
|
109 | gists = _gists | |||
|
110 | ||||
|
111 | # default show ALL public gists | |||
|
112 | if not c.show_public and not c.show_private and not c.show_all: | |||
|
113 | gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC) | |||
|
114 | c.active = 'public' | |||
|
115 | ||||
|
116 | _render = self.request.get_partial_renderer( | |||
|
117 | 'data_table/_dt_elements.mako') | |||
|
118 | ||||
|
119 | data = [] | |||
|
120 | ||||
|
121 | for gist in gists: | |||
|
122 | data.append({ | |||
|
123 | 'created_on': _render('gist_created', gist.created_on), | |||
|
124 | 'created_on_raw': gist.created_on, | |||
|
125 | 'type': _render('gist_type', gist.gist_type), | |||
|
126 | 'access_id': _render('gist_access_id', gist.gist_access_id, gist.owner.full_contact), | |||
|
127 | 'author': _render('gist_author', gist.owner.full_contact, gist.created_on, gist.gist_expires), | |||
|
128 | 'author_raw': h.escape(gist.owner.full_contact), | |||
|
129 | 'expires': _render('gist_expires', gist.gist_expires), | |||
|
130 | 'description': _render('gist_description', gist.gist_description) | |||
|
131 | }) | |||
|
132 | c.data = json.dumps(data) | |||
|
133 | ||||
|
134 | return self._get_template_context(c) | |||
|
135 | ||||
|
136 | @LoginRequired() | |||
|
137 | @NotAnonymous() | |||
|
138 | @view_config( | |||
|
139 | route_name='gists_new', request_method='GET', | |||
|
140 | renderer='rhodecode:templates/admin/gists/new.mako') | |||
|
141 | def gist_new(self): | |||
|
142 | c = self.load_default_context() | |||
|
143 | return self._get_template_context(c) | |||
|
144 | ||||
|
145 | @LoginRequired() | |||
|
146 | @NotAnonymous() | |||
|
147 | @CSRFRequired() | |||
|
148 | @view_config( | |||
|
149 | route_name='gists_create', request_method='POST', | |||
|
150 | renderer='rhodecode:templates/admin/gists/new.mako') | |||
|
151 | def gist_create(self): | |||
|
152 | _ = self.request.translate | |||
|
153 | c = self.load_default_context() | |||
|
154 | ||||
|
155 | data = dict(self.request.POST) | |||
|
156 | data['filename'] = data.get('filename') or Gist.DEFAULT_FILENAME | |||
|
157 | data['nodes'] = [{ | |||
|
158 | 'filename': data['filename'], | |||
|
159 | 'content': data.get('content'), | |||
|
160 | 'mimetype': data.get('mimetype') # None is autodetect | |||
|
161 | }] | |||
|
162 | ||||
|
163 | data['gist_type'] = ( | |||
|
164 | Gist.GIST_PUBLIC if data.get('public') else Gist.GIST_PRIVATE) | |||
|
165 | data['gist_acl_level'] = ( | |||
|
166 | data.get('gist_acl_level') or Gist.ACL_LEVEL_PRIVATE) | |||
|
167 | ||||
|
168 | schema = gist_schema.GistSchema().bind( | |||
|
169 | lifetime_options=[x[0] for x in c.lifetime_values]) | |||
|
170 | ||||
|
171 | try: | |||
|
172 | ||||
|
173 | schema_data = schema.deserialize(data) | |||
|
174 | # convert to safer format with just KEYs so we sure no duplicates | |||
|
175 | schema_data['nodes'] = gist_schema.sequence_to_nodes( | |||
|
176 | schema_data['nodes']) | |||
|
177 | ||||
|
178 | gist = GistModel().create( | |||
|
179 | gist_id=schema_data['gistid'], # custom access id not real ID | |||
|
180 | description=schema_data['description'], | |||
|
181 | owner=self._rhodecode_user.user_id, | |||
|
182 | gist_mapping=schema_data['nodes'], | |||
|
183 | gist_type=schema_data['gist_type'], | |||
|
184 | lifetime=schema_data['lifetime'], | |||
|
185 | gist_acl_level=schema_data['gist_acl_level'] | |||
|
186 | ) | |||
|
187 | Session().commit() | |||
|
188 | new_gist_id = gist.gist_access_id | |||
|
189 | except validation_schema.Invalid as errors: | |||
|
190 | defaults = data | |||
|
191 | errors = errors.asdict() | |||
|
192 | ||||
|
193 | if 'nodes.0.content' in errors: | |||
|
194 | errors['content'] = errors['nodes.0.content'] | |||
|
195 | del errors['nodes.0.content'] | |||
|
196 | if 'nodes.0.filename' in errors: | |||
|
197 | errors['filename'] = errors['nodes.0.filename'] | |||
|
198 | del errors['nodes.0.filename'] | |||
|
199 | ||||
|
200 | data = render('rhodecode:templates/admin/gists/new.mako', | |||
|
201 | self._get_template_context(c), self.request) | |||
|
202 | html = formencode.htmlfill.render( | |||
|
203 | data, | |||
|
204 | defaults=defaults, | |||
|
205 | errors=errors, | |||
|
206 | prefix_error=False, | |||
|
207 | encoding="UTF-8", | |||
|
208 | force_defaults=False | |||
|
209 | ) | |||
|
210 | return Response(html) | |||
|
211 | ||||
|
212 | except Exception: | |||
|
213 | log.exception("Exception while trying to create a gist") | |||
|
214 | h.flash(_('Error occurred during gist creation'), category='error') | |||
|
215 | raise HTTPFound(h.route_url('gists_new')) | |||
|
216 | raise HTTPFound(h.route_url('gist_show', gist_id=new_gist_id)) | |||
|
217 | ||||
|
218 | @LoginRequired() | |||
|
219 | @NotAnonymous() | |||
|
220 | @CSRFRequired() | |||
|
221 | @view_config( | |||
|
222 | route_name='gist_delete', request_method='POST') | |||
|
223 | def gist_delete(self): | |||
|
224 | _ = self.request.translate | |||
|
225 | gist_id = self.request.matchdict['gist_id'] | |||
|
226 | ||||
|
227 | c = self.load_default_context() | |||
|
228 | c.gist = Gist.get_or_404(gist_id) | |||
|
229 | ||||
|
230 | owner = c.gist.gist_owner == self._rhodecode_user.user_id | |||
|
231 | if not (h.HasPermissionAny('hg.admin')() or owner): | |||
|
232 | log.warning('Deletion of Gist was forbidden ' | |||
|
233 | 'by unauthorized user: `%s`', self._rhodecode_user) | |||
|
234 | raise HTTPNotFound() | |||
|
235 | ||||
|
236 | GistModel().delete(c.gist) | |||
|
237 | Session().commit() | |||
|
238 | h.flash(_('Deleted gist %s') % c.gist.gist_access_id, category='success') | |||
|
239 | ||||
|
240 | raise HTTPFound(h.route_url('gists_show')) | |||
|
241 | ||||
|
242 | def _get_gist(self, gist_id): | |||
|
243 | ||||
|
244 | gist = Gist.get_or_404(gist_id) | |||
|
245 | ||||
|
246 | # Check if this gist is expired | |||
|
247 | if gist.gist_expires != -1: | |||
|
248 | if time.time() > gist.gist_expires: | |||
|
249 | log.error( | |||
|
250 | 'Gist expired at %s', time_to_datetime(gist.gist_expires)) | |||
|
251 | raise HTTPNotFound() | |||
|
252 | ||||
|
253 | # check if this gist requires a login | |||
|
254 | is_default_user = self._rhodecode_user.username == User.DEFAULT_USER | |||
|
255 | if gist.acl_level == Gist.ACL_LEVEL_PRIVATE and is_default_user: | |||
|
256 | log.error("Anonymous user %s tried to access protected gist `%s`", | |||
|
257 | self._rhodecode_user, gist_id) | |||
|
258 | raise HTTPNotFound() | |||
|
259 | return gist | |||
|
260 | ||||
|
261 | @LoginRequired() | |||
|
262 | @view_config( | |||
|
263 | route_name='gist_show', request_method='GET', | |||
|
264 | renderer='rhodecode:templates/admin/gists/show.mako') | |||
|
265 | @view_config( | |||
|
266 | route_name='gist_show_rev', request_method='GET', | |||
|
267 | renderer='rhodecode:templates/admin/gists/show.mako') | |||
|
268 | @view_config( | |||
|
269 | route_name='gist_show_formatted', request_method='GET', | |||
|
270 | renderer=None) | |||
|
271 | @view_config( | |||
|
272 | route_name='gist_show_formatted_path', request_method='GET', | |||
|
273 | renderer=None) | |||
|
274 | def gist_show(self): | |||
|
275 | gist_id = self.request.matchdict['gist_id'] | |||
|
276 | ||||
|
277 | # TODO(marcink): expose those via matching dict | |||
|
278 | revision = self.request.matchdict.get('revision', 'tip') | |||
|
279 | f_path = self.request.matchdict.get('f_path', None) | |||
|
280 | return_format = self.request.matchdict.get('format') | |||
|
281 | ||||
|
282 | c = self.load_default_context() | |||
|
283 | c.gist = self._get_gist(gist_id) | |||
|
284 | c.render = not self.request.GET.get('no-render', False) | |||
|
285 | ||||
|
286 | try: | |||
|
287 | c.file_last_commit, c.files = GistModel().get_gist_files( | |||
|
288 | gist_id, revision=revision) | |||
|
289 | except VCSError: | |||
|
290 | log.exception("Exception in gist show") | |||
|
291 | raise HTTPNotFound() | |||
|
292 | ||||
|
293 | if return_format == 'raw': | |||
|
294 | content = '\n\n'.join([f.content for f in c.files | |||
|
295 | if (f_path is None or f.path == f_path)]) | |||
|
296 | response = Response(content) | |||
|
297 | response.content_type = 'text/plain' | |||
|
298 | return response | |||
|
299 | ||||
|
300 | return self._get_template_context(c) | |||
|
301 | ||||
|
302 | @LoginRequired() | |||
|
303 | @NotAnonymous() | |||
|
304 | @view_config( | |||
|
305 | route_name='gist_edit', request_method='GET', | |||
|
306 | renderer='rhodecode:templates/admin/gists/edit.mako') | |||
|
307 | def gist_edit(self): | |||
|
308 | _ = self.request.translate | |||
|
309 | gist_id = self.request.matchdict['gist_id'] | |||
|
310 | c = self.load_default_context() | |||
|
311 | c.gist = self._get_gist(gist_id) | |||
|
312 | ||||
|
313 | owner = c.gist.gist_owner == self._rhodecode_user.user_id | |||
|
314 | if not (h.HasPermissionAny('hg.admin')() or owner): | |||
|
315 | raise HTTPNotFound() | |||
|
316 | ||||
|
317 | try: | |||
|
318 | c.file_last_commit, c.files = GistModel().get_gist_files(gist_id) | |||
|
319 | except VCSError: | |||
|
320 | log.exception("Exception in gist edit") | |||
|
321 | raise HTTPNotFound() | |||
|
322 | ||||
|
323 | if c.gist.gist_expires == -1: | |||
|
324 | expiry = _('never') | |||
|
325 | else: | |||
|
326 | # this cannot use timeago, since it's used in select2 as a value | |||
|
327 | expiry = h.age(h.time_to_datetime(c.gist.gist_expires)) | |||
|
328 | ||||
|
329 | c.lifetime_values.append( | |||
|
330 | (0, _('%(expiry)s - current value') % {'expiry': _(expiry)}) | |||
|
331 | ) | |||
|
332 | ||||
|
333 | return self._get_template_context(c) | |||
|
334 | ||||
|
335 | @LoginRequired() | |||
|
336 | @NotAnonymous() | |||
|
337 | @CSRFRequired() | |||
|
338 | @view_config( | |||
|
339 | route_name='gist_update', request_method='POST', | |||
|
340 | renderer='rhodecode:templates/admin/gists/edit.mako') | |||
|
341 | def gist_update(self): | |||
|
342 | _ = self.request.translate | |||
|
343 | gist_id = self.request.matchdict['gist_id'] | |||
|
344 | c = self.load_default_context() | |||
|
345 | c.gist = self._get_gist(gist_id) | |||
|
346 | ||||
|
347 | owner = c.gist.gist_owner == self._rhodecode_user.user_id | |||
|
348 | if not (h.HasPermissionAny('hg.admin')() or owner): | |||
|
349 | raise HTTPNotFound() | |||
|
350 | ||||
|
351 | data = peppercorn.parse(self.request.POST.items()) | |||
|
352 | ||||
|
353 | schema = gist_schema.GistSchema() | |||
|
354 | schema = schema.bind( | |||
|
355 | # '0' is special value to leave lifetime untouched | |||
|
356 | lifetime_options=[x[0] for x in c.lifetime_values] + [0], | |||
|
357 | ) | |||
|
358 | ||||
|
359 | try: | |||
|
360 | schema_data = schema.deserialize(data) | |||
|
361 | # convert to safer format with just KEYs so we sure no duplicates | |||
|
362 | schema_data['nodes'] = gist_schema.sequence_to_nodes( | |||
|
363 | schema_data['nodes']) | |||
|
364 | ||||
|
365 | GistModel().update( | |||
|
366 | gist=c.gist, | |||
|
367 | description=schema_data['description'], | |||
|
368 | owner=c.gist.owner, | |||
|
369 | gist_mapping=schema_data['nodes'], | |||
|
370 | lifetime=schema_data['lifetime'], | |||
|
371 | gist_acl_level=schema_data['gist_acl_level'] | |||
|
372 | ) | |||
|
373 | ||||
|
374 | Session().commit() | |||
|
375 | h.flash(_('Successfully updated gist content'), category='success') | |||
|
376 | except NodeNotChangedError: | |||
|
377 | # raised if nothing was changed in repo itself. We anyway then | |||
|
378 | # store only DB stuff for gist | |||
|
379 | Session().commit() | |||
|
380 | h.flash(_('Successfully updated gist data'), category='success') | |||
|
381 | except validation_schema.Invalid as errors: | |||
|
382 | errors = h.escape(errors.asdict()) | |||
|
383 | h.flash(_('Error occurred during update of gist {}: {}').format( | |||
|
384 | gist_id, errors), category='error') | |||
|
385 | except Exception: | |||
|
386 | log.exception("Exception in gist edit") | |||
|
387 | h.flash(_('Error occurred during update of gist %s') % gist_id, | |||
|
388 | category='error') | |||
|
389 | ||||
|
390 | raise HTTPFound(h.route_url('gist_show', gist_id=gist_id)) | |||
|
391 | ||||
|
392 | @LoginRequired() | |||
|
393 | @NotAnonymous() | |||
|
394 | @view_config( | |||
|
395 | route_name='gist_edit_check_revision', request_method='GET', | |||
|
396 | renderer='json_ext') | |||
|
397 | def gist_edit_check_revision(self): | |||
|
398 | _ = self.request.translate | |||
|
399 | gist_id = self.request.matchdict['gist_id'] | |||
|
400 | c = self.load_default_context() | |||
|
401 | c.gist = self._get_gist(gist_id) | |||
|
402 | ||||
|
403 | last_rev = c.gist.scm_instance().get_commit() | |||
|
404 | success = True | |||
|
405 | revision = self.request.GET.get('revision') | |||
|
406 | ||||
|
407 | if revision != last_rev.raw_id: | |||
|
408 | log.error('Last revision %s is different then submitted %s' | |||
|
409 | % (revision, last_rev)) | |||
|
410 | # our gist has newer version than we | |||
|
411 | success = False | |||
|
412 | ||||
|
413 | return {'success': success} |
@@ -0,0 +1,53 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | ||||
|
22 | from rhodecode.apps._base import ADMIN_PREFIX | |||
|
23 | ||||
|
24 | ||||
|
25 | def admin_routes(config): | |||
|
26 | ||||
|
27 | config.add_route( | |||
|
28 | name='journal', pattern='/journal') | |||
|
29 | config.add_route( | |||
|
30 | name='journal_rss', pattern='/journal/rss') | |||
|
31 | config.add_route( | |||
|
32 | name='journal_atom', pattern='/journal/atom') | |||
|
33 | ||||
|
34 | config.add_route( | |||
|
35 | name='journal_public', pattern='/public_journal') | |||
|
36 | config.add_route( | |||
|
37 | name='journal_public_atom', pattern='/public_journal/atom') | |||
|
38 | config.add_route( | |||
|
39 | name='journal_public_atom_old', pattern='/public_journal_atom') | |||
|
40 | ||||
|
41 | config.add_route( | |||
|
42 | name='journal_public_rss', pattern='/public_journal/rss') | |||
|
43 | config.add_route( | |||
|
44 | name='journal_public_rss_old', pattern='/public_journal_rss') | |||
|
45 | ||||
|
46 | config.add_route( | |||
|
47 | name='toggle_following', pattern='/toggle_following') | |||
|
48 | ||||
|
49 | ||||
|
50 | def includeme(config): | |||
|
51 | config.include(admin_routes, route_prefix=ADMIN_PREFIX) | |||
|
52 | # Scan module for configuration decorators. | |||
|
53 | config.scan('.views', ignore='.tests') |
@@ -0,0 +1,19 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
@@ -0,0 +1,384 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2010-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | ||||
|
22 | import logging | |||
|
23 | import itertools | |||
|
24 | ||||
|
25 | from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed | |||
|
26 | ||||
|
27 | from pyramid.view import view_config | |||
|
28 | from pyramid.httpexceptions import HTTPBadRequest | |||
|
29 | from pyramid.response import Response | |||
|
30 | from pyramid.renderers import render | |||
|
31 | ||||
|
32 | from rhodecode.apps._base import BaseAppView | |||
|
33 | from rhodecode.model.db import ( | |||
|
34 | or_, joinedload, UserLog, UserFollowing, User, UserApiKeys) | |||
|
35 | from rhodecode.model.meta import Session | |||
|
36 | import rhodecode.lib.helpers as h | |||
|
37 | from rhodecode.lib.helpers import Page | |||
|
38 | from rhodecode.lib.user_log_filter import user_log_filter | |||
|
39 | from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired | |||
|
40 | from rhodecode.lib.utils2 import safe_int, AttributeDict, md5_safe | |||
|
41 | from rhodecode.model.scm import ScmModel | |||
|
42 | ||||
|
43 | log = logging.getLogger(__name__) | |||
|
44 | ||||
|
45 | ||||
|
46 | class JournalView(BaseAppView): | |||
|
47 | ||||
|
48 | def load_default_context(self): | |||
|
49 | c = self._get_local_tmpl_context(include_app_defaults=True) | |||
|
50 | self._register_global_c(c) | |||
|
51 | self._load_defaults(c.rhodecode_name) | |||
|
52 | ||||
|
53 | # TODO(marcink): what is this, why we need a global register ? | |||
|
54 | c.search_term = self.request.GET.get('filter') or '' | |||
|
55 | return c | |||
|
56 | ||||
|
57 | def _get_config(self, rhodecode_name): | |||
|
58 | import rhodecode | |||
|
59 | config = rhodecode.CONFIG | |||
|
60 | ||||
|
61 | return { | |||
|
62 | 'language': 'en-us', | |||
|
63 | 'feed_ttl': '5', # TTL of feed, | |||
|
64 | 'feed_items_per_page': | |||
|
65 | safe_int(config.get('rss_items_per_page', 20)), | |||
|
66 | 'rhodecode_name': rhodecode_name | |||
|
67 | } | |||
|
68 | ||||
|
69 | def _load_defaults(self, rhodecode_name): | |||
|
70 | config = self._get_config(rhodecode_name) | |||
|
71 | # common values for feeds | |||
|
72 | self.language = config["language"] | |||
|
73 | self.ttl = config["feed_ttl"] | |||
|
74 | self.feed_items_per_page = config['feed_items_per_page'] | |||
|
75 | self.rhodecode_name = config['rhodecode_name'] | |||
|
76 | ||||
|
77 | def _get_daily_aggregate(self, journal): | |||
|
78 | groups = [] | |||
|
79 | for k, g in itertools.groupby(journal, lambda x: x.action_as_day): | |||
|
80 | user_group = [] | |||
|
81 | # groupby username if it's a present value, else | |||
|
82 | # fallback to journal username | |||
|
83 | for _, g2 in itertools.groupby( | |||
|
84 | list(g), lambda x: x.user.username if x.user else x.username): | |||
|
85 | l = list(g2) | |||
|
86 | user_group.append((l[0].user, l)) | |||
|
87 | ||||
|
88 | groups.append((k, user_group,)) | |||
|
89 | ||||
|
90 | return groups | |||
|
91 | ||||
|
92 | def _get_journal_data(self, following_repos, search_term): | |||
|
93 | repo_ids = [x.follows_repository.repo_id for x in following_repos | |||
|
94 | if x.follows_repository is not None] | |||
|
95 | user_ids = [x.follows_user.user_id for x in following_repos | |||
|
96 | if x.follows_user is not None] | |||
|
97 | ||||
|
98 | filtering_criterion = None | |||
|
99 | ||||
|
100 | if repo_ids and user_ids: | |||
|
101 | filtering_criterion = or_(UserLog.repository_id.in_(repo_ids), | |||
|
102 | UserLog.user_id.in_(user_ids)) | |||
|
103 | if repo_ids and not user_ids: | |||
|
104 | filtering_criterion = UserLog.repository_id.in_(repo_ids) | |||
|
105 | if not repo_ids and user_ids: | |||
|
106 | filtering_criterion = UserLog.user_id.in_(user_ids) | |||
|
107 | if filtering_criterion is not None: | |||
|
108 | journal = Session().query(UserLog)\ | |||
|
109 | .options(joinedload(UserLog.user))\ | |||
|
110 | .options(joinedload(UserLog.repository)) | |||
|
111 | # filter | |||
|
112 | try: | |||
|
113 | journal = user_log_filter(journal, search_term) | |||
|
114 | except Exception: | |||
|
115 | # we want this to crash for now | |||
|
116 | raise | |||
|
117 | journal = journal.filter(filtering_criterion)\ | |||
|
118 | .order_by(UserLog.action_date.desc()) | |||
|
119 | else: | |||
|
120 | journal = [] | |||
|
121 | ||||
|
122 | return journal | |||
|
123 | ||||
|
124 | def feed_uid(self, entry_id): | |||
|
125 | return '{}:{}'.format('journal', md5_safe(entry_id)) | |||
|
126 | ||||
|
127 | def _atom_feed(self, repos, search_term, public=True): | |||
|
128 | _ = self.request.translate | |||
|
129 | journal = self._get_journal_data(repos, search_term) | |||
|
130 | if public: | |||
|
131 | _link = h.route_url('journal_public_atom') | |||
|
132 | _desc = '%s %s %s' % (self.rhodecode_name, _('public journal'), | |||
|
133 | 'atom feed') | |||
|
134 | else: | |||
|
135 | _link = h.route_url('journal_atom') | |||
|
136 | _desc = '%s %s %s' % (self.rhodecode_name, _('journal'), 'atom feed') | |||
|
137 | ||||
|
138 | feed = Atom1Feed( | |||
|
139 | title=_desc, link=_link, description=_desc, | |||
|
140 | language=self.language, ttl=self.ttl) | |||
|
141 | ||||
|
142 | for entry in journal[:self.feed_items_per_page]: | |||
|
143 | user = entry.user | |||
|
144 | if user is None: | |||
|
145 | # fix deleted users | |||
|
146 | user = AttributeDict({'short_contact': entry.username, | |||
|
147 | 'email': '', | |||
|
148 | 'full_contact': ''}) | |||
|
149 | action, action_extra, ico = h.action_parser(entry, feed=True) | |||
|
150 | title = "%s - %s %s" % (user.short_contact, action(), | |||
|
151 | entry.repository.repo_name) | |||
|
152 | desc = action_extra() | |||
|
153 | _url = h.route_url('home') | |||
|
154 | if entry.repository is not None: | |||
|
155 | _url = h.route_url('repo_changelog', | |||
|
156 | repo_name=entry.repository.repo_name) | |||
|
157 | ||||
|
158 | feed.add_item( | |||
|
159 | unique_id=self.feed_uid(entry.user_log_id), | |||
|
160 | title=title, | |||
|
161 | pubdate=entry.action_date, | |||
|
162 | link=_url, | |||
|
163 | author_email=user.email, | |||
|
164 | author_name=user.full_contact, | |||
|
165 | description=desc) | |||
|
166 | ||||
|
167 | response = Response(feed.writeString('utf-8')) | |||
|
168 | response.content_type = feed.mime_type | |||
|
169 | return response | |||
|
170 | ||||
|
171 | def _rss_feed(self, repos, search_term, public=True): | |||
|
172 | _ = self.request.translate | |||
|
173 | journal = self._get_journal_data(repos, search_term) | |||
|
174 | if public: | |||
|
175 | _link = h.route_url('journal_public_atom') | |||
|
176 | _desc = '%s %s %s' % ( | |||
|
177 | self.rhodecode_name, _('public journal'), 'rss feed') | |||
|
178 | else: | |||
|
179 | _link = h.route_url('journal_atom') | |||
|
180 | _desc = '%s %s %s' % ( | |||
|
181 | self.rhodecode_name, _('journal'), 'rss feed') | |||
|
182 | ||||
|
183 | feed = Rss201rev2Feed( | |||
|
184 | title=_desc, link=_link, description=_desc, | |||
|
185 | language=self.language, ttl=self.ttl) | |||
|
186 | ||||
|
187 | for entry in journal[:self.feed_items_per_page]: | |||
|
188 | user = entry.user | |||
|
189 | if user is None: | |||
|
190 | # fix deleted users | |||
|
191 | user = AttributeDict({'short_contact': entry.username, | |||
|
192 | 'email': '', | |||
|
193 | 'full_contact': ''}) | |||
|
194 | action, action_extra, ico = h.action_parser(entry, feed=True) | |||
|
195 | title = "%s - %s %s" % (user.short_contact, action(), | |||
|
196 | entry.repository.repo_name) | |||
|
197 | desc = action_extra() | |||
|
198 | _url = h.route_url('home') | |||
|
199 | if entry.repository is not None: | |||
|
200 | _url = h.route_url('repo_changelog', | |||
|
201 | repo_name=entry.repository.repo_name) | |||
|
202 | ||||
|
203 | feed.add_item( | |||
|
204 | unique_id=self.feed_uid(entry.user_log_id), | |||
|
205 | title=title, | |||
|
206 | pubdate=entry.action_date, | |||
|
207 | link=_url, | |||
|
208 | author_email=user.email, | |||
|
209 | author_name=user.full_contact, | |||
|
210 | description=desc) | |||
|
211 | ||||
|
212 | response = Response(feed.writeString('utf-8')) | |||
|
213 | response.content_type = feed.mime_type | |||
|
214 | return response | |||
|
215 | ||||
|
216 | @LoginRequired() | |||
|
217 | @NotAnonymous() | |||
|
218 | @view_config( | |||
|
219 | route_name='journal', request_method='GET', | |||
|
220 | renderer=None) | |||
|
221 | def journal(self): | |||
|
222 | c = self.load_default_context() | |||
|
223 | ||||
|
224 | p = safe_int(self.request.GET.get('page', 1), 1) | |||
|
225 | c.user = User.get(self._rhodecode_user.user_id) | |||
|
226 | following = Session().query(UserFollowing)\ | |||
|
227 | .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\ | |||
|
228 | .options(joinedload(UserFollowing.follows_repository))\ | |||
|
229 | .all() | |||
|
230 | ||||
|
231 | journal = self._get_journal_data(following, c.search_term) | |||
|
232 | ||||
|
233 | def url_generator(**kw): | |||
|
234 | query_params = { | |||
|
235 | 'filter': c.search_term | |||
|
236 | } | |||
|
237 | query_params.update(kw) | |||
|
238 | return self.request.current_route_path(_query=query_params) | |||
|
239 | ||||
|
240 | c.journal_pager = Page( | |||
|
241 | journal, page=p, items_per_page=20, url=url_generator) | |||
|
242 | c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager) | |||
|
243 | ||||
|
244 | c.journal_data = render( | |||
|
245 | 'rhodecode:templates/journal/journal_data.mako', | |||
|
246 | self._get_template_context(c), self.request) | |||
|
247 | ||||
|
248 | if self.request.is_xhr: | |||
|
249 | return Response(c.journal_data) | |||
|
250 | ||||
|
251 | html = render( | |||
|
252 | 'rhodecode:templates/journal/journal.mako', | |||
|
253 | self._get_template_context(c), self.request) | |||
|
254 | return Response(html) | |||
|
255 | ||||
|
256 | @LoginRequired(auth_token_access=[UserApiKeys.ROLE_FEED]) | |||
|
257 | @NotAnonymous() | |||
|
258 | @view_config( | |||
|
259 | route_name='journal_atom', request_method='GET', | |||
|
260 | renderer=None) | |||
|
261 | def journal_atom(self): | |||
|
262 | """ | |||
|
263 | Produce an atom-1.0 feed via feedgenerator module | |||
|
264 | """ | |||
|
265 | c = self.load_default_context() | |||
|
266 | following_repos = Session().query(UserFollowing)\ | |||
|
267 | .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\ | |||
|
268 | .options(joinedload(UserFollowing.follows_repository))\ | |||
|
269 | .all() | |||
|
270 | return self._atom_feed(following_repos, c.search_term, public=False) | |||
|
271 | ||||
|
272 | @LoginRequired(auth_token_access=[UserApiKeys.ROLE_FEED]) | |||
|
273 | @NotAnonymous() | |||
|
274 | @view_config( | |||
|
275 | route_name='journal_rss', request_method='GET', | |||
|
276 | renderer=None) | |||
|
277 | def journal_rss(self): | |||
|
278 | """ | |||
|
279 | Produce an rss feed via feedgenerator module | |||
|
280 | """ | |||
|
281 | c = self.load_default_context() | |||
|
282 | following_repos = Session().query(UserFollowing)\ | |||
|
283 | .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\ | |||
|
284 | .options(joinedload(UserFollowing.follows_repository))\ | |||
|
285 | .all() | |||
|
286 | return self._rss_feed(following_repos, c.search_term, public=False) | |||
|
287 | ||||
|
288 | @LoginRequired() | |||
|
289 | @NotAnonymous() | |||
|
290 | @CSRFRequired() | |||
|
291 | @view_config( | |||
|
292 | route_name='toggle_following', request_method='POST', | |||
|
293 | renderer='json_ext') | |||
|
294 | def toggle_following(self): | |||
|
295 | user_id = self.request.POST.get('follows_user_id') | |||
|
296 | if user_id: | |||
|
297 | try: | |||
|
298 | ScmModel().toggle_following_user( | |||
|
299 | user_id, self._rhodecode_user.user_id) | |||
|
300 | Session().commit() | |||
|
301 | return 'ok' | |||
|
302 | except Exception: | |||
|
303 | raise HTTPBadRequest() | |||
|
304 | ||||
|
305 | repo_id = self.request.POST.get('follows_repo_id') | |||
|
306 | if repo_id: | |||
|
307 | try: | |||
|
308 | ScmModel().toggle_following_repo( | |||
|
309 | repo_id, self._rhodecode_user.user_id) | |||
|
310 | Session().commit() | |||
|
311 | return 'ok' | |||
|
312 | except Exception: | |||
|
313 | raise HTTPBadRequest() | |||
|
314 | ||||
|
315 | raise HTTPBadRequest() | |||
|
316 | ||||
|
317 | @LoginRequired() | |||
|
318 | @view_config( | |||
|
319 | route_name='journal_public', request_method='GET', | |||
|
320 | renderer=None) | |||
|
321 | def journal_public(self): | |||
|
322 | c = self.load_default_context() | |||
|
323 | # Return a rendered template | |||
|
324 | p = safe_int(self.request.GET.get('page', 1), 1) | |||
|
325 | ||||
|
326 | c.following = Session().query(UserFollowing)\ | |||
|
327 | .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\ | |||
|
328 | .options(joinedload(UserFollowing.follows_repository))\ | |||
|
329 | .all() | |||
|
330 | ||||
|
331 | journal = self._get_journal_data(c.following, c.search_term) | |||
|
332 | ||||
|
333 | def url_generator(**kw): | |||
|
334 | query_params = {} | |||
|
335 | query_params.update(kw) | |||
|
336 | return self.request.current_route_path(_query=query_params) | |||
|
337 | ||||
|
338 | c.journal_pager = Page( | |||
|
339 | journal, page=p, items_per_page=20, url=url_generator) | |||
|
340 | c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager) | |||
|
341 | ||||
|
342 | c.journal_data = render( | |||
|
343 | 'rhodecode:templates/journal/journal_data.mako', | |||
|
344 | self._get_template_context(c), self.request) | |||
|
345 | ||||
|
346 | if self.request.is_xhr: | |||
|
347 | return Response(c.journal_data) | |||
|
348 | ||||
|
349 | html = render( | |||
|
350 | 'rhodecode:templates/journal/public_journal.mako', | |||
|
351 | self._get_template_context(c), self.request) | |||
|
352 | return Response(html) | |||
|
353 | ||||
|
354 | @LoginRequired(auth_token_access=[UserApiKeys.ROLE_FEED]) | |||
|
355 | @view_config( | |||
|
356 | route_name='journal_public_atom', request_method='GET', | |||
|
357 | renderer=None) | |||
|
358 | def journal_public_atom(self): | |||
|
359 | """ | |||
|
360 | Produce an atom-1.0 feed via feedgenerator module | |||
|
361 | """ | |||
|
362 | c = self.load_default_context() | |||
|
363 | following_repos = Session().query(UserFollowing)\ | |||
|
364 | .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\ | |||
|
365 | .options(joinedload(UserFollowing.follows_repository))\ | |||
|
366 | .all() | |||
|
367 | ||||
|
368 | return self._atom_feed(following_repos, c.search_term) | |||
|
369 | ||||
|
370 | @LoginRequired(auth_token_access=[UserApiKeys.ROLE_FEED]) | |||
|
371 | @view_config( | |||
|
372 | route_name='journal_public_rss', request_method='GET', | |||
|
373 | renderer=None) | |||
|
374 | def journal_public_rss(self): | |||
|
375 | """ | |||
|
376 | Produce an rss2 feed via feedgenerator module | |||
|
377 | """ | |||
|
378 | c = self.load_default_context() | |||
|
379 | following_repos = Session().query(UserFollowing)\ | |||
|
380 | .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\ | |||
|
381 | .options(joinedload(UserFollowing.follows_repository))\ | |||
|
382 | .all() | |||
|
383 | ||||
|
384 | return self._rss_feed(following_repos, c.search_term) |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: new file 100644 |
|
NO CONTENT: new file 100644 | ||
The requested commit or file is too big and content was truncated. Show full diff |
@@ -1,5 +1,5 b'' | |||||
1 | [bumpversion] |
|
1 | [bumpversion] | |
2 |
current_version = 4. |
|
2 | current_version = 4.10.0 | |
3 | message = release: Bump version {current_version} to {new_version} |
|
3 | message = release: Bump version {current_version} to {new_version} | |
4 |
|
4 | |||
5 | [bumpversion:file:rhodecode/VERSION] |
|
5 | [bumpversion:file:rhodecode/VERSION] |
@@ -5,25 +5,20 b' done = false' | |||||
5 | done = true |
|
5 | done = true | |
6 |
|
6 | |||
7 | [task:rc_tools_pinned] |
|
7 | [task:rc_tools_pinned] | |
8 | done = true |
|
|||
9 |
|
8 | |||
10 | [task:fixes_on_stable] |
|
9 | [task:fixes_on_stable] | |
11 | done = true |
|
|||
12 |
|
10 | |||
13 | [task:pip2nix_generated] |
|
11 | [task:pip2nix_generated] | |
14 | done = true |
|
|||
15 |
|
12 | |||
16 | [task:changelog_updated] |
|
13 | [task:changelog_updated] | |
17 | done = true |
|
|||
18 |
|
14 | |||
19 | [task:generate_api_docs] |
|
15 | [task:generate_api_docs] | |
20 | done = true |
|
16 | ||
|
17 | [task:updated_translation] | |||
21 |
|
18 | |||
22 | [release] |
|
19 | [release] | |
23 |
state = |
|
20 | state = in_progress | |
24 |
version = 4. |
|
21 | version = 4.10.0 | |
25 |
|
||||
26 | [task:updated_translation] |
|
|||
27 |
|
22 | |||
28 | [task:generate_js_routes] |
|
23 | [task:generate_js_routes] | |
29 |
|
24 |
@@ -1,5 +1,5 b'' | |||||
1 |
|
1 | |||
2 | .PHONY: clean docs docs-clean docs-cleanup test test-clean test-only web-build |
|
2 | .PHONY: clean docs docs-clean docs-cleanup test test-clean test-only test-only-postgres test-only-mysql web-build | |
3 |
|
3 | |||
4 | WEBPACK=./node_modules/webpack/bin/webpack.js |
|
4 | WEBPACK=./node_modules/webpack/bin/webpack.js | |
5 | GRUNT=grunt |
|
5 | GRUNT=grunt | |
@@ -19,7 +19,25 b' test-clean:' | |||||
19 | find . -type d -name "__pycache__" -prune -exec rm -rf '{}' ';' |
|
19 | find . -type d -name "__pycache__" -prune -exec rm -rf '{}' ';' | |
20 |
|
20 | |||
21 | test-only: |
|
21 | test-only: | |
22 | PYTHONHASHSEED=random py.test -vv -r xw --cov=rhodecode --cov-report=term-missing --cov-report=html rhodecode |
|
22 | PYTHONHASHSEED=random \ | |
|
23 | py.test -x -vv -r xw -p no:sugar --cov=rhodecode \ | |||
|
24 | --cov-report=term-missing --cov-report=html \ | |||
|
25 | rhodecode | |||
|
26 | ||||
|
27 | test-only-mysql: | |||
|
28 | PYTHONHASHSEED=random \ | |||
|
29 | py.test -x -vv -r xw -p no:sugar --cov=rhodecode \ | |||
|
30 | --cov-report=term-missing --cov-report=html \ | |||
|
31 | --ini-config-override='{"app:main": {"sqlalchemy.db1.url": "mysql://root:qweqwe@localhost/rhodecode_test"}}' \ | |||
|
32 | rhodecode | |||
|
33 | ||||
|
34 | test-only-postgres: | |||
|
35 | PYTHONHASHSEED=random \ | |||
|
36 | py.test -x -vv -r xw -p no:sugar --cov=rhodecode \ | |||
|
37 | --cov-report=term-missing --cov-report=html \ | |||
|
38 | --ini-config-override='{"app:main": {"sqlalchemy.db1.url": "postgresql://postgres:qweqwe@localhost/rhodecode_test"}}' \ | |||
|
39 | rhodecode | |||
|
40 | ||||
23 |
|
41 | |||
24 | docs: |
|
42 | docs: | |
25 | (cd docs; nix-build default.nix -o result; make clean html) |
|
43 | (cd docs; nix-build default.nix -o result; make clean html) |
@@ -73,7 +73,7 b' asyncore_use_poll = true' | |||||
73 | ## The `instance_id = *` must be set in the [app:main] section below |
|
73 | ## The `instance_id = *` must be set in the [app:main] section below | |
74 | #workers = 2 |
|
74 | #workers = 2 | |
75 | ## number of threads for each of the worker, must be set to 1 for gevent |
|
75 | ## number of threads for each of the worker, must be set to 1 for gevent | |
76 | ## generally recommened to be at 1 |
|
76 | ## generally recommended to be at 1 | |
77 | #threads = 1 |
|
77 | #threads = 1 | |
78 | ## process name |
|
78 | ## process name | |
79 | #proc_name = rhodecode |
|
79 | #proc_name = rhodecode | |
@@ -111,7 +111,6 b' use = egg:rhodecode-enterprise-ce' | |||||
111 | # During development the we want to have the debug toolbar enabled |
|
111 | # During development the we want to have the debug toolbar enabled | |
112 | pyramid.includes = |
|
112 | pyramid.includes = | |
113 | pyramid_debugtoolbar |
|
113 | pyramid_debugtoolbar | |
114 | rhodecode.utils.debugtoolbar |
|
|||
115 | rhodecode.lib.middleware.request_wrapper |
|
114 | rhodecode.lib.middleware.request_wrapper | |
116 |
|
115 | |||
117 | pyramid.reload_templates = true |
|
116 | pyramid.reload_templates = true | |
@@ -163,12 +162,23 b' startup.import_repos = false' | |||||
163 | ## the repository. |
|
162 | ## the repository. | |
164 | #archive_cache_dir = /tmp/tarballcache |
|
163 | #archive_cache_dir = /tmp/tarballcache | |
165 |
|
164 | |||
|
165 | ## URL at which the application is running. This is used for bootstraping | |||
|
166 | ## requests in context when no web request is available. Used in ishell, or | |||
|
167 | ## SSH calls. Set this for events to receive proper url for SSH calls. | |||
|
168 | app.base_url = http://rhodecode.local | |||
|
169 | ||||
166 | ## change this to unique ID for security |
|
170 | ## change this to unique ID for security | |
167 | app_instance_uuid = rc-production |
|
171 | app_instance_uuid = rc-production | |
168 |
|
172 | |||
169 | ## cut off limit for large diffs (size in bytes) |
|
173 | ## cut off limit for large diffs (size in bytes). If overall diff size on | |
170 | cut_off_limit_diff = 1024000 |
|
174 | ## commit, or pull request exceeds this limit this diff will be displayed | |
171 | cut_off_limit_file = 256000 |
|
175 | ## partially. E.g 512000 == 512Kb | |
|
176 | cut_off_limit_diff = 512000 | |||
|
177 | ||||
|
178 | ## cut off limit for large files inside diffs (size in bytes). Each individual | |||
|
179 | ## file inside diff which exceeds this limit will be displayed partially. | |||
|
180 | ## E.g 128000 == 128Kb | |||
|
181 | cut_off_limit_file = 128000 | |||
172 |
|
182 | |||
173 | ## use cache version of scm repo everywhere |
|
183 | ## use cache version of scm repo everywhere | |
174 | vcs_full_cache = true |
|
184 | vcs_full_cache = true | |
@@ -201,22 +211,26 b' rss_include_diff = false' | |||||
201 | ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid} |
|
211 | ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid} | |
202 | gist_alias_url = |
|
212 | gist_alias_url = | |
203 |
|
213 | |||
204 |
## List of |
|
214 | ## List of views (using glob pattern syntax) that AUTH TOKENS could be | |
205 | ## used for access. |
|
215 | ## used for access. | |
206 | ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it |
|
216 | ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it | |
207 | ## came from the the logged in user who own this authentication token. |
|
217 | ## came from the the logged in user who own this authentication token. | |
|
218 | ## Additionally @TOKEN syntaxt can be used to bound the view to specific | |||
|
219 | ## authentication token. Such view would be only accessible when used together | |||
|
220 | ## with this authentication token | |||
208 | ## |
|
221 | ## | |
209 | ## Syntax is ControllerClass:function_pattern. |
|
222 | ## list of all views can be found under `/_admin/permissions/auth_token_access` | |
210 | ## To enable access to raw_files put `FilesController:raw`. |
|
|||
211 | ## To enable access to patches add `ChangesetController:changeset_patch`. |
|
|||
212 | ## The list should be "," separated and on a single line. |
|
223 | ## The list should be "," separated and on a single line. | |
213 | ## |
|
224 | ## | |
214 |
## |
|
225 | ## Most common views to enable: | |
215 | # ChangesetController:changeset_patch, |
|
226 | # RepoCommitsView:repo_commit_download | |
216 | # ChangesetController:changeset_raw, |
|
227 | # RepoCommitsView:repo_commit_patch | |
217 | # FilesController:raw, |
|
228 | # RepoCommitsView:repo_commit_raw | |
218 | # FilesController:archivefile, |
|
229 | # RepoCommitsView:repo_commit_raw@TOKEN | |
219 | # GistsController:*, |
|
230 | # RepoFilesView:repo_files_diff | |
|
231 | # RepoFilesView:repo_archivefile | |||
|
232 | # RepoFilesView:repo_file_raw | |||
|
233 | # GistView:* | |||
220 | api_access_controllers_whitelist = |
|
234 | api_access_controllers_whitelist = | |
221 |
|
235 | |||
222 | ## default encoding used to convert from and to unicode |
|
236 | ## default encoding used to convert from and to unicode | |
@@ -563,7 +577,7 b' vcs.backends = hg, git, svn' | |||||
563 |
|
577 | |||
564 | vcs.connection_timeout = 3600 |
|
578 | vcs.connection_timeout = 3600 | |
565 | ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out. |
|
579 | ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out. | |
566 | ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible |
|
580 | ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible | |
567 | #vcs.svn.compatible_version = pre-1.8-compatible |
|
581 | #vcs.svn.compatible_version = pre-1.8-compatible | |
568 |
|
582 | |||
569 |
|
583 | |||
@@ -577,6 +591,8 b' svn.proxy.generate_config = false' | |||||
577 | svn.proxy.list_parent_path = true |
|
591 | svn.proxy.list_parent_path = true | |
578 | ## Set location and file name of generated config file. |
|
592 | ## Set location and file name of generated config file. | |
579 | svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf |
|
593 | svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf | |
|
594 | ## alternative mod_dav config template. This needs to be a mako template | |||
|
595 | #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako | |||
580 | ## Used as a prefix to the `Location` block in the generated config file. |
|
596 | ## Used as a prefix to the `Location` block in the generated config file. | |
581 | ## In most cases it should be set to `/`. |
|
597 | ## In most cases it should be set to `/`. | |
582 | svn.proxy.location_root = / |
|
598 | svn.proxy.location_root = / | |
@@ -587,6 +603,43 b' svn.proxy.location_root = /' | |||||
587 | ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds. |
|
603 | ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds. | |
588 | #svn.proxy.reload_timeout = 10 |
|
604 | #svn.proxy.reload_timeout = 10 | |
589 |
|
605 | |||
|
606 | ############################################################ | |||
|
607 | ### SSH Support Settings ### | |||
|
608 | ############################################################ | |||
|
609 | ||||
|
610 | ## Defines if a custom authorized_keys file should be created and written on | |||
|
611 | ## any change user ssh keys. Setting this to false also disables posibility | |||
|
612 | ## of adding SSH keys by users from web interface. Super admins can still | |||
|
613 | ## manage SSH Keys. | |||
|
614 | ssh.generate_authorized_keyfile = false | |||
|
615 | ||||
|
616 | ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding` | |||
|
617 | # ssh.authorized_keys_ssh_opts = | |||
|
618 | ||||
|
619 | ## Path to the authrozied_keys file where the generate entries are placed. | |||
|
620 | ## It is possible to have multiple key files specified in `sshd_config` e.g. | |||
|
621 | ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode | |||
|
622 | ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode | |||
|
623 | ||||
|
624 | ## Command to execute the SSH wrapper. The binary is available in the | |||
|
625 | ## rhodecode installation directory. | |||
|
626 | ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper | |||
|
627 | ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper | |||
|
628 | ||||
|
629 | ## Allow shell when executing the ssh-wrapper command | |||
|
630 | ssh.wrapper_cmd_allow_shell = false | |||
|
631 | ||||
|
632 | ## Enables logging, and detailed output send back to the client during SSH | |||
|
633 | ## operations. Usefull for debugging, shouldn't be used in production. | |||
|
634 | ssh.enable_debug_logging = true | |||
|
635 | ||||
|
636 | ## Paths to binary executable, by default they are the names, but we can | |||
|
637 | ## override them if we want to use a custom one | |||
|
638 | ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg | |||
|
639 | ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git | |||
|
640 | ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve | |||
|
641 | ||||
|
642 | ||||
590 | ## Dummy marker to add new entries after. |
|
643 | ## Dummy marker to add new entries after. | |
591 | ## Add any custom entries below. Please don't remove. |
|
644 | ## Add any custom entries below. Please don't remove. | |
592 | custom.conf = 1 |
|
645 | custom.conf = 1 | |
@@ -596,7 +649,7 b' custom.conf = 1' | |||||
596 | ### LOGGING CONFIGURATION #### |
|
649 | ### LOGGING CONFIGURATION #### | |
597 | ################################ |
|
650 | ################################ | |
598 | [loggers] |
|
651 | [loggers] | |
599 |
keys = root, |
|
652 | keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper | |
600 |
|
653 | |||
601 | [handlers] |
|
654 | [handlers] | |
602 | keys = console, console_sql |
|
655 | keys = console, console_sql | |
@@ -611,12 +664,11 b' keys = generic, color_formatter, color_f' | |||||
611 | level = NOTSET |
|
664 | level = NOTSET | |
612 | handlers = console |
|
665 | handlers = console | |
613 |
|
666 | |||
614 | [logger_routes] |
|
667 | [logger_sqlalchemy] | |
615 |
level = |
|
668 | level = INFO | |
616 | handlers = |
|
669 | handlers = console_sql | |
617 | qualname = routes.middleware |
|
670 | qualname = sqlalchemy.engine | |
618 | ## "level = DEBUG" logs the route matched and routing variables. |
|
671 | propagate = 0 | |
619 | propagate = 1 |
|
|||
620 |
|
672 | |||
621 | [logger_beaker] |
|
673 | [logger_beaker] | |
622 | level = DEBUG |
|
674 | level = DEBUG | |
@@ -624,23 +676,18 b' handlers =' | |||||
624 | qualname = beaker.container |
|
676 | qualname = beaker.container | |
625 | propagate = 1 |
|
677 | propagate = 1 | |
626 |
|
678 | |||
627 | [logger_templates] |
|
|||
628 | level = INFO |
|
|||
629 | handlers = |
|
|||
630 | qualname = pylons.templating |
|
|||
631 | propagate = 1 |
|
|||
632 |
|
||||
633 | [logger_rhodecode] |
|
679 | [logger_rhodecode] | |
634 | level = DEBUG |
|
680 | level = DEBUG | |
635 | handlers = |
|
681 | handlers = | |
636 | qualname = rhodecode |
|
682 | qualname = rhodecode | |
637 | propagate = 1 |
|
683 | propagate = 1 | |
638 |
|
684 | |||
639 |
[logger_s |
|
685 | [logger_ssh_wrapper] | |
640 |
level = |
|
686 | level = DEBUG | |
641 |
handlers = |
|
687 | handlers = | |
642 | qualname = sqlalchemy.engine |
|
688 | qualname = ssh_wrapper | |
643 |
propagate = |
|
689 | propagate = 1 | |
|
690 | ||||
644 |
|
691 | |||
645 | ############## |
|
692 | ############## | |
646 | ## HANDLERS ## |
|
693 | ## HANDLERS ## |
@@ -15,8 +15,11 b' available post the .ini config.' | |||||
15 |
|
15 | |||
16 | import multiprocessing |
|
16 | import multiprocessing | |
17 | import sys |
|
17 | import sys | |
|
18 | import time | |||
|
19 | import datetime | |||
18 | import threading |
|
20 | import threading | |
19 | import traceback |
|
21 | import traceback | |
|
22 | from gunicorn.glogging import Logger | |||
20 |
|
23 | |||
21 |
|
24 | |||
22 | # GLOBAL |
|
25 | # GLOBAL | |
@@ -87,4 +90,24 b' def pre_request(worker, req):' | |||||
87 | def post_request(worker, req, environ, resp): |
|
90 | def post_request(worker, req, environ, resp): | |
88 | return |
|
91 | return | |
89 | worker.log.debug("[<%-10s>] POST WORKER: %s %s resp: %s", worker.pid, |
|
92 | worker.log.debug("[<%-10s>] POST WORKER: %s %s resp: %s", worker.pid, | |
90 | req.method, req.path, resp.status_code) No newline at end of file |
|
93 | req.method, req.path, resp.status_code) | |
|
94 | ||||
|
95 | ||||
|
96 | class RhodeCodeLogger(Logger): | |||
|
97 | """ | |||
|
98 | Custom Logger that allows some customization that gunicorn doesn't allow | |||
|
99 | """ | |||
|
100 | ||||
|
101 | datefmt = r"%Y-%m-%d %H:%M:%S" | |||
|
102 | ||||
|
103 | def __init__(self, cfg): | |||
|
104 | Logger.__init__(self, cfg) | |||
|
105 | ||||
|
106 | def now(self): | |||
|
107 | """ return date in RhodeCode Log format """ | |||
|
108 | now = time.time() | |||
|
109 | msecs = int((now - long(now)) * 1000) | |||
|
110 | return time.strftime(self.datefmt, time.localtime(now)) + '.{0:03d}'.format(msecs) | |||
|
111 | ||||
|
112 | ||||
|
113 | logger_class = RhodeCodeLogger |
@@ -73,7 +73,7 b' use = egg:gunicorn#main' | |||||
73 | ## The `instance_id = *` must be set in the [app:main] section below |
|
73 | ## The `instance_id = *` must be set in the [app:main] section below | |
74 | workers = 2 |
|
74 | workers = 2 | |
75 | ## number of threads for each of the worker, must be set to 1 for gevent |
|
75 | ## number of threads for each of the worker, must be set to 1 for gevent | |
76 | ## generally recommened to be at 1 |
|
76 | ## generally recommended to be at 1 | |
77 | #threads = 1 |
|
77 | #threads = 1 | |
78 | ## process name |
|
78 | ## process name | |
79 | proc_name = rhodecode |
|
79 | proc_name = rhodecode | |
@@ -137,12 +137,23 b' startup.import_repos = false' | |||||
137 | ## the repository. |
|
137 | ## the repository. | |
138 | #archive_cache_dir = /tmp/tarballcache |
|
138 | #archive_cache_dir = /tmp/tarballcache | |
139 |
|
139 | |||
|
140 | ## URL at which the application is running. This is used for bootstraping | |||
|
141 | ## requests in context when no web request is available. Used in ishell, or | |||
|
142 | ## SSH calls. Set this for events to receive proper url for SSH calls. | |||
|
143 | app.base_url = http://rhodecode.local | |||
|
144 | ||||
140 | ## change this to unique ID for security |
|
145 | ## change this to unique ID for security | |
141 | app_instance_uuid = rc-production |
|
146 | app_instance_uuid = rc-production | |
142 |
|
147 | |||
143 | ## cut off limit for large diffs (size in bytes) |
|
148 | ## cut off limit for large diffs (size in bytes). If overall diff size on | |
144 | cut_off_limit_diff = 1024000 |
|
149 | ## commit, or pull request exceeds this limit this diff will be displayed | |
145 | cut_off_limit_file = 256000 |
|
150 | ## partially. E.g 512000 == 512Kb | |
|
151 | cut_off_limit_diff = 512000 | |||
|
152 | ||||
|
153 | ## cut off limit for large files inside diffs (size in bytes). Each individual | |||
|
154 | ## file inside diff which exceeds this limit will be displayed partially. | |||
|
155 | ## E.g 128000 == 128Kb | |||
|
156 | cut_off_limit_file = 128000 | |||
146 |
|
157 | |||
147 | ## use cache version of scm repo everywhere |
|
158 | ## use cache version of scm repo everywhere | |
148 | vcs_full_cache = true |
|
159 | vcs_full_cache = true | |
@@ -175,22 +186,26 b' rss_include_diff = false' | |||||
175 | ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid} |
|
186 | ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid} | |
176 | gist_alias_url = |
|
187 | gist_alias_url = | |
177 |
|
188 | |||
178 |
## List of |
|
189 | ## List of views (using glob pattern syntax) that AUTH TOKENS could be | |
179 | ## used for access. |
|
190 | ## used for access. | |
180 | ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it |
|
191 | ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it | |
181 | ## came from the the logged in user who own this authentication token. |
|
192 | ## came from the the logged in user who own this authentication token. | |
|
193 | ## Additionally @TOKEN syntaxt can be used to bound the view to specific | |||
|
194 | ## authentication token. Such view would be only accessible when used together | |||
|
195 | ## with this authentication token | |||
182 | ## |
|
196 | ## | |
183 | ## Syntax is ControllerClass:function_pattern. |
|
197 | ## list of all views can be found under `/_admin/permissions/auth_token_access` | |
184 | ## To enable access to raw_files put `FilesController:raw`. |
|
|||
185 | ## To enable access to patches add `ChangesetController:changeset_patch`. |
|
|||
186 | ## The list should be "," separated and on a single line. |
|
198 | ## The list should be "," separated and on a single line. | |
187 | ## |
|
199 | ## | |
188 |
## |
|
200 | ## Most common views to enable: | |
189 | # ChangesetController:changeset_patch, |
|
201 | # RepoCommitsView:repo_commit_download | |
190 | # ChangesetController:changeset_raw, |
|
202 | # RepoCommitsView:repo_commit_patch | |
191 | # FilesController:raw, |
|
203 | # RepoCommitsView:repo_commit_raw | |
192 | # FilesController:archivefile, |
|
204 | # RepoCommitsView:repo_commit_raw@TOKEN | |
193 | # GistsController:*, |
|
205 | # RepoFilesView:repo_files_diff | |
|
206 | # RepoFilesView:repo_archivefile | |||
|
207 | # RepoFilesView:repo_file_raw | |||
|
208 | # GistView:* | |||
194 | api_access_controllers_whitelist = |
|
209 | api_access_controllers_whitelist = | |
195 |
|
210 | |||
196 | ## default encoding used to convert from and to unicode |
|
211 | ## default encoding used to convert from and to unicode | |
@@ -532,7 +547,7 b' vcs.backends = hg, git, svn' | |||||
532 |
|
547 | |||
533 | vcs.connection_timeout = 3600 |
|
548 | vcs.connection_timeout = 3600 | |
534 | ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out. |
|
549 | ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out. | |
535 | ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible |
|
550 | ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible | |
536 | #vcs.svn.compatible_version = pre-1.8-compatible |
|
551 | #vcs.svn.compatible_version = pre-1.8-compatible | |
537 |
|
552 | |||
538 |
|
553 | |||
@@ -546,6 +561,8 b' svn.proxy.generate_config = false' | |||||
546 | svn.proxy.list_parent_path = true |
|
561 | svn.proxy.list_parent_path = true | |
547 | ## Set location and file name of generated config file. |
|
562 | ## Set location and file name of generated config file. | |
548 | svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf |
|
563 | svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf | |
|
564 | ## alternative mod_dav config template. This needs to be a mako template | |||
|
565 | #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako | |||
549 | ## Used as a prefix to the `Location` block in the generated config file. |
|
566 | ## Used as a prefix to the `Location` block in the generated config file. | |
550 | ## In most cases it should be set to `/`. |
|
567 | ## In most cases it should be set to `/`. | |
551 | svn.proxy.location_root = / |
|
568 | svn.proxy.location_root = / | |
@@ -556,6 +573,43 b' svn.proxy.location_root = /' | |||||
556 | ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds. |
|
573 | ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds. | |
557 | #svn.proxy.reload_timeout = 10 |
|
574 | #svn.proxy.reload_timeout = 10 | |
558 |
|
575 | |||
|
576 | ############################################################ | |||
|
577 | ### SSH Support Settings ### | |||
|
578 | ############################################################ | |||
|
579 | ||||
|
580 | ## Defines if a custom authorized_keys file should be created and written on | |||
|
581 | ## any change user ssh keys. Setting this to false also disables posibility | |||
|
582 | ## of adding SSH keys by users from web interface. Super admins can still | |||
|
583 | ## manage SSH Keys. | |||
|
584 | ssh.generate_authorized_keyfile = false | |||
|
585 | ||||
|
586 | ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding` | |||
|
587 | # ssh.authorized_keys_ssh_opts = | |||
|
588 | ||||
|
589 | ## Path to the authrozied_keys file where the generate entries are placed. | |||
|
590 | ## It is possible to have multiple key files specified in `sshd_config` e.g. | |||
|
591 | ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode | |||
|
592 | ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode | |||
|
593 | ||||
|
594 | ## Command to execute the SSH wrapper. The binary is available in the | |||
|
595 | ## rhodecode installation directory. | |||
|
596 | ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper | |||
|
597 | ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper | |||
|
598 | ||||
|
599 | ## Allow shell when executing the ssh-wrapper command | |||
|
600 | ssh.wrapper_cmd_allow_shell = false | |||
|
601 | ||||
|
602 | ## Enables logging, and detailed output send back to the client during SSH | |||
|
603 | ## operations. Usefull for debugging, shouldn't be used in production. | |||
|
604 | ssh.enable_debug_logging = false | |||
|
605 | ||||
|
606 | ## Paths to binary executable, by default they are the names, but we can | |||
|
607 | ## override them if we want to use a custom one | |||
|
608 | ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg | |||
|
609 | ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git | |||
|
610 | ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve | |||
|
611 | ||||
|
612 | ||||
559 | ## Dummy marker to add new entries after. |
|
613 | ## Dummy marker to add new entries after. | |
560 | ## Add any custom entries below. Please don't remove. |
|
614 | ## Add any custom entries below. Please don't remove. | |
561 | custom.conf = 1 |
|
615 | custom.conf = 1 | |
@@ -565,7 +619,7 b' custom.conf = 1' | |||||
565 | ### LOGGING CONFIGURATION #### |
|
619 | ### LOGGING CONFIGURATION #### | |
566 | ################################ |
|
620 | ################################ | |
567 | [loggers] |
|
621 | [loggers] | |
568 |
keys = root, |
|
622 | keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper | |
569 |
|
623 | |||
570 | [handlers] |
|
624 | [handlers] | |
571 | keys = console, console_sql |
|
625 | keys = console, console_sql | |
@@ -580,12 +634,11 b' keys = generic, color_formatter, color_f' | |||||
580 | level = NOTSET |
|
634 | level = NOTSET | |
581 | handlers = console |
|
635 | handlers = console | |
582 |
|
636 | |||
583 | [logger_routes] |
|
637 | [logger_sqlalchemy] | |
584 |
level = |
|
638 | level = INFO | |
585 | handlers = |
|
639 | handlers = console_sql | |
586 | qualname = routes.middleware |
|
640 | qualname = sqlalchemy.engine | |
587 | ## "level = DEBUG" logs the route matched and routing variables. |
|
641 | propagate = 0 | |
588 | propagate = 1 |
|
|||
589 |
|
642 | |||
590 | [logger_beaker] |
|
643 | [logger_beaker] | |
591 | level = DEBUG |
|
644 | level = DEBUG | |
@@ -593,23 +646,18 b' handlers =' | |||||
593 | qualname = beaker.container |
|
646 | qualname = beaker.container | |
594 | propagate = 1 |
|
647 | propagate = 1 | |
595 |
|
648 | |||
596 | [logger_templates] |
|
|||
597 | level = INFO |
|
|||
598 | handlers = |
|
|||
599 | qualname = pylons.templating |
|
|||
600 | propagate = 1 |
|
|||
601 |
|
||||
602 | [logger_rhodecode] |
|
649 | [logger_rhodecode] | |
603 | level = DEBUG |
|
650 | level = DEBUG | |
604 | handlers = |
|
651 | handlers = | |
605 | qualname = rhodecode |
|
652 | qualname = rhodecode | |
606 | propagate = 1 |
|
653 | propagate = 1 | |
607 |
|
654 | |||
608 |
[logger_s |
|
655 | [logger_ssh_wrapper] | |
609 |
level = |
|
656 | level = DEBUG | |
610 |
handlers = |
|
657 | handlers = | |
611 | qualname = sqlalchemy.engine |
|
658 | qualname = ssh_wrapper | |
612 |
propagate = |
|
659 | propagate = 1 | |
|
660 | ||||
613 |
|
661 | |||
614 | ############## |
|
662 | ############## | |
615 | ## HANDLERS ## |
|
663 | ## HANDLERS ## |
@@ -40,8 +40,17 b' Below config if for an Apache Reverse Pr' | |||||
40 | ServerName rhodecode.myserver.com |
|
40 | ServerName rhodecode.myserver.com | |
41 | ServerAlias rhodecode.myserver.com |
|
41 | ServerAlias rhodecode.myserver.com | |
42 |
|
42 | |||
|
43 | ## Skip ProxyPass the _static to backend server | |||
|
44 | #ProxyPass /_static ! | |||
|
45 | ||||
43 | ## serve static files by Apache, recommended for performance |
|
46 | ## serve static files by Apache, recommended for performance | |
44 | #Alias /_static /home/ubuntu/.rccontrol/community-1/static |
|
47 | #Alias /_static/rhodecode /home/ubuntu/.rccontrol/community-1/static | |
|
48 | ||||
|
49 | ## Allow Apache to access the static files in this directory | |||
|
50 | #<Directory /home/ubuntu/.rccontrol/community-1/static/> | |||
|
51 | # AllowOverride none | |||
|
52 | # Require all granted | |||
|
53 | #</Directory> | |||
45 |
|
54 | |||
46 | RequestHeader set X-Forwarded-Proto "https" |
|
55 | RequestHeader set X-Forwarded-Proto "https" | |
47 |
|
56 | |||
@@ -86,5 +95,9 b' Below config if for an Apache Reverse Pr' | |||||
86 | # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits |
|
95 | # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits | |
87 | #SSLOpenSSLConfCmd DHParameters "/etc/apache2/dhparam.pem" |
|
96 | #SSLOpenSSLConfCmd DHParameters "/etc/apache2/dhparam.pem" | |
88 |
|
97 | |||
|
98 | ## custom 502 error page. Will be displayed while RhodeCode server | |||
|
99 | ## is turned off | |||
|
100 | ErrorDocument 502 /path/to/.rccontrol/enterprise-1/static/502.html | |||
|
101 | ||||
89 | </VirtualHost> |
|
102 | </VirtualHost> | |
90 |
|
103 |
@@ -89,6 +89,13 b' Use the following example to configure N' | |||||
89 |
|
89 | |||
90 | ## serve static files by Nginx, recommended for performance |
|
90 | ## serve static files by Nginx, recommended for performance | |
91 | # location /_static/rhodecode { |
|
91 | # location /_static/rhodecode { | |
|
92 | # gzip on; | |||
|
93 | # gzip_min_length 500; | |||
|
94 | # gzip_proxied any; | |||
|
95 | # gzip_comp_level 4; | |||
|
96 | # gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/json application/xml application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml; | |||
|
97 | # gzip_vary on; | |||
|
98 | # gzip_disable "msie6"; | |||
92 | # alias /path/to/.rccontrol/enterprise-1/static; |
|
99 | # alias /path/to/.rccontrol/enterprise-1/static; | |
93 | # } |
|
100 | # } | |
94 |
|
101 | |||
@@ -127,7 +134,8 b' Use the following example to configure N' | |||||
127 | proxy_pass http://rc; |
|
134 | proxy_pass http://rc; | |
128 | } |
|
135 | } | |
129 |
|
136 | |||
130 | ## custom 502 error page |
|
137 | ## custom 502 error page. Will be displayed while RhodeCode server | |
|
138 | ## is turned off | |||
131 | error_page 502 /502.html; |
|
139 | error_page 502 /502.html; | |
132 | location = /502.html { |
|
140 | location = /502.html { | |
133 | root /path/to/.rccontrol/enterprise-1/static; |
|
141 | root /path/to/.rccontrol/enterprise-1/static; |
@@ -19,6 +19,7 b' The following are the most common system' | |||||
19 | config-files-overview |
|
19 | config-files-overview | |
20 | vcs-server |
|
20 | vcs-server | |
21 | svn-http |
|
21 | svn-http | |
|
22 | gunicorn-ssl-support | |||
22 | apache-config |
|
23 | apache-config | |
23 | nginx-config |
|
24 | nginx-config | |
24 | backup-restore |
|
25 | backup-restore |
@@ -3,16 +3,19 b'' | |||||
3 | Increase Gunicorn Workers |
|
3 | Increase Gunicorn Workers | |
4 | ------------------------- |
|
4 | ------------------------- | |
5 |
|
5 | |||
6 | .. important:: |
|
6 | ||
|
7 | |RCE| comes with `Gunicorn`_ packaged in its Nix environment. | |||
|
8 | Gunicorn is a Python WSGI HTTP Server for UNIX. | |||
7 |
|
9 | |||
8 |
|
|
10 | To improve |RCE| performance you can increase the number of `Gunicorn`_ workers. | |
9 | increase the threadpool size of the VCS Server. The recommended size is |
|
11 | This allows to handle more connections concurently, and provide better | |
10 | 6 times the number of Gunicorn workers. To set this, see |
|
12 | responsiveness and performance. | |
11 | :ref:`vcs-server-config-file`. |
|
|||
12 |
|
13 | |||
13 | |RCE| comes with `Gunicorn`_ packaged in its Nix environment. To improve |
|
14 | By default during installation |RCC| tries to detect how many CPUs are | |
14 | performance you can increase the number of workers. To do this, use the |
|
15 | available in the system, and set the number workers based on that information. | |
15 | following steps: |
|
16 | However sometimes it's better to manually set the number of workers. | |
|
17 | ||||
|
18 | To do this, use the following steps: | |||
16 |
|
19 | |||
17 | 1. Open the :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. |
|
20 | 1. Open the :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. | |
18 | 2. In the ``[server:main]`` section, increase the number of Gunicorn |
|
21 | 2. In the ``[server:main]`` section, increase the number of Gunicorn | |
@@ -20,16 +23,26 b' 2. In the ``[server:main]`` section, inc' | |||||
20 |
|
23 | |||
21 | .. code-block:: ini |
|
24 | .. code-block:: ini | |
22 |
|
25 | |||
23 | [server:main] |
|
|||
24 | host = 127.0.0.1 |
|
|||
25 | port = 10002 |
|
|||
26 | use = egg:gunicorn#main |
|
26 | use = egg:gunicorn#main | |
27 | workers = 1 |
|
27 | ## Sets the number of process workers. You must set `instance_id = *` | |
28 | threads = 1 |
|
28 | ## when this option is set to more than one worker, recommended | |
29 | proc_name = RhodeCodeEnterprise |
|
29 | ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers | |
|
30 | ## The `instance_id = *` must be set in the [app:main] section below | |||
|
31 | workers = 4 | |||
|
32 | ## process name | |||
|
33 | proc_name = rhodecode | |||
|
34 | ## type of worker class, one of sync, gevent | |||
|
35 | ## recommended for bigger setup is using of of other than sync one | |||
30 | worker_class = sync |
|
36 | worker_class = sync | |
|
37 | ## The maximum number of simultaneous clients. Valid only for Gevent | |||
|
38 | #worker_connections = 10 | |||
|
39 | ## max number of requests that worker will handle before being gracefully | |||
|
40 | ## restarted, could prevent memory leaks | |||
31 | max_requests = 1000 |
|
41 | max_requests = 1000 | |
32 | timeout = 3600 |
|
42 | max_requests_jitter = 30 | |
|
43 | ## amount of time a worker can spend with handling a request before it | |||
|
44 | ## gets killed and restarted. Set to 6hrs | |||
|
45 | timeout = 21600 | |||
33 |
|
46 | |||
34 | 3. In the ``[app:main]`` section, set the ``instance_id`` property to ``*``. |
|
47 | 3. In the ``[app:main]`` section, set the ``instance_id`` property to ``*``. | |
35 |
|
48 | |||
@@ -40,72 +53,72 b' 3. In the ``[app:main]`` section, set th' | |||||
40 | # You must set `instance_id = *` |
|
53 | # You must set `instance_id = *` | |
41 | instance_id = * |
|
54 | instance_id = * | |
42 |
|
55 | |||
43 | 4. Save your changes. |
|
56 | 4. Change the VCSServer workers too. Open the | |
44 | 5. Restart your |RCE| instance, using the following command: |
|
57 | :file:`home/{user}/.rccontrol/{instance-id}/vcsserver.ini` file. | |
|
58 | ||||
|
59 | 5. In the ``[server:main]`` section, increase the number of Gunicorn | |||
|
60 | ``workers`` using the following formula :math:`(2 * Cores) + 1`. | |||
|
61 | ||||
|
62 | .. code-block:: ini | |||
|
63 | ||||
|
64 | ## run with gunicorn --log-config vcsserver.ini --paste vcsserver.ini | |||
|
65 | use = egg:gunicorn#main | |||
|
66 | ## Sets the number of process workers. Recommended | |||
|
67 | ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers | |||
|
68 | workers = 4 | |||
|
69 | ## process name | |||
|
70 | proc_name = rhodecode_vcsserver | |||
|
71 | ## type of worker class, currently `sync` is the only option allowed. | |||
|
72 | worker_class = sync | |||
|
73 | ## The maximum number of simultaneous clients. Valid only for Gevent | |||
|
74 | #worker_connections = 10 | |||
|
75 | ## max number of requests that worker will handle before being gracefully | |||
|
76 | ## restarted, could prevent memory leaks | |||
|
77 | max_requests = 1000 | |||
|
78 | max_requests_jitter = 30 | |||
|
79 | ## amount of time a worker can spend with handling a request before it | |||
|
80 | ## gets killed and restarted. Set to 6hrs | |||
|
81 | timeout = 21600 | |||
|
82 | ||||
|
83 | 6. Save your changes. | |||
|
84 | 7. Restart your |RCE| instances, using the following command: | |||
45 |
|
85 | |||
46 | .. code-block:: bash |
|
86 | .. code-block:: bash | |
47 |
|
87 | |||
48 |
$ rccontrol restart |
|
88 | $ rccontrol restart '*' | |
|
89 | ||||
|
90 | ||||
|
91 | Gunicorn Gevent Backend | |||
|
92 | ----------------------- | |||
49 |
|
93 | |||
50 | If you scale across different machines, each |RCM| instance |
|
94 | Gevent is an asynchronous worker type for Gunicorn. It allows accepting multiple | |
51 | needs to store its data on a shared disk, preferably together with your |
|
95 | connections on a single `Gunicorn`_ worker. This means you can handle 100s | |
52 | |repos|. This data directory contains template caches, a whoosh index, |
|
96 | of concurrent clones, or API calls using just few workers. A setting called | |
53 | and is used for task locking to ensure safety across multiple instances. |
|
97 | `worker_connections` defines on how many connections each worker can | |
54 | To do this, set the following properties in the :file:`rhodecode.ini` file to |
|
98 | handle using `Gevent`. | |
55 | set the shared location across all |RCM| instances. |
|
99 | ||
|
100 | ||||
|
101 | To enable `Gevent` on |RCE| do the following: | |||
|
102 | ||||
|
103 | ||||
|
104 | 1. Open the :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. | |||
|
105 | 2. In the ``[server:main]`` section, change `worker_class` for Gunicorn. | |||
|
106 | ||||
56 |
|
107 | |||
57 | .. code-block:: ini |
|
108 | .. code-block:: ini | |
58 |
|
109 | |||
59 | cache_dir = /file/path # set to shared location |
|
110 | ## type of worker class, one of sync, gevent | |
60 | search.location = /file/path # set to shared location |
|
111 | ## recommended for bigger setup is using of of other than sync one | |
|
112 | worker_class = gevent | |||
|
113 | ## The maximum number of simultaneous clients. Valid only for Gevent | |||
|
114 | worker_connections = 30 | |||
61 |
|
115 | |||
62 | #################################### |
|
116 | ||
63 | ### BEAKER CACHE #### |
|
117 | .. note:: | |
64 | #################################### |
|
118 | ||
65 | beaker.cache.data_dir = /file/path # set to shared location |
|
119 | `Gevent` is currently only supported for Enterprise/Community instances. | |
66 | beaker.cache.lock_dir = /file/path # set to shared location |
|
120 | VCSServer doesn't yet support gevent. | |
67 |
|
121 | |||
68 |
|
122 | |||
69 |
|
123 | |||
70 | Gunicorn SSL support |
|
|||
71 | -------------------- |
|
|||
72 |
|
||||
73 |
|
||||
74 | :term:`Gunicorn` wsgi server allows users to use HTTPS connection directly |
|
|||
75 | without a need to use HTTP server like Nginx or Apache. To Configure |
|
|||
76 | SSL support directly with :term:`Gunicorn` you need to simply add the key |
|
|||
77 | and certificate paths to your configuration file. |
|
|||
78 |
|
||||
79 | 1. Open the :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. |
|
|||
80 | 2. In the ``[server:main]`` section, add two new variables |
|
|||
81 | called `certfile` and `keyfile`. |
|
|||
82 |
|
||||
83 | .. code-block:: ini |
|
|||
84 |
|
||||
85 | [server:main] |
|
|||
86 | host = 127.0.0.1 |
|
|||
87 | port = 10002 |
|
|||
88 | use = egg:gunicorn#main |
|
|||
89 | workers = 1 |
|
|||
90 | threads = 1 |
|
|||
91 | proc_name = RhodeCodeEnterprise |
|
|||
92 | worker_class = sync |
|
|||
93 | max_requests = 1000 |
|
|||
94 | timeout = 3600 |
|
|||
95 | # adding ssl support |
|
|||
96 | certfile = /home/ssl/my_server_com.pem |
|
|||
97 | keyfile = /home/ssl/my_server_com.key |
|
|||
98 |
|
||||
99 | 4. Save your changes. |
|
|||
100 | 5. Restart your |RCE| instance, using the following command: |
|
|||
101 |
|
||||
102 | .. code-block:: bash |
|
|||
103 |
|
||||
104 | $ rccontrol restart enterprise-1 |
|
|||
105 |
|
||||
106 | After this is enabled you can *only* access your instances via https:// |
|
|||
107 | protocol. Check out more docs here `Gunicorn SSL Docs`_ |
|
|||
108 |
|
||||
109 |
|
||||
110 | .. _Gunicorn: http://gunicorn.org/ |
|
124 | .. _Gunicorn: http://gunicorn.org/ | |
111 | .. _Gunicorn SSL Docs: http://docs.gunicorn.org/en/stable/settings.html#ssl |
|
@@ -25,6 +25,15 b' depending on your available resources.' | |||||
25 |
|
25 | |||
26 | .. _move-tmp: |
|
26 | .. _move-tmp: | |
27 |
|
27 | |||
|
28 | ||||
|
29 | In order to make this change permanent it's recommend to set it as /etc/fstab | |||
|
30 | entry. | |||
|
31 | ||||
|
32 | .. code-block:: bash | |||
|
33 | ||||
|
34 | tmpfs /home/user/.rccontrol/enterprise-1/data tmpfs nodev,nosuid,noexec,nodiratime,size=2G 0 0 | |||
|
35 | ||||
|
36 | ||||
28 | Move ``tmp`` to TMPFS |
|
37 | Move ``tmp`` to TMPFS | |
29 | --------------------- |
|
38 | --------------------- | |
30 |
|
39 |
@@ -3,21 +3,45 b'' | |||||
3 | Scale Horizontally |
|
3 | Scale Horizontally | |
4 | ------------------ |
|
4 | ------------------ | |
5 |
|
5 | |||
|
6 | |RCE| is built in a way it support horizontal scaling across multiple machines. | |||
|
7 | There are two main pre-requisites for that: | |||
|
8 | ||||
|
9 | - Shared storage that each machine can access. | |||
|
10 | - Shared DB connection across machines. | |||
|
11 | ||||
|
12 | ||||
6 | Horizontal scaling means adding more machines or workers into your pool of |
|
13 | Horizontal scaling means adding more machines or workers into your pool of | |
7 | resources. Horizontally scaling |RCE| gives a huge performance increase, |
|
14 | resources. Horizontally scaling |RCE| gives a huge performance increase, | |
8 | especially under large traffic scenarios with a high number of requests. This |
|
15 | especially under large traffic scenarios with a high number of requests. This | |
9 | is very beneficial when |RCE| is serving many users simultaneously, |
|
16 | is very beneficial when |RCE| is serving many users simultaneously, | |
10 | or if continuous integration servers are automatically pulling and pushing code. |
|
17 | or if continuous integration servers are automatically pulling and pushing code. | |
11 |
|
18 | |||
12 | To horizontally scale |RCE| you should use the following steps: |
|
19 | ||
|
20 | If you scale across different machines, each |RCM| instance | |||
|
21 | needs to store its data on a shared disk, preferably together with your | |||
|
22 | |repos|. This data directory contains template caches, a full text search index, | |||
|
23 | and is used for task locking to ensure safety across multiple instances. | |||
|
24 | To do this, set the following properties in the :file:`rhodecode.ini` file to | |||
|
25 | set the shared location across all |RCM| instances. | |||
|
26 | ||||
|
27 | .. code-block:: ini | |||
|
28 | ||||
|
29 | cache_dir = /shared/path/caches # set to shared location | |||
|
30 | search.location = /shared/path/search_index # set to shared location | |||
13 |
|
|
31 | ||
14 | 1. In the :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file, |
|
32 | #################################### | |
15 | set ``instance_id = *``. This enables |RCE| to use multiple nodes. |
|
33 | ### BEAKER CACHE #### | |
16 | 2. Define the number of worker threads using the formula |
|
34 | #################################### | |
17 | :math:`(2 * Cores) + 1`. For example 4 CPU cores would lead to |
|
35 | beaker.cache.data_dir = /shared/path/data # set to shared location | |
18 | :math:`(2 * 4) + 1 = 9` workers. In some cases it's ok to increase number of |
|
36 | beaker.cache.lock_dir = /shared/path/lock # set to shared location | |
19 | workers even beyond this formula. Generally the more workers, the more |
|
37 | ||
20 | simultaneous connections the system can handle. |
|
38 | ||
|
39 | .. note:: | |||
|
40 | ||||
|
41 | If you use custom caches such as `beaker.cache.auth_plugins.` it's recommended | |||
|
42 | to set it to the memcached/redis or database backend so it can be shared | |||
|
43 | across machines. | |||
|
44 | ||||
21 |
|
45 | |||
22 | It is recommended to create another dedicated |RCE| instance to handle |
|
46 | It is recommended to create another dedicated |RCE| instance to handle | |
23 | traffic from build farms or continuous integration servers. |
|
47 | traffic from build farms or continuous integration servers. | |
@@ -28,24 +52,7 b' traffic from build farms or continuous i' | |||||
28 | load balancing rules that will separate regular user traffic from |
|
52 | load balancing rules that will separate regular user traffic from | |
29 | automated process traffic like continuous servers or build bots. |
|
53 | automated process traffic like continuous servers or build bots. | |
30 |
|
54 | |||
31 | If you scale across different machines, each |RCE| instance needs to store |
|
|||
32 | its data on a shared disk, preferably together with your repositories. This |
|
|||
33 | data directory contains template caches, a whoosh index, |
|
|||
34 | and is used for task locking to ensure safety across multiple instances. To |
|
|||
35 | do this, set the following properties in the |
|
|||
36 | :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file to set |
|
|||
37 | the shared location across all |RCE| instances. |
|
|||
38 |
|
||||
39 | .. code-block:: ini |
|
|||
40 |
|
||||
41 | cache_dir = /file/path # set to shared directory location |
|
|||
42 | search.location = /file/path # set to shared directory location |
|
|||
43 | beaker.cache.data_dir = /file/path # set to shared directory location |
|
|||
44 | beaker.cache.lock_dir = /file/path # set to shared directory location |
|
|||
45 |
|
||||
46 | .. note:: |
|
55 | .. note:: | |
47 |
|
56 | |||
48 | If Celery is used on each instance then you should run separate Celery |
|
57 | If Celery is used on each instance then you should run separate Celery | |
49 | instances, but the message broker should be the same for all of them. |
|
58 | instances, but the message broker should be the same for all of them. | |
50 | This excludes one RabbitMQ shared server. |
|
|||
51 |
|
@@ -42,7 +42,7 b' archive.' | |||||
42 | ## Syntax is <ControllerClass>:<function_pattern>. |
|
42 | ## Syntax is <ControllerClass>:<function_pattern>. | |
43 | ## The list should be "," separated and on a single line. |
|
43 | ## The list should be "," separated and on a single line. | |
44 | ## |
|
44 | ## | |
45 | api_access_controllers_whitelist = ChangesetController:changeset_patch,ChangesetController:changeset_raw,ilesController:raw,FilesController:archivefile, |
|
45 | api_access_controllers_whitelist = RepoCommitsView:repo_commit_raw,RepoCommitsView:repo_commit_patch,RepoCommitsView:repo_commit_download | |
46 |
|
46 | |||
47 | After this change, a |RCE| view can be accessed without login by adding a |
|
47 | After this change, a |RCE| view can be accessed without login by adding a | |
48 | GET parameter ``?auth_token=<auth_token>`` to a url. For example to |
|
48 | GET parameter ``?auth_token=<auth_token>`` to a url. For example to |
@@ -533,6 +533,9 b' get_repo_settings' | |||||
533 | "hooks_outgoing_pull_logger": true, |
|
533 | "hooks_outgoing_pull_logger": true, | |
534 | "phases_publish": "True", |
|
534 | "phases_publish": "True", | |
535 | "rhodecode_hg_use_rebase_for_merging": true, |
|
535 | "rhodecode_hg_use_rebase_for_merging": true, | |
|
536 | "rhodecode_hg_close_branch_before_merging": false, | |||
|
537 | "rhodecode_git_use_rebase_for_merging": true, | |||
|
538 | "rhodecode_git_close_branch_before_merging": false, | |||
536 | "rhodecode_pr_merge_enabled": true, |
|
539 | "rhodecode_pr_merge_enabled": true, | |
537 | "rhodecode_use_outdated_comments": true |
|
540 | "rhodecode_use_outdated_comments": true | |
538 | } |
|
541 | } |
@@ -137,6 +137,30 b' get_method' | |||||
137 | error : null |
|
137 | error : null | |
138 |
|
138 | |||
139 |
|
139 | |||
|
140 | get_repo_store | |||
|
141 | -------------- | |||
|
142 | ||||
|
143 | .. py:function:: get_repo_store(apiuser) | |||
|
144 | ||||
|
145 | Returns the |RCE| repository storage information. | |||
|
146 | ||||
|
147 | :param apiuser: This is filled automatically from the |authtoken|. | |||
|
148 | :type apiuser: AuthUser | |||
|
149 | ||||
|
150 | Example output: | |||
|
151 | ||||
|
152 | .. code-block:: bash | |||
|
153 | ||||
|
154 | id : <id_given_in_input> | |||
|
155 | result : { | |||
|
156 | 'modules': [<module name>,...] | |||
|
157 | 'py_version': <python version>, | |||
|
158 | 'platform': <platform type>, | |||
|
159 | 'rhodecode_version': <rhodecode version> | |||
|
160 | } | |||
|
161 | error : null | |||
|
162 | ||||
|
163 | ||||
140 | get_server_info |
|
164 | get_server_info | |
141 | --------------- |
|
165 | --------------- | |
142 |
|
166 |
@@ -3,11 +3,13 b'' | |||||
3 | LDAP |
|
3 | LDAP | |
4 | ---- |
|
4 | ---- | |
5 |
|
5 | |||
6 |
|RCM| supports LDAP (Lightweight Directory Access Protocol) |
|
6 | |RCM| supports LDAP (Lightweight Directory Access Protocol) or | |
|
7 | AD (active Directory) authentication. | |||
7 | All LDAP versions are supported, with the following |RCM| plugins managing each: |
|
8 | All LDAP versions are supported, with the following |RCM| plugins managing each: | |
8 |
|
9 | |||
9 | * For LDAPv3 use ``rhodecode.lib.auth_modules.auth_ldap_group`` |
|
10 | * For LDAPv3 use ``LDAP (egg:rhodecode-enterprise-ce#ldap)`` | |
10 | * For older LDAP versions use ``rhodecode.lib.auth_modules.auth_ldap`` |
|
11 | * For LDAPv3 with user group sync use ``LDAP + User Groups (egg:rhodecode-enterprise-ee#ldap_group)`` | |
|
12 | ||||
11 |
|
13 | |||
12 | .. important:: |
|
14 | .. important:: | |
13 |
|
15 |
@@ -3,127 +3,136 b'' | |||||
3 | SSH Connection |
|
3 | SSH Connection | |
4 | -------------- |
|
4 | -------------- | |
5 |
|
5 | |||
6 |
If you wish to connect to your |
|
6 | If you wish to connect to your |repos| using SSH protocol, use the | |
7 | following instructions. |
|
7 | following instructions. | |
8 |
|
8 | |||
9 | .. note:: |
|
9 | 1. Include |RCE| generated `authorized_keys` file into your sshd_config. | |
10 |
|
10 | |||
11 | SSH access with full |RCE| permissions will require an Admin |authtoken|. |
|
11 | By default a file `authorized_keys_rhodecode` is created containing | |
|
12 | configuration and all allowed user connection keys are stored inside. | |||
|
13 | On each change of stored keys inside |RCE| this file is updated with | |||
|
14 | proper data. | |||
12 |
|
15 | |||
13 | You need to install the |RC| SSH tool on the server which is running |
|
16 | .. code-block:: bash | |
14 | the |RCE| instance. |
|
|||
15 |
|
|
17 | ||
16 | 1. Gather the following information about the instance you wish to connect to: |
|
18 | # Edit sshd_config file most likely at /etc/ssh/sshd_config | |
|
19 | # add or edit the AuthorizedKeysFile, and set to use custom files | |||
|
20 | ||||
|
21 | AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode | |||
17 |
|
|
22 | ||
18 | * *Hostname*: Use the ``rccontrol status`` command to view instance details. |
|
23 | This way we use a separate file for SSH access and separate one for | |
19 | * *API key*: From the |RCE|, go to |
|
24 | SSH access to |RCE| repositories. | |
20 | :menuselection:`username --> My Account --> Auth Tokens` |
|
25 | ||
21 | * *Configuration file*: Identify the configuration file for that instance, |
|
26 | ||
22 | the default is :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` |
|
27 | 2. Enable the SSH module on instance. | |
23 | * Identify which |git| and |hg| packages your |RCM| instance is using. |
|
|||
24 |
|
28 | |||
25 | * For |git|, see |
|
29 | On the server where |RCE| is running executing: | |
26 | :menuselection:`Admin --> Settings --> System Info` |
|
30 | ||
27 | * For |hg|, use the ``which hg`` command. |
|
31 | .. code-block:: bash | |
28 |
|
|
32 | ||
29 | 2. Clone the |RC| SSH script, |
|
33 | rccontrol enable-module ssh {instance-id} | |
30 | ``hg clone https://code.rhodecode.com/rhodecode-ssh`` |
|
|||
31 | 3. Copy the ``sshwrapper.sample.ini``, and save it as ``sshwrapper.ini`` |
|
|||
32 | 4. Configure the :file:`sshwrapper.ini` file using the following example: |
|
|||
33 |
|
|
34 | ||
34 | .. code-block:: ini |
|
35 | This will add the following configuration into :file:`rhodecode.ini`. | |
|
36 | This also can be done manually: | |||
35 |
|
37 | |||
36 | [api] |
|
38 | .. code-block:: ini | |
37 | host=http://localhost:10005 |
|
|||
38 | key=24a67076d69c84670132f55166ac79d1faafd660 |
|
|||
39 |
|
39 | |||
40 | [shell] |
|
40 | ############################################################ | |
41 | shell=/bin/bash -l |
|
41 | ### SSH Support Settings ### | |
|
42 | ############################################################ | |||
42 |
|
43 | |||
43 | [vcs] |
|
44 | ## Defines if a custom authorized_keys file should be created and written on | |
44 | root=/path/to/repos/ |
|
45 | ## any change user ssh keys. Setting this to false also disables posibility | |
|
46 | ## of adding SSH keys by users from web interface. Super admins can still | |||
|
47 | ## manage SSH Keys. | |||
|
48 | ssh.generate_authorized_keyfile = true | |||
45 |
|
49 | |||
46 | [rhodecode] |
|
50 | ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding` | |
47 | config=/home/user/.rccontrol/enterprise-3/rhodecode.ini |
|
51 | # ssh.authorized_keys_ssh_opts = | |
48 |
|
||||
49 | [vcs:hg] |
|
|||
50 | path=/usr/bin/hg |
|
|||
51 |
|
52 | |||
52 | # should be a base dir for all git binaries, i.e. not ../bin/git |
|
53 | ## Path to the authrozied_keys file where the generate entries are placed. | |
53 | [vcs:git] |
|
54 | ## It is possible to have multiple key files specified in `sshd_config` e.g. | |
54 | path=/usr/bin |
|
55 | ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode | |
55 |
|
56 | ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode | ||
56 | [keys] |
|
|||
57 | path=/home/user/.ssh/authorized_keys |
|
|||
58 |
|
57 | |||
59 | 5. Add the public key to your |RCE| instance server using the |
|
58 | ## Command to execute the SSH wrapper. The binary is available in the | |
60 | :file:`addkey.py` script. This script automatically creates |
|
59 | ## rhodecode installation directory. | |
61 | the :file:`authorized_keys` file which was specified in your |
|
60 | ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper | |
62 | :file:`sshwrapper.ini` configuration. Use the following example: |
|
61 | ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper | |
63 |
|
|
62 | ||
64 | .. code-block:: bash |
|
63 | ## Allow shell when executing the ssh-wrapper command | |
|
64 | ssh.wrapper_cmd_allow_shell = false | |||
65 |
|
65 | |||
66 | $ ./addkey.py --user username --shell --key /home/username/.ssh/id_rsa.pub |
|
66 | ## Enables logging, and detailed output send back to the client during SSH | |
67 |
|
67 | ## operations. Usefull for debugging, shouldn't be used in production. | ||
68 | .. important:: |
|
68 | ssh.enable_debug_logging = false | |
69 |
|
|
69 | ||
70 | To give SSH access to all users, you will need to maintain |
|
70 | ## Paths to binary executable, by default they are the names, but we can | |
71 | each users |authtoken| in the :file:`authorized_keys` file. |
|
71 | ## override them if we want to use a custom one | |
|
72 | ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg | |||
|
73 | ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git | |||
|
74 | ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve | |||
72 |
|
|
75 | ||
73 | 6. Connect to your server using SSH from your local machine. |
|
|||
74 |
|
||||
75 | .. code-block:: bash |
|
|||
76 |
|
76 | |||
77 | $ ssh user@localhost |
|
77 | 3. Set base_url for instance to enable proper event handling (Optional): | |
78 | Enter passphrase for key '/home/username/.ssh/id_rsa': |
|
|||
79 |
|
78 | |||
80 | If you need to manually configure the ``authorized_keys`` file, |
|
79 | If you wish to have integrations working correctly via SSH please configure | |
81 | add a line for each key using the following example: |
|
80 | The Application base_url. | |
82 |
|
81 | |||
83 | .. code-block:: vim |
|
82 | Use the ``rccontrol status`` command to view instance details. | |
|
83 | Hostname is required for the integration to properly set the instance URL. | |||
84 |
|
84 | |||
85 | command="/home/user/.rhodecode-ssh/sshwrapper.py --user username --shell", |
|
85 | When your hostname is known (e.g https://code.rhodecode.com) please set it | |
86 | no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-rsa yourpublickey |
|
86 | inside :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` | |
87 |
|
87 | |||
88 | .. tip:: |
|
88 | add into `[app:main]` section the following configuration: | |
|
89 | ||||
|
90 | .. code-block:: ini | |||
|
91 | ||||
|
92 | app.base_url = https://code.rhodecode.com | |||
89 |
|
|
93 | ||
90 | Best practice would be to create a special SSH user account with each |
|
94 | ||
91 | users |authtoken| attached. |
|
95 | 4. Add the public key to your user account for testing. | |
|
96 | First generate a new key, or use your existing one and have your public key | |||
|
97 | at hand. | |||
92 |
|
98 | |||
93 | |RCE| will manage the user permissions based on the |authtoken| supplied. |
|
99 | Go to | |
94 | This would allow you to immediately revoke all SSH access by removing one |
|
100 | :menuselection:`My Account --> SSH Keys` and add the public key with proper description. | |
95 | user from your server if you needed to. |
|
|||
96 |
|
101 | |||
97 | See the following command line example of setting this up. These steps |
|
102 | This will generate a new entry inside our configured `authorized_keys_rhodecode` file. | |
98 | take place on the server. |
|
|||
99 |
|
103 | |||
100 | .. code-block:: bash |
|
104 | Test the connection from your local machine using the following example: | |
|
105 | ||||
|
106 | .. note:: | |||
101 |
|
107 | |||
102 | # On the RhodeCode Enterprise server |
|
108 | In case of connection problems please set | |
103 | # set up user and clone SSH tool |
|
109 | `ssh.enable_debug_logging = true` inside the SSH configuration of | |
104 | $ sudo adduser testuser |
|
110 | :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.ini` | |
105 | $ sudo su - testuser |
|
111 | Then add, remove your SSH key and try connecting again. | |
106 | $ hg clone https://code.rhodecode.com/rhodecode-ssh |
|
112 | Debug logging will be printed to help find the problems on the server side. | |
107 | $ cd rhodecode-ssh |
|
|||
108 |
|
113 | |||
109 | # Copy and modify the sshwrapper.ini as explained in step 4 |
|
114 | Test connection using the ssh command from the local machine | |
110 | $ cp sshwrapper.sample.ini sshwrapper.ini |
|
115 | ||
|
116 | ||||
|
117 | For SVN: | |||
|
118 | ||||
|
119 | .. code-block:: bash | |||
111 |
|
120 | |||
112 | $ cd ~ |
|
121 | SVN_SSH="ssh -i ~/.ssh/id_rsa_test_ssh" svn checkout svn+ssh://rhodecode@rc-server/repo_name | |
113 | $ mkdir .ssh |
|
122 | ||
114 | $ touch .ssh/authorized_keys |
|
123 | For GIT: | |
115 |
|
124 | |||
116 | # copy your ssh public key, id_rsa.pub, from your local machine |
|
125 | .. code-block:: bash | |
117 | # to the server. We’ll use it in the next step |
|
|||
118 |
|
|
126 | ||
119 | $ python addkey.py --user testuser --shell --key /path/to/id_rsa.pub |
|
127 | GIT_SSH_COMMAND='ssh -i ~/.ssh/id_rsa_test_ssh' git clone ssh://rhodecode@rc-server/repo_name | |
120 |
|
128 | |||
121 | # Note: testssh - user on the rhodecode instance |
|
129 | For Mercurial: | |
122 | $ chmod 755 sshwrapper.py |
|
|||
123 |
|
130 | |||
124 | Test the connection from your local machine using the following example: |
|
131 | .. code-block:: bash | |
125 |
|
|
132 | ||
126 | .. code-block:: bash |
|
133 | Add to hgrc: | |
127 |
|
134 | |||
128 | # Test connection using the ssh command from the local machine |
|
135 | [ui] | |
129 | $ ssh testuser@my-server.example.com |
|
136 | ssh = ssh -C -i ~/.ssh/id_rsa_test_ssh | |
|
137 | ||||
|
138 | hg clone ssh://rhodecode@rc-server/repo_name |
@@ -15,15 +15,13 b' We keep the calls in the form ``{verb}_{' | |||||
15 | Change and Deprecation |
|
15 | Change and Deprecation | |
16 | ====================== |
|
16 | ====================== | |
17 |
|
17 | |||
18 |
API deprecation is documented in the section |
|
18 | API deprecation is documented in the section `deprecated` together with | |
19 | other notes about deprecated parts of the application. |
|
19 | other notes about deprecated parts of the application. | |
20 |
|
20 | |||
21 |
|
21 | |||
22 | Deprecated API calls |
|
22 | Deprecated API calls | |
23 | -------------------- |
|
23 | -------------------- | |
24 |
|
24 | |||
25 | - Make sure to add them into the section :ref:`deprecated`. |
|
|||
26 |
|
||||
27 | - Use `deprecated` inside of the call docstring to make our users aware of the |
|
25 | - Use `deprecated` inside of the call docstring to make our users aware of the | |
28 | deprecation:: |
|
26 | deprecation:: | |
29 |
|
27 |
@@ -1,66 +1,69 b'' | |||||
1 |
|
1 | |||
2 | .. _config-celery: |
|
2 | .. _config-celery: | |
3 |
|
3 | |||
4 | Install Celery |
|
4 | Configure Celery | |
5 | -------------- |
|
5 | ---------------- | |
6 |
|
6 | |||
7 |
To improve |RCM| performance you should |
|
7 | To improve |RCM| performance you should configure and enabled Celery_ as it makes | |
8 |
asynchronous tasks work efficiently. |
|
8 | asynchronous tasks work efficiently. Most important it allows sending notification | |
9 | install Celery you also need multi-broker support. The recommended message |
|
9 | emails, create repository forks, and import repositories in async way. | |
10 | broker is rabbitmq_. |RCM| works in sync |
|
10 | ||
11 | mode, but running Celery_ will give you a large speed improvement when |
|
11 | If you decide to use Celery you also need a working message queue. | |
12 | managing many big repositories. |
|
12 | The recommended message broker is rabbitmq_. | |
|
13 | ||||
|
14 | ||||
|
15 | In order to have install and configure Celery, follow these steps: | |||
13 |
|
16 | |||
14 | If you want to run |RCM| with Celery you need to run ``celeryd`` using the |
|
17 | 1. Install RabbitMQ, see the documentation on the Celery website for | |
15 | ``paster`` command and the message broker. |
|
18 | `rabbitmq installation`_. | |
16 | The ``paster`` command is already installed during |RCM| installation. |
|
|||
17 |
|
19 | |||
18 | To install and configure Celery, use the following steps: |
|
20 | 2. Configure Celery in the | |
|
21 | :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. | |||
|
22 | Set the following minimal settings, that are set during rabbitmq_ installation:: | |||
19 |
|
|
23 | ||
20 | 1. Install Celery and RabbitMQ, see the documentation on the Celery website for |
|
24 | broker.host = | |
21 | `Celery installation`_ and `rabbitmq installation`_. |
|
25 | broker.vhost = | |
22 | 2. Enable Celery in the |
|
26 | broker.user = | |
23 | :file:`home/{user}/.rccontrol/{instance-id}/rhodecode.ini` file. |
|
27 | broker.password = | |
24 | 3. Run the Celery daemon with the ``paster`` command, |
|
|||
25 | using the following example |
|
|||
26 | ``.rccontrol/enterprise-1/profile/bin/paster celeryd .rccontrol/enterprise-1/rhodecode.ini`` |
|
|||
27 |
|
|
28 | ||
28 | .. code-block:: ini |
|
29 | Full configuration example is below: | |
|
30 | ||||
|
31 | .. code-block:: ini | |||
29 |
|
32 | |||
30 | # Set this section of the ini file to match your Celery installation |
|
33 | # Set this section of the ini file to match your Celery installation | |
31 | #################################### |
|
34 | #################################### | |
32 | ### CELERY CONFIG #### |
|
35 | ### CELERY CONFIG #### | |
33 | #################################### |
|
36 | #################################### | |
34 | ## Set to true |
|
37 | ## Set to true | |
35 |
use_celery = |
|
38 | use_celery = true | |
36 | broker.host = localhost |
|
39 | broker.host = localhost | |
37 | broker.vhost = rabbitmqhost |
|
40 | broker.vhost = rabbitmqvhost | |
38 | broker.port = 5672 |
|
41 | broker.port = 5672 | |
39 | broker.user = rabbitmq |
|
42 | broker.user = rabbitmq | |
40 |
broker.password = |
|
43 | broker.password = secret | |
41 |
|
44 | |||
42 | celery.imports = rhodecode.lib.celerylib.tasks |
|
45 | celery.imports = rhodecode.lib.celerylib.tasks | |
43 |
|
46 | |||
44 | celery.result.backend = amqp |
|
47 | celery.result.backend = amqp | |
45 | celery.result.dburi = amqp:// |
|
48 | celery.result.dburi = amqp:// | |
46 | celery.result.serialier = json |
|
49 | celery.result.serialier = json | |
47 |
|
50 | |||
48 | #celery.send.task.error.emails = true |
|
51 | #celery.send.task.error.emails = true | |
49 | #celery.amqp.task.result.expires = 18000 |
|
52 | #celery.amqp.task.result.expires = 18000 | |
50 |
|
53 | |||
51 | celeryd.concurrency = 2 |
|
54 | celeryd.concurrency = 2 | |
52 | #celeryd.log.file = celeryd.log |
|
55 | #celeryd.log.file = celeryd.log | |
53 | celeryd.log.level = debug |
|
56 | celeryd.log.level = debug | |
54 | celeryd.max.tasks.per.child = 1 |
|
57 | celeryd.max.tasks.per.child = 1 | |
55 |
|
58 | |||
56 | ## tasks will never be sent to the queue, but executed locally instead. |
|
59 | ## tasks will never be sent to the queue, but executed locally instead. | |
57 | celery.always.eager = false |
|
60 | celery.always.eager = false | |
|
61 | ||||
58 |
|
62 | |||
59 | .. code-block:: bash |
|
63 | 3. Enable celery, and install `celeryd` process script using the `enable-module`:: | |
60 |
|
64 | |||
61 | # Once the above is configured and saved |
|
65 | rccontrol enable-module celery {instance-id} | |
62 | # Run celery with the paster command and specify the ini file |
|
66 | ||
63 | .rccontrol/enterprise-1/profile/bin/paster celeryd .rccontrol/enterprise-1/rhodecode.ini |
|
|||
64 |
|
67 | |||
65 | .. _python: http://www.python.org/ |
|
68 | .. _python: http://www.python.org/ | |
66 | .. _mercurial: http://mercurial.selenic.com/ |
|
69 | .. _mercurial: http://mercurial.selenic.com/ | |
@@ -68,4 +71,3 b' 3. Run the Celery daemon with the ``past' | |||||
68 | .. _rabbitmq: http://www.rabbitmq.com/ |
|
71 | .. _rabbitmq: http://www.rabbitmq.com/ | |
69 | .. _rabbitmq installation: http://docs.celeryproject.org/en/latest/getting-started/brokers/rabbitmq.html |
|
72 | .. _rabbitmq installation: http://docs.celeryproject.org/en/latest/getting-started/brokers/rabbitmq.html | |
70 | .. _Celery installation: http://docs.celeryproject.org/en/latest/getting-started/introduction.html#bundles |
|
73 | .. _Celery installation: http://docs.celeryproject.org/en/latest/getting-started/introduction.html#bundles | |
71 | .. _virtualenv: http://docs.python-guide.org/en/latest/dev/virtualenvs/ |
|
@@ -10,5 +10,5 b' the information in these sections to con' | |||||
10 |
|
10 | |||
11 | setup-email |
|
11 | setup-email | |
12 | database-string |
|
12 | database-string | |
13 |
|
|
13 | configure-celery | |
14 | migrate-repos |
|
14 | migrate-repos |
@@ -9,6 +9,7 b' Release Notes' | |||||
9 | .. toctree:: |
|
9 | .. toctree:: | |
10 | :maxdepth: 1 |
|
10 | :maxdepth: 1 | |
11 |
|
11 | |||
|
12 | release-notes-4.10.0.rst | |||
12 | release-notes-4.9.1.rst |
|
13 | release-notes-4.9.1.rst | |
13 | release-notes-4.9.0.rst |
|
14 | release-notes-4.9.0.rst | |
14 | release-notes-4.8.0.rst |
|
15 | release-notes-4.8.0.rst |
@@ -22,7 +22,7 b' section.' | |||||
22 | gunicorn rhodecode-extensions svn svnversion |
|
22 | gunicorn rhodecode-extensions svn svnversion | |
23 | hg rhodecode-gist svnadmin vcsserver |
|
23 | hg rhodecode-gist svnadmin vcsserver | |
24 | paster rhodecode-index svndumpfilter |
|
24 | paster rhodecode-index svndumpfilter | |
25 |
rcserver |
|
25 | rc-server rhodecode-list-instances svnlook | |
26 | rhodecode-api rhodecode-setup-config svnmucc |
|
26 | rhodecode-api rhodecode-setup-config svnmucc | |
27 |
|
27 | |||
28 | You can then use the tools as described in the :ref:`rc-tools` section using the |
|
28 | You can then use the tools as described in the :ref:`rc-tools` section using the |
@@ -6,6 +6,7 b'' | |||||
6 | }, |
|
6 | }, | |
7 | "js": { |
|
7 | "js": { | |
8 | "src": "rhodecode/public/js/src", |
|
8 | "src": "rhodecode/public/js/src", | |
|
9 | "src_rc": "rhodecode/public/js/rhodecode", | |||
9 | "dest": "rhodecode/public/js", |
|
10 | "dest": "rhodecode/public/js", | |
10 | "bower": "bower_components", |
|
11 | "bower": "bower_components", | |
11 | "node_modules": "node_modules" |
|
12 | "node_modules": "node_modules" | |
@@ -31,13 +32,14 b'' | |||||
31 | }, |
|
32 | }, | |
32 | "dist": { |
|
33 | "dist": { | |
33 | "src": [ |
|
34 | "src": [ | |
34 |
"<%= dirs.js.s |
|
35 | "<%= dirs.js.node_modules %>/jquery/dist/jquery.min.js", | |
|
36 | "<%= dirs.js.node_modules %>/mousetrap/mousetrap.min.js", | |||
|
37 | "<%= dirs.js.node_modules %>/moment/min/moment.min.js", | |||
|
38 | "<%= dirs.js.node_modules %>/clipboard/dist/clipboard.min.js", | |||
|
39 | "<%= dirs.js.node_modules %>/favico.js/favico-0.3.10.min.js", | |||
|
40 | "<%= dirs.js.node_modules %>/appenlight-client/appenlight-client.min.js", | |||
35 | "<%= dirs.js.src %>/logging.js", |
|
41 | "<%= dirs.js.src %>/logging.js", | |
36 | "<%= dirs.js.src %>/bootstrap.js", |
|
42 | "<%= dirs.js.src %>/bootstrap.js", | |
37 | "<%= dirs.js.src %>/mousetrap.js", |
|
|||
38 | "<%= dirs.js.src %>/moment.js", |
|
|||
39 | "<%= dirs.js.node_modules %>/appenlight-client/appenlight-client.min.js", |
|
|||
40 | "<%= dirs.js.node_modules %>/favico.js/favico-0.3.10.min.js", |
|
|||
41 | "<%= dirs.js.src %>/i18n_utils.js", |
|
43 | "<%= dirs.js.src %>/i18n_utils.js", | |
42 | "<%= dirs.js.src %>/deform.js", |
|
44 | "<%= dirs.js.src %>/deform.js", | |
43 | "<%= dirs.js.src %>/plugins/jquery.pjax.js", |
|
45 | "<%= dirs.js.src %>/plugins/jquery.pjax.js", | |
@@ -55,9 +57,10 b'' | |||||
55 | "<%= dirs.js.src %>/codemirror/codemirror_hint.js", |
|
57 | "<%= dirs.js.src %>/codemirror/codemirror_hint.js", | |
56 | "<%= dirs.js.src %>/codemirror/codemirror_overlay.js", |
|
58 | "<%= dirs.js.src %>/codemirror/codemirror_overlay.js", | |
57 | "<%= dirs.js.src %>/codemirror/codemirror_placeholder.js", |
|
59 | "<%= dirs.js.src %>/codemirror/codemirror_placeholder.js", | |
|
60 | "<%= dirs.js.src %>/codemirror/codemirror_simplemode.js", | |||
58 | "<%= dirs.js.dest %>/mode/meta.js", |
|
61 | "<%= dirs.js.dest %>/mode/meta.js", | |
59 | "<%= dirs.js.dest %>/mode/meta_ext.js", |
|
62 | "<%= dirs.js.dest %>/mode/meta_ext.js", | |
60 |
"<%= dirs.js. |
|
63 | "<%= dirs.js.src_rc %>/i18n/select2/translations.js", | |
61 | "<%= dirs.js.src %>/rhodecode/utils/array.js", |
|
64 | "<%= dirs.js.src %>/rhodecode/utils/array.js", | |
62 | "<%= dirs.js.src %>/rhodecode/utils/string.js", |
|
65 | "<%= dirs.js.src %>/rhodecode/utils/string.js", | |
63 | "<%= dirs.js.src %>/rhodecode/utils/pyroutes.js", |
|
66 | "<%= dirs.js.src %>/rhodecode/utils/pyroutes.js", |
@@ -12,9 +12,14 b'' | |||||
12 | "vulcanize": "^1.14.8", |
|
12 | "vulcanize": "^1.14.8", | |
13 | "grunt-crisper": "^1.0.1", |
|
13 | "grunt-crisper": "^1.0.1", | |
14 | "grunt-vulcanize": "^1.0.0", |
|
14 | "grunt-vulcanize": "^1.0.0", | |
|
15 | "node2nix": "^1.0.0", | |||
15 | "jshint": "^2.9.1-rc3", |
|
16 | "jshint": "^2.9.1-rc3", | |
16 | "bower": "^1.7.9", |
|
17 | "bower": "^1.7.9", | |
|
18 | "jquery": "1.11.3", | |||
17 | "favico.js": "^0.3.10", |
|
19 | "favico.js": "^0.3.10", | |
18 | "appenlight-client": "git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.0" |
|
20 | "clipboard": "^1.7.1", | |
|
21 | "moment": "^2.18.1", | |||
|
22 | "mousetrap": "^1.6.1", | |||
|
23 | "appenlight-client": "git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.1" | |||
19 | } |
|
24 | } | |
20 | } |
|
25 | } |
@@ -7,7 +7,7 b' buildEnv { name = "bower-env"; ignoreCol' | |||||
7 | (fetchbower "paper-tooltip" "PolymerElements/paper-tooltip#1.1.3" "PolymerElements/paper-tooltip#^1.1.2" "0vmrm1n8k9sk9nvqy03q177axy22pia6i3j1gxbk72j3pqiqvg6k") |
|
7 | (fetchbower "paper-tooltip" "PolymerElements/paper-tooltip#1.1.3" "PolymerElements/paper-tooltip#^1.1.2" "0vmrm1n8k9sk9nvqy03q177axy22pia6i3j1gxbk72j3pqiqvg6k") | |
8 | (fetchbower "paper-toast" "PolymerElements/paper-toast#1.3.0" "PolymerElements/paper-toast#^1.3.0" "0x9rqxsks5455s8pk4aikpp99ijdn6kxr9gvhwh99nbcqdzcxq1m") |
|
8 | (fetchbower "paper-toast" "PolymerElements/paper-toast#1.3.0" "PolymerElements/paper-toast#^1.3.0" "0x9rqxsks5455s8pk4aikpp99ijdn6kxr9gvhwh99nbcqdzcxq1m") | |
9 | (fetchbower "paper-toggle-button" "PolymerElements/paper-toggle-button#1.2.0" "PolymerElements/paper-toggle-button#^1.2.0" "0mphcng3ngspbpg4jjn0mb91nvr4xc1phq3qswib15h6sfww1b2w") |
|
9 | (fetchbower "paper-toggle-button" "PolymerElements/paper-toggle-button#1.2.0" "PolymerElements/paper-toggle-button#^1.2.0" "0mphcng3ngspbpg4jjn0mb91nvr4xc1phq3qswib15h6sfww1b2w") | |
10 |
(fetchbower "iron-ajax" "PolymerElements/iron-ajax#1.4.3" "PolymerElements/iron-ajax#^1.4.3" " |
|
10 | (fetchbower "iron-ajax" "PolymerElements/iron-ajax#1.4.3" "PolymerElements/iron-ajax#^1.4.3" "0m3dx27arwmlcp00b7n516sc5a51f40p9vapr1nvd57l3i3z0pzm") | |
11 | (fetchbower "iron-autogrow-textarea" "PolymerElements/iron-autogrow-textarea#1.0.13" "PolymerElements/iron-autogrow-textarea#^1.0.13" "0zwhpl97vii1s8k0lgain8i9dnw29b0mxc5ixdscx9las13n2lqq") |
|
11 | (fetchbower "iron-autogrow-textarea" "PolymerElements/iron-autogrow-textarea#1.0.13" "PolymerElements/iron-autogrow-textarea#^1.0.13" "0zwhpl97vii1s8k0lgain8i9dnw29b0mxc5ixdscx9las13n2lqq") | |
12 | (fetchbower "iron-a11y-keys" "PolymerElements/iron-a11y-keys#1.0.6" "PolymerElements/iron-a11y-keys#^1.0.6" "1xz3mgghfcxixq28sdb654iaxj4nyi1bzcwf77ydkms6fviqs9mv") |
|
12 | (fetchbower "iron-a11y-keys" "PolymerElements/iron-a11y-keys#1.0.6" "PolymerElements/iron-a11y-keys#^1.0.6" "1xz3mgghfcxixq28sdb654iaxj4nyi1bzcwf77ydkms6fviqs9mv") | |
13 | (fetchbower "iron-flex-layout" "PolymerElements/iron-flex-layout#1.3.1" "PolymerElements/iron-flex-layout#^1.0.0" "0nswv3ih3bhflgcd2wjfmddqswzgqxb2xbq65jk9w3rkj26hplbl") |
|
13 | (fetchbower "iron-flex-layout" "PolymerElements/iron-flex-layout#1.3.1" "PolymerElements/iron-flex-layout#^1.0.0" "0nswv3ih3bhflgcd2wjfmddqswzgqxb2xbq65jk9w3rkj26hplbl") |
This diff has been collapsed as it changes many lines, (2397 lines changed) Show them Hide them | |||||
@@ -40,13 +40,13 b' let' | |||||
40 | sha1 = "f6b2f06fc715264837a7ab6c69a1ce1a689c2c29"; |
|
40 | sha1 = "f6b2f06fc715264837a7ab6c69a1ce1a689c2c29"; | |
41 | }; |
|
41 | }; | |
42 | }; |
|
42 | }; | |
43 |
"grunt-contrib-less-1.4. |
|
43 | "grunt-contrib-less-1.4.1" = { | |
44 | name = "grunt-contrib-less"; |
|
44 | name = "grunt-contrib-less"; | |
45 | packageName = "grunt-contrib-less"; |
|
45 | packageName = "grunt-contrib-less"; | |
46 |
version = "1.4. |
|
46 | version = "1.4.1"; | |
47 | src = fetchurl { |
|
47 | src = fetchurl { | |
48 |
url = "https://registry.npmjs.org/grunt-contrib-less/-/grunt-contrib-less-1.4. |
|
48 | url = "https://registry.npmjs.org/grunt-contrib-less/-/grunt-contrib-less-1.4.1.tgz"; | |
49 | sha1 = "17ee79cad21c9720ee07b3a991fab5103b513514"; |
|
49 | sha1 = "3bbdec0b75d12ceaa55d62943625c0b0861cdf6f"; | |
50 | }; |
|
50 | }; | |
51 | }; |
|
51 | }; | |
52 | "grunt-contrib-watch-0.6.1" = { |
|
52 | "grunt-contrib-watch-0.6.1" = { | |
@@ -58,22 +58,22 b' let' | |||||
58 | sha1 = "64fdcba25a635f5b4da1b6ce6f90da0aeb6e3f15"; |
|
58 | sha1 = "64fdcba25a635f5b4da1b6ce6f90da0aeb6e3f15"; | |
59 | }; |
|
59 | }; | |
60 | }; |
|
60 | }; | |
61 |
"crisper-2. |
|
61 | "crisper-2.1.1" = { | |
62 | name = "crisper"; |
|
62 | name = "crisper"; | |
63 | packageName = "crisper"; |
|
63 | packageName = "crisper"; | |
64 |
version = "2. |
|
64 | version = "2.1.1"; | |
65 | src = fetchurl { |
|
65 | src = fetchurl { | |
66 |
url = "https://registry.npmjs.org/crisper/-/crisper-2. |
|
66 | url = "https://registry.npmjs.org/crisper/-/crisper-2.1.1.tgz"; | |
67 | sha1 = "188a7da3d00dcf0c64eff7f253d23dacffba7197"; |
|
67 | sha1 = "4cc7321c3e90f3c5cbdc3503217f118fd7d5c51c"; | |
68 | }; |
|
68 | }; | |
69 | }; |
|
69 | }; | |
70 |
"vulcanize-1.1 |
|
70 | "vulcanize-1.16.0" = { | |
71 | name = "vulcanize"; |
|
71 | name = "vulcanize"; | |
72 | packageName = "vulcanize"; |
|
72 | packageName = "vulcanize"; | |
73 |
version = "1.1 |
|
73 | version = "1.16.0"; | |
74 | src = fetchurl { |
|
74 | src = fetchurl { | |
75 |
url = "https://registry.npmjs.org/vulcanize/-/vulcanize-1.1 |
|
75 | url = "https://registry.npmjs.org/vulcanize/-/vulcanize-1.16.0.tgz"; | |
76 | sha1 = "3cdd6f81d9baf2c5796ddd6d2d289e45975086f7"; |
|
76 | sha1 = "b0ce3b0044d194ad4908ae4f1a6c6110a6e4d5e6"; | |
77 | }; |
|
77 | }; | |
78 | }; |
|
78 | }; | |
79 | "grunt-crisper-1.0.1" = { |
|
79 | "grunt-crisper-1.0.1" = { | |
@@ -94,22 +94,40 b' let' | |||||
94 | sha1 = "f4d6cfef274f8216c06f6c290e7dbb3b9e9e3b0f"; |
|
94 | sha1 = "f4d6cfef274f8216c06f6c290e7dbb3b9e9e3b0f"; | |
95 | }; |
|
95 | }; | |
96 | }; |
|
96 | }; | |
97 |
" |
|
97 | "node2nix-1.3.0" = { | |
|
98 | name = "node2nix"; | |||
|
99 | packageName = "node2nix"; | |||
|
100 | version = "1.3.0"; | |||
|
101 | src = fetchurl { | |||
|
102 | url = "https://registry.npmjs.org/node2nix/-/node2nix-1.3.0.tgz"; | |||
|
103 | sha1 = "e830a3bc5880dd22ae47be71a147f776542850cc"; | |||
|
104 | }; | |||
|
105 | }; | |||
|
106 | "jshint-2.9.5" = { | |||
98 | name = "jshint"; |
|
107 | name = "jshint"; | |
99 | packageName = "jshint"; |
|
108 | packageName = "jshint"; | |
100 |
version = "2.9. |
|
109 | version = "2.9.5"; | |
101 | src = fetchurl { |
|
110 | src = fetchurl { | |
102 |
url = "https://registry.npmjs.org/jshint/-/jshint-2.9. |
|
111 | url = "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz"; | |
103 | sha1 = "a2e14ff85c2d6bf8c8080e5aa55129ebc6a2d320"; |
|
112 | sha1 = "1e7252915ce681b40827ee14248c46d34e9aa62c"; | |
104 | }; |
|
113 | }; | |
105 | }; |
|
114 | }; | |
106 |
"bower-1. |
|
115 | "bower-1.8.2" = { | |
107 | name = "bower"; |
|
116 | name = "bower"; | |
108 | packageName = "bower"; |
|
117 | packageName = "bower"; | |
109 |
version = "1. |
|
118 | version = "1.8.2"; | |
110 | src = fetchurl { |
|
119 | src = fetchurl { | |
111 |
url = "https://registry.npmjs.org/bower/-/bower-1. |
|
120 | url = "https://registry.npmjs.org/bower/-/bower-1.8.2.tgz"; | |
112 | sha1 = "b7296c2393e0d75edaa6ca39648132dd255812b0"; |
|
121 | sha1 = "adf53529c8d4af02ef24fb8d5341c1419d33e2f7"; | |
|
122 | }; | |||
|
123 | }; | |||
|
124 | "jquery-1.11.3" = { | |||
|
125 | name = "jquery"; | |||
|
126 | packageName = "jquery"; | |||
|
127 | version = "1.11.3"; | |||
|
128 | src = fetchurl { | |||
|
129 | url = "https://registry.npmjs.org/jquery/-/jquery-1.11.3.tgz"; | |||
|
130 | sha1 = "dd8b74278b27102d29df63eae28308a8cfa1b583"; | |||
113 | }; |
|
131 | }; | |
114 | }; |
|
132 | }; | |
115 | "favico.js-0.3.10" = { |
|
133 | "favico.js-0.3.10" = { | |
@@ -121,14 +139,41 b' let' | |||||
121 | sha1 = "80586e27a117f24a8d51c18a99bdc714d4339301"; |
|
139 | sha1 = "80586e27a117f24a8d51c18a99bdc714d4339301"; | |
122 | }; |
|
140 | }; | |
123 | }; |
|
141 | }; | |
124 | "appenlight-client-git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.0" = { |
|
142 | "clipboard-1.7.1" = { | |
|
143 | name = "clipboard"; | |||
|
144 | packageName = "clipboard"; | |||
|
145 | version = "1.7.1"; | |||
|
146 | src = fetchurl { | |||
|
147 | url = "https://registry.npmjs.org/clipboard/-/clipboard-1.7.1.tgz"; | |||
|
148 | sha1 = "360d6d6946e99a7a1fef395e42ba92b5e9b5a16b"; | |||
|
149 | }; | |||
|
150 | }; | |||
|
151 | "moment-2.18.1" = { | |||
|
152 | name = "moment"; | |||
|
153 | packageName = "moment"; | |||
|
154 | version = "2.18.1"; | |||
|
155 | src = fetchurl { | |||
|
156 | url = "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz"; | |||
|
157 | sha1 = "c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"; | |||
|
158 | }; | |||
|
159 | }; | |||
|
160 | "mousetrap-1.6.1" = { | |||
|
161 | name = "mousetrap"; | |||
|
162 | packageName = "mousetrap"; | |||
|
163 | version = "1.6.1"; | |||
|
164 | src = fetchurl { | |||
|
165 | url = "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.1.tgz"; | |||
|
166 | sha1 = "2a085f5c751294c75e7e81f6ec2545b29cbf42d9"; | |||
|
167 | }; | |||
|
168 | }; | |||
|
169 | "appenlight-client-git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.1" = { | |||
125 | name = "appenlight-client"; |
|
170 | name = "appenlight-client"; | |
126 | packageName = "appenlight-client"; |
|
171 | packageName = "appenlight-client"; | |
127 |
version = "0.5. |
|
172 | version = "0.5.1"; | |
128 | src = fetchgit { |
|
173 | src = fetchgit { | |
129 | url = "https://git@github.com/AppEnlight/appenlight-client-js.git"; |
|
174 | url = "https://git@github.com/AppEnlight/appenlight-client-js.git"; | |
130 | rev = "b1d6853345dc3e96468b34537810b3eb77e0764f"; |
|
175 | rev = "14712c64c230fbbe94fcbc8094aef5eb3b90b307"; | |
131 | sha256 = "2ef00aef7dafdecdc1666d2e83fc190a796849985d04a8f0fad148d64aa4f8db"; |
|
176 | sha256 = "92111f1104cbf0b31303c366c0fa752cf68af7ddde40d0161edd1b5fd9dd07f7"; | |
132 | }; |
|
177 | }; | |
133 | }; |
|
178 | }; | |
134 | "async-0.1.22" = { |
|
179 | "async-0.1.22" = { | |
@@ -383,13 +428,13 b' let' | |||||
383 | sha1 = "ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"; |
|
428 | sha1 = "ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"; | |
384 | }; |
|
429 | }; | |
385 | }; |
|
430 | }; | |
386 |
"abbrev-1.0 |
|
431 | "abbrev-1.1.0" = { | |
387 | name = "abbrev"; |
|
432 | name = "abbrev"; | |
388 | packageName = "abbrev"; |
|
433 | packageName = "abbrev"; | |
389 |
version = "1.0 |
|
434 | version = "1.1.0"; | |
390 | src = fetchurl { |
|
435 | src = fetchurl { | |
391 |
url = "https://registry.npmjs.org/abbrev/-/abbrev-1.0 |
|
436 | url = "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz"; | |
392 | sha1 = "91b4792588a7738c25f35dd6f63752a2f8776135"; |
|
437 | sha1 = "d0554c2256636e2f56e7c2e5ad183f859428d81f"; | |
393 | }; |
|
438 | }; | |
394 | }; |
|
439 | }; | |
395 | "argparse-0.1.16" = { |
|
440 | "argparse-0.1.16" = { | |
@@ -509,13 +554,13 b' let' | |||||
509 | sha1 = "535d045ce6b6363fa40117084629995e9df324c7"; |
|
554 | sha1 = "535d045ce6b6363fa40117084629995e9df324c7"; | |
510 | }; |
|
555 | }; | |
511 | }; |
|
556 | }; | |
512 |
"ansi-regex-2. |
|
557 | "ansi-regex-2.1.1" = { | |
513 | name = "ansi-regex"; |
|
558 | name = "ansi-regex"; | |
514 | packageName = "ansi-regex"; |
|
559 | packageName = "ansi-regex"; | |
515 |
version = "2. |
|
560 | version = "2.1.1"; | |
516 | src = fetchurl { |
|
561 | src = fetchurl { | |
517 |
url = "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2. |
|
562 | url = "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"; | |
518 | sha1 = "c5061b6e0ef8a81775e50f5d66151bf6bf371107"; |
|
563 | sha1 = "c3b33ab5ee360d86e0e628f0468ae7ef27d654df"; | |
519 | }; |
|
564 | }; | |
520 | }; |
|
565 | }; | |
521 | "chalk-0.5.1" = { |
|
566 | "chalk-0.5.1" = { | |
@@ -581,40 +626,40 b' let' | |||||
581 | sha1 = "0d8e946967a3d8143f93e24e298525fc1b2235f9"; |
|
626 | sha1 = "0d8e946967a3d8143f93e24e298525fc1b2235f9"; | |
582 | }; |
|
627 | }; | |
583 | }; |
|
628 | }; | |
584 |
"amdefine-1.0. |
|
629 | "amdefine-1.0.1" = { | |
585 | name = "amdefine"; |
|
630 | name = "amdefine"; | |
586 | packageName = "amdefine"; |
|
631 | packageName = "amdefine"; | |
587 |
version = "1.0. |
|
632 | version = "1.0.1"; | |
588 | src = fetchurl { |
|
633 | src = fetchurl { | |
589 |
url = "https://registry.npmjs.org/amdefine/-/amdefine-1.0. |
|
634 | url = "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz"; | |
590 | sha1 = "fd17474700cb5cc9c2b709f0be9d23ce3c198c33"; |
|
635 | sha1 = "4a5282ac164729e93619bcfd3ad151f817ce91f5"; | |
591 | }; |
|
636 | }; | |
592 | }; |
|
637 | }; | |
593 |
"async-2.0 |
|
638 | "async-2.5.0" = { | |
594 | name = "async"; |
|
639 | name = "async"; | |
595 | packageName = "async"; |
|
640 | packageName = "async"; | |
596 |
version = "2.0 |
|
641 | version = "2.5.0"; | |
597 | src = fetchurl { |
|
642 | src = fetchurl { | |
598 |
url = "https://registry.npmjs.org/async/-/async-2.0 |
|
643 | url = "https://registry.npmjs.org/async/-/async-2.5.0.tgz"; | |
599 | sha1 = "b709cc0280a9c36f09f4536be823c838a9049e25"; |
|
644 | sha1 = "843190fd6b7357a0b9e1c956edddd5ec8462b54d"; | |
600 | }; |
|
645 | }; | |
601 | }; |
|
646 | }; | |
602 |
"less-2.7. |
|
647 | "less-2.7.2" = { | |
603 | name = "less"; |
|
648 | name = "less"; | |
604 | packageName = "less"; |
|
649 | packageName = "less"; | |
605 |
version = "2.7. |
|
650 | version = "2.7.2"; | |
606 | src = fetchurl { |
|
651 | src = fetchurl { | |
607 |
url = "https://registry.npmjs.org/less/-/less-2.7. |
|
652 | url = "https://registry.npmjs.org/less/-/less-2.7.2.tgz"; | |
608 | sha1 = "6cbfea22b3b830304e9a5fb371d54fa480c9d7cf"; |
|
653 | sha1 = "368d6cc73e1fb03981183280918743c5dcf9b3df"; | |
609 | }; |
|
654 | }; | |
610 | }; |
|
655 | }; | |
611 |
"lodash-4.1 |
|
656 | "lodash-4.17.4" = { | |
612 | name = "lodash"; |
|
657 | name = "lodash"; | |
613 | packageName = "lodash"; |
|
658 | packageName = "lodash"; | |
614 |
version = "4.1 |
|
659 | version = "4.17.4"; | |
615 | src = fetchurl { |
|
660 | src = fetchurl { | |
616 |
url = "https://registry.npmjs.org/lodash/-/lodash-4.1 |
|
661 | url = "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"; | |
617 | sha1 = "3e626db827048a699281a8a125226326cfc0e652"; |
|
662 | sha1 = "78203a4d1c328ae1d86dca6460e369b57f4055ae"; | |
618 | }; |
|
663 | }; | |
619 | }; |
|
664 | }; | |
620 | "errno-0.1.4" = { |
|
665 | "errno-0.1.4" = { | |
@@ -626,31 +671,31 b' let' | |||||
626 | sha1 = "b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"; |
|
671 | sha1 = "b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"; | |
627 | }; |
|
672 | }; | |
628 | }; |
|
673 | }; | |
629 |
"graceful-fs-4.1. |
|
674 | "graceful-fs-4.1.11" = { | |
630 | name = "graceful-fs"; |
|
675 | name = "graceful-fs"; | |
631 | packageName = "graceful-fs"; |
|
676 | packageName = "graceful-fs"; | |
632 |
version = "4.1. |
|
677 | version = "4.1.11"; | |
633 | src = fetchurl { |
|
678 | src = fetchurl { | |
634 |
url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1. |
|
679 | url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"; | |
635 | sha1 = "da3e11135eb2168bdd374532c4e2649751672890"; |
|
680 | sha1 = "0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"; | |
636 | }; |
|
681 | }; | |
637 | }; |
|
682 | }; | |
638 |
"image-size-0.5. |
|
683 | "image-size-0.5.5" = { | |
639 | name = "image-size"; |
|
684 | name = "image-size"; | |
640 | packageName = "image-size"; |
|
685 | packageName = "image-size"; | |
641 |
version = "0.5. |
|
686 | version = "0.5.5"; | |
642 | src = fetchurl { |
|
687 | src = fetchurl { | |
643 |
url = "https://registry.npmjs.org/image-size/-/image-size-0.5. |
|
688 | url = "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz"; | |
644 | sha1 = "be7aed1c37b5ac3d9ba1d66a24b4c47ff8397651"; |
|
689 | sha1 = "09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"; | |
645 | }; |
|
690 | }; | |
646 | }; |
|
691 | }; | |
647 |
"mime-1. |
|
692 | "mime-1.4.0" = { | |
648 | name = "mime"; |
|
693 | name = "mime"; | |
649 | packageName = "mime"; |
|
694 | packageName = "mime"; | |
650 |
version = "1. |
|
695 | version = "1.4.0"; | |
651 | src = fetchurl { |
|
696 | src = fetchurl { | |
652 |
url = "https://registry.npmjs.org/mime/-/mime-1. |
|
697 | url = "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz"; | |
653 | sha1 = "115f9e3b6b3daf2959983cb38f149a2d40eb5d53"; |
|
698 | sha1 = "69e9e0db51d44f2a3b56e48b7817d7d137f1a343"; | |
654 | }; |
|
699 | }; | |
655 | }; |
|
700 | }; | |
656 | "mkdirp-0.5.1" = { |
|
701 | "mkdirp-0.5.1" = { | |
@@ -662,22 +707,31 b' let' | |||||
662 | sha1 = "30057438eac6cf7f8c4767f38648d6697d75c903"; |
|
707 | sha1 = "30057438eac6cf7f8c4767f38648d6697d75c903"; | |
663 | }; |
|
708 | }; | |
664 | }; |
|
709 | }; | |
665 |
"promise-7. |
|
710 | "promise-7.3.1" = { | |
666 | name = "promise"; |
|
711 | name = "promise"; | |
667 | packageName = "promise"; |
|
712 | packageName = "promise"; | |
668 |
version = "7. |
|
713 | version = "7.3.1"; | |
669 | src = fetchurl { |
|
714 | src = fetchurl { | |
670 |
url = "https://registry.npmjs.org/promise/-/promise-7. |
|
715 | url = "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz"; | |
671 | sha1 = "489654c692616b8aa55b0724fa809bb7db49c5bf"; |
|
716 | sha1 = "064b72602b18f90f29192b8b1bc418ffd1ebd3bf"; | |
672 | }; |
|
717 | }; | |
673 | }; |
|
718 | }; | |
674 |
"source-map-0.5. |
|
719 | "source-map-0.5.7" = { | |
675 | name = "source-map"; |
|
720 | name = "source-map"; | |
676 | packageName = "source-map"; |
|
721 | packageName = "source-map"; | |
677 |
version = "0.5. |
|
722 | version = "0.5.7"; | |
678 | src = fetchurl { |
|
723 | src = fetchurl { | |
679 |
url = "https://registry.npmjs.org/source-map/-/source-map-0.5. |
|
724 | url = "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"; | |
680 | sha1 = "75ce38f52bf0733c5a7f0c118d81334a2bb5f412"; |
|
725 | sha1 = "8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"; | |
|
726 | }; | |||
|
727 | }; | |||
|
728 | "request-2.82.0" = { | |||
|
729 | name = "request"; | |||
|
730 | packageName = "request"; | |||
|
731 | version = "2.82.0"; | |||
|
732 | src = fetchurl { | |||
|
733 | url = "https://registry.npmjs.org/request/-/request-2.82.0.tgz"; | |||
|
734 | sha1 = "2ba8a92cd7ac45660ea2b10a53ae67cd247516ea"; | |||
681 | }; |
|
735 | }; | |
682 | }; |
|
736 | }; | |
683 | "prr-0.0.0" = { |
|
737 | "prr-0.0.0" = { | |
@@ -698,13 +752,481 b' let' | |||||
698 | sha1 = "857fcabfc3397d2625b8228262e86aa7a011b05d"; |
|
752 | sha1 = "857fcabfc3397d2625b8228262e86aa7a011b05d"; | |
699 | }; |
|
753 | }; | |
700 | }; |
|
754 | }; | |
701 |
"asap-2.0. |
|
755 | "asap-2.0.6" = { | |
702 | name = "asap"; |
|
756 | name = "asap"; | |
703 | packageName = "asap"; |
|
757 | packageName = "asap"; | |
704 |
version = "2.0. |
|
758 | version = "2.0.6"; | |
|
759 | src = fetchurl { | |||
|
760 | url = "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz"; | |||
|
761 | sha1 = "e50347611d7e690943208bbdafebcbc2fb866d46"; | |||
|
762 | }; | |||
|
763 | }; | |||
|
764 | "aws-sign2-0.7.0" = { | |||
|
765 | name = "aws-sign2"; | |||
|
766 | packageName = "aws-sign2"; | |||
|
767 | version = "0.7.0"; | |||
|
768 | src = fetchurl { | |||
|
769 | url = "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz"; | |||
|
770 | sha1 = "b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"; | |||
|
771 | }; | |||
|
772 | }; | |||
|
773 | "aws4-1.6.0" = { | |||
|
774 | name = "aws4"; | |||
|
775 | packageName = "aws4"; | |||
|
776 | version = "1.6.0"; | |||
|
777 | src = fetchurl { | |||
|
778 | url = "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz"; | |||
|
779 | sha1 = "83ef5ca860b2b32e4a0deedee8c771b9db57471e"; | |||
|
780 | }; | |||
|
781 | }; | |||
|
782 | "caseless-0.12.0" = { | |||
|
783 | name = "caseless"; | |||
|
784 | packageName = "caseless"; | |||
|
785 | version = "0.12.0"; | |||
|
786 | src = fetchurl { | |||
|
787 | url = "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz"; | |||
|
788 | sha1 = "1b681c21ff84033c826543090689420d187151dc"; | |||
|
789 | }; | |||
|
790 | }; | |||
|
791 | "combined-stream-1.0.5" = { | |||
|
792 | name = "combined-stream"; | |||
|
793 | packageName = "combined-stream"; | |||
|
794 | version = "1.0.5"; | |||
|
795 | src = fetchurl { | |||
|
796 | url = "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"; | |||
|
797 | sha1 = "938370a57b4a51dea2c77c15d5c5fdf895164009"; | |||
|
798 | }; | |||
|
799 | }; | |||
|
800 | "extend-3.0.1" = { | |||
|
801 | name = "extend"; | |||
|
802 | packageName = "extend"; | |||
|
803 | version = "3.0.1"; | |||
|
804 | src = fetchurl { | |||
|
805 | url = "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz"; | |||
|
806 | sha1 = "a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"; | |||
|
807 | }; | |||
|
808 | }; | |||
|
809 | "forever-agent-0.6.1" = { | |||
|
810 | name = "forever-agent"; | |||
|
811 | packageName = "forever-agent"; | |||
|
812 | version = "0.6.1"; | |||
|
813 | src = fetchurl { | |||
|
814 | url = "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"; | |||
|
815 | sha1 = "fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"; | |||
|
816 | }; | |||
|
817 | }; | |||
|
818 | "form-data-2.3.1" = { | |||
|
819 | name = "form-data"; | |||
|
820 | packageName = "form-data"; | |||
|
821 | version = "2.3.1"; | |||
|
822 | src = fetchurl { | |||
|
823 | url = "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz"; | |||
|
824 | sha1 = "6fb94fbd71885306d73d15cc497fe4cc4ecd44bf"; | |||
|
825 | }; | |||
|
826 | }; | |||
|
827 | "har-validator-5.0.3" = { | |||
|
828 | name = "har-validator"; | |||
|
829 | packageName = "har-validator"; | |||
|
830 | version = "5.0.3"; | |||
|
831 | src = fetchurl { | |||
|
832 | url = "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz"; | |||
|
833 | sha1 = "ba402c266194f15956ef15e0fcf242993f6a7dfd"; | |||
|
834 | }; | |||
|
835 | }; | |||
|
836 | "hawk-6.0.2" = { | |||
|
837 | name = "hawk"; | |||
|
838 | packageName = "hawk"; | |||
|
839 | version = "6.0.2"; | |||
|
840 | src = fetchurl { | |||
|
841 | url = "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz"; | |||
|
842 | sha1 = "af4d914eb065f9b5ce4d9d11c1cb2126eecc3038"; | |||
|
843 | }; | |||
|
844 | }; | |||
|
845 | "http-signature-1.2.0" = { | |||
|
846 | name = "http-signature"; | |||
|
847 | packageName = "http-signature"; | |||
|
848 | version = "1.2.0"; | |||
|
849 | src = fetchurl { | |||
|
850 | url = "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz"; | |||
|
851 | sha1 = "9aecd925114772f3d95b65a60abb8f7c18fbace1"; | |||
|
852 | }; | |||
|
853 | }; | |||
|
854 | "is-typedarray-1.0.0" = { | |||
|
855 | name = "is-typedarray"; | |||
|
856 | packageName = "is-typedarray"; | |||
|
857 | version = "1.0.0"; | |||
|
858 | src = fetchurl { | |||
|
859 | url = "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"; | |||
|
860 | sha1 = "e479c80858df0c1b11ddda6940f96011fcda4a9a"; | |||
|
861 | }; | |||
|
862 | }; | |||
|
863 | "isstream-0.1.2" = { | |||
|
864 | name = "isstream"; | |||
|
865 | packageName = "isstream"; | |||
|
866 | version = "0.1.2"; | |||
|
867 | src = fetchurl { | |||
|
868 | url = "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"; | |||
|
869 | sha1 = "47e63f7af55afa6f92e1500e690eb8b8529c099a"; | |||
|
870 | }; | |||
|
871 | }; | |||
|
872 | "json-stringify-safe-5.0.1" = { | |||
|
873 | name = "json-stringify-safe"; | |||
|
874 | packageName = "json-stringify-safe"; | |||
|
875 | version = "5.0.1"; | |||
|
876 | src = fetchurl { | |||
|
877 | url = "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"; | |||
|
878 | sha1 = "1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"; | |||
|
879 | }; | |||
|
880 | }; | |||
|
881 | "mime-types-2.1.17" = { | |||
|
882 | name = "mime-types"; | |||
|
883 | packageName = "mime-types"; | |||
|
884 | version = "2.1.17"; | |||
|
885 | src = fetchurl { | |||
|
886 | url = "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz"; | |||
|
887 | sha1 = "09d7a393f03e995a79f8af857b70a9e0ab16557a"; | |||
|
888 | }; | |||
|
889 | }; | |||
|
890 | "oauth-sign-0.8.2" = { | |||
|
891 | name = "oauth-sign"; | |||
|
892 | packageName = "oauth-sign"; | |||
|
893 | version = "0.8.2"; | |||
|
894 | src = fetchurl { | |||
|
895 | url = "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz"; | |||
|
896 | sha1 = "46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"; | |||
|
897 | }; | |||
|
898 | }; | |||
|
899 | "performance-now-2.1.0" = { | |||
|
900 | name = "performance-now"; | |||
|
901 | packageName = "performance-now"; | |||
|
902 | version = "2.1.0"; | |||
|
903 | src = fetchurl { | |||
|
904 | url = "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz"; | |||
|
905 | sha1 = "6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"; | |||
|
906 | }; | |||
|
907 | }; | |||
|
908 | "qs-6.5.1" = { | |||
|
909 | name = "qs"; | |||
|
910 | packageName = "qs"; | |||
|
911 | version = "6.5.1"; | |||
|
912 | src = fetchurl { | |||
|
913 | url = "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz"; | |||
|
914 | sha1 = "349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"; | |||
|
915 | }; | |||
|
916 | }; | |||
|
917 | "safe-buffer-5.1.1" = { | |||
|
918 | name = "safe-buffer"; | |||
|
919 | packageName = "safe-buffer"; | |||
|
920 | version = "5.1.1"; | |||
|
921 | src = fetchurl { | |||
|
922 | url = "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz"; | |||
|
923 | sha1 = "893312af69b2123def71f57889001671eeb2c853"; | |||
|
924 | }; | |||
|
925 | }; | |||
|
926 | "stringstream-0.0.5" = { | |||
|
927 | name = "stringstream"; | |||
|
928 | packageName = "stringstream"; | |||
|
929 | version = "0.0.5"; | |||
|
930 | src = fetchurl { | |||
|
931 | url = "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"; | |||
|
932 | sha1 = "4e484cd4de5a0bbbee18e46307710a8a81621878"; | |||
|
933 | }; | |||
|
934 | }; | |||
|
935 | "tough-cookie-2.3.3" = { | |||
|
936 | name = "tough-cookie"; | |||
|
937 | packageName = "tough-cookie"; | |||
|
938 | version = "2.3.3"; | |||
|
939 | src = fetchurl { | |||
|
940 | url = "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz"; | |||
|
941 | sha1 = "0b618a5565b6dea90bf3425d04d55edc475a7561"; | |||
|
942 | }; | |||
|
943 | }; | |||
|
944 | "tunnel-agent-0.6.0" = { | |||
|
945 | name = "tunnel-agent"; | |||
|
946 | packageName = "tunnel-agent"; | |||
|
947 | version = "0.6.0"; | |||
|
948 | src = fetchurl { | |||
|
949 | url = "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz"; | |||
|
950 | sha1 = "27a5dea06b36b04a0a9966774b290868f0fc40fd"; | |||
|
951 | }; | |||
|
952 | }; | |||
|
953 | "uuid-3.1.0" = { | |||
|
954 | name = "uuid"; | |||
|
955 | packageName = "uuid"; | |||
|
956 | version = "3.1.0"; | |||
|
957 | src = fetchurl { | |||
|
958 | url = "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz"; | |||
|
959 | sha1 = "3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"; | |||
|
960 | }; | |||
|
961 | }; | |||
|
962 | "delayed-stream-1.0.0" = { | |||
|
963 | name = "delayed-stream"; | |||
|
964 | packageName = "delayed-stream"; | |||
|
965 | version = "1.0.0"; | |||
|
966 | src = fetchurl { | |||
|
967 | url = "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"; | |||
|
968 | sha1 = "df3ae199acadfb7d440aaae0b29e2272b24ec619"; | |||
|
969 | }; | |||
|
970 | }; | |||
|
971 | "asynckit-0.4.0" = { | |||
|
972 | name = "asynckit"; | |||
|
973 | packageName = "asynckit"; | |||
|
974 | version = "0.4.0"; | |||
|
975 | src = fetchurl { | |||
|
976 | url = "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"; | |||
|
977 | sha1 = "c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"; | |||
|
978 | }; | |||
|
979 | }; | |||
|
980 | "ajv-5.2.2" = { | |||
|
981 | name = "ajv"; | |||
|
982 | packageName = "ajv"; | |||
|
983 | version = "5.2.2"; | |||
|
984 | src = fetchurl { | |||
|
985 | url = "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz"; | |||
|
986 | sha1 = "47c68d69e86f5d953103b0074a9430dc63da5e39"; | |||
|
987 | }; | |||
|
988 | }; | |||
|
989 | "har-schema-2.0.0" = { | |||
|
990 | name = "har-schema"; | |||
|
991 | packageName = "har-schema"; | |||
|
992 | version = "2.0.0"; | |||
705 | src = fetchurl { |
|
993 | src = fetchurl { | |
706 |
url = "https://registry.npmjs.org/asa |
|
994 | url = "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz"; | |
707 | sha1 = "522765b50c3510490e52d7dcfe085ef9ba96958f"; |
|
995 | sha1 = "a94c2224ebcac04782a0d9035521f24735b7ec92"; | |
|
996 | }; | |||
|
997 | }; | |||
|
998 | "co-4.6.0" = { | |||
|
999 | name = "co"; | |||
|
1000 | packageName = "co"; | |||
|
1001 | version = "4.6.0"; | |||
|
1002 | src = fetchurl { | |||
|
1003 | url = "https://registry.npmjs.org/co/-/co-4.6.0.tgz"; | |||
|
1004 | sha1 = "6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"; | |||
|
1005 | }; | |||
|
1006 | }; | |||
|
1007 | "fast-deep-equal-1.0.0" = { | |||
|
1008 | name = "fast-deep-equal"; | |||
|
1009 | packageName = "fast-deep-equal"; | |||
|
1010 | version = "1.0.0"; | |||
|
1011 | src = fetchurl { | |||
|
1012 | url = "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz"; | |||
|
1013 | sha1 = "96256a3bc975595eb36d82e9929d060d893439ff"; | |||
|
1014 | }; | |||
|
1015 | }; | |||
|
1016 | "json-schema-traverse-0.3.1" = { | |||
|
1017 | name = "json-schema-traverse"; | |||
|
1018 | packageName = "json-schema-traverse"; | |||
|
1019 | version = "0.3.1"; | |||
|
1020 | src = fetchurl { | |||
|
1021 | url = "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz"; | |||
|
1022 | sha1 = "349a6d44c53a51de89b40805c5d5e59b417d3340"; | |||
|
1023 | }; | |||
|
1024 | }; | |||
|
1025 | "json-stable-stringify-1.0.1" = { | |||
|
1026 | name = "json-stable-stringify"; | |||
|
1027 | packageName = "json-stable-stringify"; | |||
|
1028 | version = "1.0.1"; | |||
|
1029 | src = fetchurl { | |||
|
1030 | url = "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz"; | |||
|
1031 | sha1 = "9a759d39c5f2ff503fd5300646ed445f88c4f9af"; | |||
|
1032 | }; | |||
|
1033 | }; | |||
|
1034 | "jsonify-0.0.0" = { | |||
|
1035 | name = "jsonify"; | |||
|
1036 | packageName = "jsonify"; | |||
|
1037 | version = "0.0.0"; | |||
|
1038 | src = fetchurl { | |||
|
1039 | url = "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"; | |||
|
1040 | sha1 = "2c74b6ee41d93ca51b7b5aaee8f503631d252a73"; | |||
|
1041 | }; | |||
|
1042 | }; | |||
|
1043 | "hoek-4.2.0" = { | |||
|
1044 | name = "hoek"; | |||
|
1045 | packageName = "hoek"; | |||
|
1046 | version = "4.2.0"; | |||
|
1047 | src = fetchurl { | |||
|
1048 | url = "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz"; | |||
|
1049 | sha1 = "72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"; | |||
|
1050 | }; | |||
|
1051 | }; | |||
|
1052 | "boom-4.3.1" = { | |||
|
1053 | name = "boom"; | |||
|
1054 | packageName = "boom"; | |||
|
1055 | version = "4.3.1"; | |||
|
1056 | src = fetchurl { | |||
|
1057 | url = "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz"; | |||
|
1058 | sha1 = "4f8a3005cb4a7e3889f749030fd25b96e01d2e31"; | |||
|
1059 | }; | |||
|
1060 | }; | |||
|
1061 | "cryptiles-3.1.2" = { | |||
|
1062 | name = "cryptiles"; | |||
|
1063 | packageName = "cryptiles"; | |||
|
1064 | version = "3.1.2"; | |||
|
1065 | src = fetchurl { | |||
|
1066 | url = "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz"; | |||
|
1067 | sha1 = "a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe"; | |||
|
1068 | }; | |||
|
1069 | }; | |||
|
1070 | "sntp-2.0.2" = { | |||
|
1071 | name = "sntp"; | |||
|
1072 | packageName = "sntp"; | |||
|
1073 | version = "2.0.2"; | |||
|
1074 | src = fetchurl { | |||
|
1075 | url = "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz"; | |||
|
1076 | sha1 = "5064110f0af85f7cfdb7d6b67a40028ce52b4b2b"; | |||
|
1077 | }; | |||
|
1078 | }; | |||
|
1079 | "boom-5.2.0" = { | |||
|
1080 | name = "boom"; | |||
|
1081 | packageName = "boom"; | |||
|
1082 | version = "5.2.0"; | |||
|
1083 | src = fetchurl { | |||
|
1084 | url = "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz"; | |||
|
1085 | sha1 = "5dd9da6ee3a5f302077436290cb717d3f4a54e02"; | |||
|
1086 | }; | |||
|
1087 | }; | |||
|
1088 | "assert-plus-1.0.0" = { | |||
|
1089 | name = "assert-plus"; | |||
|
1090 | packageName = "assert-plus"; | |||
|
1091 | version = "1.0.0"; | |||
|
1092 | src = fetchurl { | |||
|
1093 | url = "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"; | |||
|
1094 | sha1 = "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"; | |||
|
1095 | }; | |||
|
1096 | }; | |||
|
1097 | "jsprim-1.4.1" = { | |||
|
1098 | name = "jsprim"; | |||
|
1099 | packageName = "jsprim"; | |||
|
1100 | version = "1.4.1"; | |||
|
1101 | src = fetchurl { | |||
|
1102 | url = "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz"; | |||
|
1103 | sha1 = "313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"; | |||
|
1104 | }; | |||
|
1105 | }; | |||
|
1106 | "sshpk-1.13.1" = { | |||
|
1107 | name = "sshpk"; | |||
|
1108 | packageName = "sshpk"; | |||
|
1109 | version = "1.13.1"; | |||
|
1110 | src = fetchurl { | |||
|
1111 | url = "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz"; | |||
|
1112 | sha1 = "512df6da6287144316dc4c18fe1cf1d940739be3"; | |||
|
1113 | }; | |||
|
1114 | }; | |||
|
1115 | "extsprintf-1.3.0" = { | |||
|
1116 | name = "extsprintf"; | |||
|
1117 | packageName = "extsprintf"; | |||
|
1118 | version = "1.3.0"; | |||
|
1119 | src = fetchurl { | |||
|
1120 | url = "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz"; | |||
|
1121 | sha1 = "96918440e3041a7a414f8c52e3c574eb3c3e1e05"; | |||
|
1122 | }; | |||
|
1123 | }; | |||
|
1124 | "json-schema-0.2.3" = { | |||
|
1125 | name = "json-schema"; | |||
|
1126 | packageName = "json-schema"; | |||
|
1127 | version = "0.2.3"; | |||
|
1128 | src = fetchurl { | |||
|
1129 | url = "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz"; | |||
|
1130 | sha1 = "b480c892e59a2f05954ce727bd3f2a4e882f9e13"; | |||
|
1131 | }; | |||
|
1132 | }; | |||
|
1133 | "verror-1.10.0" = { | |||
|
1134 | name = "verror"; | |||
|
1135 | packageName = "verror"; | |||
|
1136 | version = "1.10.0"; | |||
|
1137 | src = fetchurl { | |||
|
1138 | url = "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz"; | |||
|
1139 | sha1 = "3a105ca17053af55d6e270c1f8288682e18da400"; | |||
|
1140 | }; | |||
|
1141 | }; | |||
|
1142 | "core-util-is-1.0.2" = { | |||
|
1143 | name = "core-util-is"; | |||
|
1144 | packageName = "core-util-is"; | |||
|
1145 | version = "1.0.2"; | |||
|
1146 | src = fetchurl { | |||
|
1147 | url = "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"; | |||
|
1148 | sha1 = "b5fd54220aa2bc5ab57aab7140c940754503c1a7"; | |||
|
1149 | }; | |||
|
1150 | }; | |||
|
1151 | "asn1-0.2.3" = { | |||
|
1152 | name = "asn1"; | |||
|
1153 | packageName = "asn1"; | |||
|
1154 | version = "0.2.3"; | |||
|
1155 | src = fetchurl { | |||
|
1156 | url = "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"; | |||
|
1157 | sha1 = "dac8787713c9966849fc8180777ebe9c1ddf3b86"; | |||
|
1158 | }; | |||
|
1159 | }; | |||
|
1160 | "dashdash-1.14.1" = { | |||
|
1161 | name = "dashdash"; | |||
|
1162 | packageName = "dashdash"; | |||
|
1163 | version = "1.14.1"; | |||
|
1164 | src = fetchurl { | |||
|
1165 | url = "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz"; | |||
|
1166 | sha1 = "853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"; | |||
|
1167 | }; | |||
|
1168 | }; | |||
|
1169 | "getpass-0.1.7" = { | |||
|
1170 | name = "getpass"; | |||
|
1171 | packageName = "getpass"; | |||
|
1172 | version = "0.1.7"; | |||
|
1173 | src = fetchurl { | |||
|
1174 | url = "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz"; | |||
|
1175 | sha1 = "5eff8e3e684d569ae4cb2b1282604e8ba62149fa"; | |||
|
1176 | }; | |||
|
1177 | }; | |||
|
1178 | "jsbn-0.1.1" = { | |||
|
1179 | name = "jsbn"; | |||
|
1180 | packageName = "jsbn"; | |||
|
1181 | version = "0.1.1"; | |||
|
1182 | src = fetchurl { | |||
|
1183 | url = "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz"; | |||
|
1184 | sha1 = "a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"; | |||
|
1185 | }; | |||
|
1186 | }; | |||
|
1187 | "tweetnacl-0.14.5" = { | |||
|
1188 | name = "tweetnacl"; | |||
|
1189 | packageName = "tweetnacl"; | |||
|
1190 | version = "0.14.5"; | |||
|
1191 | src = fetchurl { | |||
|
1192 | url = "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz"; | |||
|
1193 | sha1 = "5ae68177f192d4456269d108afa93ff8743f4f64"; | |||
|
1194 | }; | |||
|
1195 | }; | |||
|
1196 | "ecc-jsbn-0.1.1" = { | |||
|
1197 | name = "ecc-jsbn"; | |||
|
1198 | packageName = "ecc-jsbn"; | |||
|
1199 | version = "0.1.1"; | |||
|
1200 | src = fetchurl { | |||
|
1201 | url = "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz"; | |||
|
1202 | sha1 = "0fc73a9ed5f0d53c38193398523ef7e543777505"; | |||
|
1203 | }; | |||
|
1204 | }; | |||
|
1205 | "bcrypt-pbkdf-1.0.1" = { | |||
|
1206 | name = "bcrypt-pbkdf"; | |||
|
1207 | packageName = "bcrypt-pbkdf"; | |||
|
1208 | version = "1.0.1"; | |||
|
1209 | src = fetchurl { | |||
|
1210 | url = "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz"; | |||
|
1211 | sha1 = "63bc5dcb61331b92bc05fd528953c33462a06f8d"; | |||
|
1212 | }; | |||
|
1213 | }; | |||
|
1214 | "mime-db-1.30.0" = { | |||
|
1215 | name = "mime-db"; | |||
|
1216 | packageName = "mime-db"; | |||
|
1217 | version = "1.30.0"; | |||
|
1218 | src = fetchurl { | |||
|
1219 | url = "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz"; | |||
|
1220 | sha1 = "74c643da2dd9d6a45399963465b26d5ca7d71f01"; | |||
|
1221 | }; | |||
|
1222 | }; | |||
|
1223 | "punycode-1.4.1" = { | |||
|
1224 | name = "punycode"; | |||
|
1225 | packageName = "punycode"; | |||
|
1226 | version = "1.4.1"; | |||
|
1227 | src = fetchurl { | |||
|
1228 | url = "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz"; | |||
|
1229 | sha1 = "c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"; | |||
708 | }; |
|
1230 | }; | |
709 | }; |
|
1231 | }; | |
710 | "gaze-0.5.2" = { |
|
1232 | "gaze-0.5.2" = { | |
@@ -797,13 +1319,22 b' let' | |||||
797 | sha1 = "ca7416f20a5e3f9c3b86180f96295fa3d0b52e0d"; |
|
1319 | sha1 = "ca7416f20a5e3f9c3b86180f96295fa3d0b52e0d"; | |
798 | }; |
|
1320 | }; | |
799 | }; |
|
1321 | }; | |
800 |
"command-line-args- |
|
1322 | "command-line-args-3.0.5" = { | |
801 | name = "command-line-args"; |
|
1323 | name = "command-line-args"; | |
802 | packageName = "command-line-args"; |
|
1324 | packageName = "command-line-args"; | |
803 |
version = " |
|
1325 | version = "3.0.5"; | |
804 | src = fetchurl { |
|
1326 | src = fetchurl { | |
805 |
url = "https://registry.npmjs.org/command-line-args/-/command-line-args- |
|
1327 | url = "https://registry.npmjs.org/command-line-args/-/command-line-args-3.0.5.tgz"; | |
806 | sha1 = "f197d6eaff34c9085577484b2864375b294f5697"; |
|
1328 | sha1 = "5bd4ad45e7983e5c1344918e40280ee2693c5ac0"; | |
|
1329 | }; | |||
|
1330 | }; | |||
|
1331 | "command-line-usage-3.0.8" = { | |||
|
1332 | name = "command-line-usage"; | |||
|
1333 | packageName = "command-line-usage"; | |||
|
1334 | version = "3.0.8"; | |||
|
1335 | src = fetchurl { | |||
|
1336 | url = "https://registry.npmjs.org/command-line-usage/-/command-line-usage-3.0.8.tgz"; | |||
|
1337 | sha1 = "b6a20978c1b383477f5c11a529428b880bfe0f4d"; | |||
807 | }; |
|
1338 | }; | |
808 | }; |
|
1339 | }; | |
809 | "dom5-1.3.6" = { |
|
1340 | "dom5-1.3.6" = { | |
@@ -815,31 +1346,13 b' let' | |||||
815 | sha1 = "a7088a9fc5f3b08dc9f6eda4c7abaeb241945e0d"; |
|
1346 | sha1 = "a7088a9fc5f3b08dc9f6eda4c7abaeb241945e0d"; | |
816 | }; |
|
1347 | }; | |
817 | }; |
|
1348 | }; | |
818 |
"array-back-1.0. |
|
1349 | "array-back-1.0.4" = { | |
819 | name = "array-back"; |
|
1350 | name = "array-back"; | |
820 | packageName = "array-back"; |
|
1351 | packageName = "array-back"; | |
821 |
version = "1.0. |
|
1352 | version = "1.0.4"; | |
822 | src = fetchurl { |
|
|||
823 | url = "https://registry.npmjs.org/array-back/-/array-back-1.0.3.tgz"; |
|
|||
824 | sha1 = "f1128a5cf1b91c80bed4a218f8c5b635c8b10663"; |
|
|||
825 | }; |
|
|||
826 | }; |
|
|||
827 | "command-line-usage-2.0.5" = { |
|
|||
828 | name = "command-line-usage"; |
|
|||
829 | packageName = "command-line-usage"; |
|
|||
830 | version = "2.0.5"; |
|
|||
831 | src = fetchurl { |
|
1353 | src = fetchurl { | |
832 |
url = "https://registry.npmjs.org/c |
|
1354 | url = "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz"; | |
833 | sha1 = "f80c35ca5e8624841923ea3be3b9bfbf4f7be27b"; |
|
1355 | sha1 = "644ba7f095f7ffcf7c43b5f0dc39d3c1f03c063b"; | |
834 | }; |
|
|||
835 | }; |
|
|||
836 | "core-js-2.4.1" = { |
|
|||
837 | name = "core-js"; |
|
|||
838 | packageName = "core-js"; |
|
|||
839 | version = "2.4.1"; |
|
|||
840 | src = fetchurl { |
|
|||
841 | url = "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz"; |
|
|||
842 | sha1 = "4de911e667b0eae9124e34254b53aea6fc618d3e"; |
|
|||
843 | }; |
|
1356 | }; | |
844 | }; |
|
1357 | }; | |
845 | "feature-detect-es6-1.3.1" = { |
|
1358 | "feature-detect-es6-1.3.1" = { | |
@@ -851,139 +1364,22 b' let' | |||||
851 | sha1 = "f888736af9cb0c91f55663bfa4762eb96ee7047f"; |
|
1364 | sha1 = "f888736af9cb0c91f55663bfa4762eb96ee7047f"; | |
852 | }; |
|
1365 | }; | |
853 | }; |
|
1366 | }; | |
854 |
"find-replace-1.0. |
|
1367 | "find-replace-1.0.3" = { | |
855 | name = "find-replace"; |
|
1368 | name = "find-replace"; | |
856 | packageName = "find-replace"; |
|
1369 | packageName = "find-replace"; | |
857 |
version = "1.0. |
|
1370 | version = "1.0.3"; | |
858 | src = fetchurl { |
|
|||
859 | url = "https://registry.npmjs.org/find-replace/-/find-replace-1.0.2.tgz"; |
|
|||
860 | sha1 = "a2d6ce740d15f0d92b1b26763e2ce9c0e361fd98"; |
|
|||
861 | }; |
|
|||
862 | }; |
|
|||
863 | "typical-2.6.0" = { |
|
|||
864 | name = "typical"; |
|
|||
865 | packageName = "typical"; |
|
|||
866 | version = "2.6.0"; |
|
|||
867 | src = fetchurl { |
|
|||
868 | url = "https://registry.npmjs.org/typical/-/typical-2.6.0.tgz"; |
|
|||
869 | sha1 = "89d51554ab139848a65bcc2c8772f8fb450c40ed"; |
|
|||
870 | }; |
|
|||
871 | }; |
|
|||
872 | "ansi-escape-sequences-2.2.2" = { |
|
|||
873 | name = "ansi-escape-sequences"; |
|
|||
874 | packageName = "ansi-escape-sequences"; |
|
|||
875 | version = "2.2.2"; |
|
|||
876 | src = fetchurl { |
|
|||
877 | url = "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-2.2.2.tgz"; |
|
|||
878 | sha1 = "174c78d6f8b7de75f8957ae81c7f72210c701635"; |
|
|||
879 | }; |
|
|||
880 | }; |
|
|||
881 | "column-layout-2.1.4" = { |
|
|||
882 | name = "column-layout"; |
|
|||
883 | packageName = "column-layout"; |
|
|||
884 | version = "2.1.4"; |
|
|||
885 | src = fetchurl { |
|
1371 | src = fetchurl { | |
886 |
url = "https://registry.npmjs.org/ |
|
1372 | url = "https://registry.npmjs.org/find-replace/-/find-replace-1.0.3.tgz"; | |
887 | sha1 = "ed2857092ccf8338026fe538379d9672d70b3641"; |
|
1373 | sha1 = "b88e7364d2d9c959559f388c66670d6130441fa0"; | |
888 | }; |
|
|||
889 | }; |
|
|||
890 | "wordwrapjs-1.2.1" = { |
|
|||
891 | name = "wordwrapjs"; |
|
|||
892 | packageName = "wordwrapjs"; |
|
|||
893 | version = "1.2.1"; |
|
|||
894 | src = fetchurl { |
|
|||
895 | url = "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-1.2.1.tgz"; |
|
|||
896 | sha1 = "754a5ea0664cfbff50540dc32d67bda3289fc34b"; |
|
|||
897 | }; |
|
|||
898 | }; |
|
|||
899 | "collect-all-0.2.1" = { |
|
|||
900 | name = "collect-all"; |
|
|||
901 | packageName = "collect-all"; |
|
|||
902 | version = "0.2.1"; |
|
|||
903 | src = fetchurl { |
|
|||
904 | url = "https://registry.npmjs.org/collect-all/-/collect-all-0.2.1.tgz"; |
|
|||
905 | sha1 = "7225fb4585c22d4ffac886f0abaf5abc563a1a6a"; |
|
|||
906 | }; |
|
|||
907 | }; |
|
|||
908 | "stream-connect-1.0.2" = { |
|
|||
909 | name = "stream-connect"; |
|
|||
910 | packageName = "stream-connect"; |
|
|||
911 | version = "1.0.2"; |
|
|||
912 | src = fetchurl { |
|
|||
913 | url = "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz"; |
|
|||
914 | sha1 = "18bc81f2edb35b8b5d9a8009200a985314428a97"; |
|
|||
915 | }; |
|
1374 | }; | |
916 | }; |
|
1375 | }; | |
917 |
" |
|
1376 | "typical-2.6.1" = { | |
918 |
name = " |
|
1377 | name = "typical"; | |
919 |
packageName = " |
|
1378 | packageName = "typical"; | |
920 |
version = " |
|
1379 | version = "2.6.1"; | |
921 | src = fetchurl { |
|
|||
922 | url = "https://registry.npmjs.org/stream-via/-/stream-via-0.1.1.tgz"; |
|
|||
923 | sha1 = "0cee5df9c959fb1d3f4eda4819f289d5f9205afc"; |
|
|||
924 | }; |
|
|||
925 | }; |
|
|||
926 | "collect-json-1.0.8" = { |
|
|||
927 | name = "collect-json"; |
|
|||
928 | packageName = "collect-json"; |
|
|||
929 | version = "1.0.8"; |
|
|||
930 | src = fetchurl { |
|
|||
931 | url = "https://registry.npmjs.org/collect-json/-/collect-json-1.0.8.tgz"; |
|
|||
932 | sha1 = "aa2fa52b4d1d9444ce690f07a1e3617ab74bb827"; |
|
|||
933 | }; |
|
|||
934 | }; |
|
|||
935 | "deep-extend-0.4.1" = { |
|
|||
936 | name = "deep-extend"; |
|
|||
937 | packageName = "deep-extend"; |
|
|||
938 | version = "0.4.1"; |
|
|||
939 | src = fetchurl { |
|
|||
940 | url = "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.1.tgz"; |
|
|||
941 | sha1 = "efe4113d08085f4e6f9687759810f807469e2253"; |
|
|||
942 | }; |
|
|||
943 | }; |
|
|||
944 | "object-tools-2.0.6" = { |
|
|||
945 | name = "object-tools"; |
|
|||
946 | packageName = "object-tools"; |
|
|||
947 | version = "2.0.6"; |
|
|||
948 | src = fetchurl { |
|
1380 | src = fetchurl { | |
949 |
url = "https://registry.npmjs.org/ |
|
1381 | url = "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz"; | |
950 | sha1 = "f3fe1c350cda4a6f5d99d9646dc4892a02476ddd"; |
|
1382 | sha1 = "5c080e5d661cbbe38259d2e70a3c7253e873881d"; | |
951 | }; |
|
|||
952 | }; |
|
|||
953 | "collect-all-1.0.2" = { |
|
|||
954 | name = "collect-all"; |
|
|||
955 | packageName = "collect-all"; |
|
|||
956 | version = "1.0.2"; |
|
|||
957 | src = fetchurl { |
|
|||
958 | url = "https://registry.npmjs.org/collect-all/-/collect-all-1.0.2.tgz"; |
|
|||
959 | sha1 = "39450f1e7aa6086570a006bce93ccf1218a77ea1"; |
|
|||
960 | }; |
|
|||
961 | }; |
|
|||
962 | "stream-via-1.0.3" = { |
|
|||
963 | name = "stream-via"; |
|
|||
964 | packageName = "stream-via"; |
|
|||
965 | version = "1.0.3"; |
|
|||
966 | src = fetchurl { |
|
|||
967 | url = "https://registry.npmjs.org/stream-via/-/stream-via-1.0.3.tgz"; |
|
|||
968 | sha1 = "cebd32a5a59d74b3b68e3404942e867184ad4ac9"; |
|
|||
969 | }; |
|
|||
970 | }; |
|
|||
971 | "object-get-2.1.0" = { |
|
|||
972 | name = "object-get"; |
|
|||
973 | packageName = "object-get"; |
|
|||
974 | version = "2.1.0"; |
|
|||
975 | src = fetchurl { |
|
|||
976 | url = "https://registry.npmjs.org/object-get/-/object-get-2.1.0.tgz"; |
|
|||
977 | sha1 = "722bbdb60039efa47cad3c6dc2ce51a85c02c5ae"; |
|
|||
978 | }; |
|
|||
979 | }; |
|
|||
980 | "test-value-1.1.0" = { |
|
|||
981 | name = "test-value"; |
|
|||
982 | packageName = "test-value"; |
|
|||
983 | version = "1.1.0"; |
|
|||
984 | src = fetchurl { |
|
|||
985 | url = "https://registry.npmjs.org/test-value/-/test-value-1.1.0.tgz"; |
|
|||
986 | sha1 = "a09136f72ec043d27c893707c2b159bfad7de93f"; |
|
|||
987 | }; |
|
1383 | }; | |
988 | }; |
|
1384 | }; | |
989 | "test-value-2.1.0" = { |
|
1385 | "test-value-2.1.0" = { | |
@@ -995,6 +1391,60 b' let' | |||||
995 | sha1 = "11da6ff670f3471a73b625ca4f3fdcf7bb748291"; |
|
1391 | sha1 = "11da6ff670f3471a73b625ca4f3fdcf7bb748291"; | |
996 | }; |
|
1392 | }; | |
997 | }; |
|
1393 | }; | |
|
1394 | "ansi-escape-sequences-3.0.0" = { | |||
|
1395 | name = "ansi-escape-sequences"; | |||
|
1396 | packageName = "ansi-escape-sequences"; | |||
|
1397 | version = "3.0.0"; | |||
|
1398 | src = fetchurl { | |||
|
1399 | url = "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-3.0.0.tgz"; | |||
|
1400 | sha1 = "1c18394b6af9b76ff9a63509fa497669fd2ce53e"; | |||
|
1401 | }; | |||
|
1402 | }; | |||
|
1403 | "table-layout-0.3.0" = { | |||
|
1404 | name = "table-layout"; | |||
|
1405 | packageName = "table-layout"; | |||
|
1406 | version = "0.3.0"; | |||
|
1407 | src = fetchurl { | |||
|
1408 | url = "https://registry.npmjs.org/table-layout/-/table-layout-0.3.0.tgz"; | |||
|
1409 | sha1 = "6ee20dc483db371b3e5c87f704ed2f7c799d2c9a"; | |||
|
1410 | }; | |||
|
1411 | }; | |||
|
1412 | "core-js-2.5.1" = { | |||
|
1413 | name = "core-js"; | |||
|
1414 | packageName = "core-js"; | |||
|
1415 | version = "2.5.1"; | |||
|
1416 | src = fetchurl { | |||
|
1417 | url = "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz"; | |||
|
1418 | sha1 = "ae6874dc66937789b80754ff5428df66819ca50b"; | |||
|
1419 | }; | |||
|
1420 | }; | |||
|
1421 | "deep-extend-0.4.2" = { | |||
|
1422 | name = "deep-extend"; | |||
|
1423 | packageName = "deep-extend"; | |||
|
1424 | version = "0.4.2"; | |||
|
1425 | src = fetchurl { | |||
|
1426 | url = "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz"; | |||
|
1427 | sha1 = "48b699c27e334bf89f10892be432f6e4c7d34a7f"; | |||
|
1428 | }; | |||
|
1429 | }; | |||
|
1430 | "wordwrapjs-2.0.0" = { | |||
|
1431 | name = "wordwrapjs"; | |||
|
1432 | packageName = "wordwrapjs"; | |||
|
1433 | version = "2.0.0"; | |||
|
1434 | src = fetchurl { | |||
|
1435 | url = "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-2.0.0.tgz"; | |||
|
1436 | sha1 = "ab55f695e6118da93858fdd70c053d1c5e01ac20"; | |||
|
1437 | }; | |||
|
1438 | }; | |||
|
1439 | "reduce-flatten-1.0.1" = { | |||
|
1440 | name = "reduce-flatten"; | |||
|
1441 | packageName = "reduce-flatten"; | |||
|
1442 | version = "1.0.1"; | |||
|
1443 | src = fetchurl { | |||
|
1444 | url = "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz"; | |||
|
1445 | sha1 = "258c78efd153ddf93cb561237f61184f3696e327"; | |||
|
1446 | }; | |||
|
1447 | }; | |||
998 | "@types/clone-0.1.30" = { |
|
1448 | "@types/clone-0.1.30" = { | |
999 | name = "@types/clone"; |
|
1449 | name = "@types/clone"; | |
1000 | packageName = "@types/clone"; |
|
1450 | packageName = "@types/clone"; | |
@@ -1004,13 +1454,13 b' let' | |||||
1004 | sha1 = "e7365648c1b42136a59c7d5040637b3b5c83b614"; |
|
1454 | sha1 = "e7365648c1b42136a59c7d5040637b3b5c83b614"; | |
1005 | }; |
|
1455 | }; | |
1006 | }; |
|
1456 | }; | |
1007 |
"@types/node-4. |
|
1457 | "@types/node-4.2.20" = { | |
1008 | name = "@types/node"; |
|
1458 | name = "@types/node"; | |
1009 | packageName = "@types/node"; |
|
1459 | packageName = "@types/node"; | |
1010 |
version = "4. |
|
1460 | version = "4.2.20"; | |
1011 | src = fetchurl { |
|
1461 | src = fetchurl { | |
1012 |
url = "https://registry.npmjs.org/@types/node/-/node-4. |
|
1462 | url = "https://registry.npmjs.org/@types/node/-/node-4.2.20.tgz"; | |
1013 | sha1 = "553f490ed3030311620f88003e7abfc0edcb301e"; |
|
1463 | sha1 = "3f7dceff43e07cfff4407fc3495d98a533b32267"; | |
1014 | }; |
|
1464 | }; | |
1015 | }; |
|
1465 | }; | |
1016 | "@types/parse5-0.0.31" = { |
|
1466 | "@types/parse5-0.0.31" = { | |
@@ -1040,13 +1490,13 b' let' | |||||
1040 | sha1 = "9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"; |
|
1490 | sha1 = "9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"; | |
1041 | }; |
|
1491 | }; | |
1042 | }; |
|
1492 | }; | |
1043 |
"@types/node-6.0. |
|
1493 | "@types/node-6.0.88" = { | |
1044 | name = "@types/node"; |
|
1494 | name = "@types/node"; | |
1045 | packageName = "@types/node"; |
|
1495 | packageName = "@types/node"; | |
1046 |
version = "6.0. |
|
1496 | version = "6.0.88"; | |
1047 | src = fetchurl { |
|
1497 | src = fetchurl { | |
1048 |
url = "https://registry.npmjs.org/@types/node/-/node-6.0. |
|
1498 | url = "https://registry.npmjs.org/@types/node/-/node-6.0.88.tgz"; | |
1049 | sha1 = "578cf53aaec65887bcaf16792f8722932e8ff8ea"; |
|
1499 | sha1 = "f618f11a944f6a18d92b5c472028728a3e3d4b66"; | |
1050 | }; |
|
1500 | }; | |
1051 | }; |
|
1501 | }; | |
1052 | "es6-promise-2.3.0" = { |
|
1502 | "es6-promise-2.3.0" = { | |
@@ -1058,13 +1508,13 b' let' | |||||
1058 | sha1 = "96edb9f2fdb01995822b263dd8aadab6748181bc"; |
|
1508 | sha1 = "96edb9f2fdb01995822b263dd8aadab6748181bc"; | |
1059 | }; |
|
1509 | }; | |
1060 | }; |
|
1510 | }; | |
1061 |
"hydrolysis-1.2 |
|
1511 | "hydrolysis-1.25.0" = { | |
1062 | name = "hydrolysis"; |
|
1512 | name = "hydrolysis"; | |
1063 | packageName = "hydrolysis"; |
|
1513 | packageName = "hydrolysis"; | |
1064 |
version = "1.2 |
|
1514 | version = "1.25.0"; | |
1065 | src = fetchurl { |
|
1515 | src = fetchurl { | |
1066 |
url = "https://registry.npmjs.org/hydrolysis/-/hydrolysis-1.2 |
|
1516 | url = "https://registry.npmjs.org/hydrolysis/-/hydrolysis-1.25.0.tgz"; | |
1067 | sha1 = "0f94f055d1065ac0d81ff40b762d143fef07eff4"; |
|
1517 | sha1 = "a4fb14a37a1e03b0db52d8aaa57c682272a14d84"; | |
1068 | }; |
|
1518 | }; | |
1069 | }; |
|
1519 | }; | |
1070 | "nopt-3.0.6" = { |
|
1520 | "nopt-3.0.6" = { | |
@@ -1085,22 +1535,22 b' let' | |||||
1085 | sha1 = "06b26113f56beab042545a23bfa88003ccac260f"; |
|
1535 | sha1 = "06b26113f56beab042545a23bfa88003ccac260f"; | |
1086 | }; |
|
1536 | }; | |
1087 | }; |
|
1537 | }; | |
1088 | "update-notifier-0.6.3" = { |
|
1538 | "acorn-3.3.0" = { | |
1089 |
name = " |
|
1539 | name = "acorn"; | |
1090 |
packageName = " |
|
1540 | packageName = "acorn"; | |
1091 |
version = " |
|
1541 | version = "3.3.0"; | |
1092 | src = fetchurl { |
|
1542 | src = fetchurl { | |
1093 |
url = "https://registry.npmjs.org/ |
|
1543 | url = "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz"; | |
1094 | sha1 = "776dec8daa13e962a341e8a1d98354306b67ae08"; |
|
1544 | sha1 = "45e37fb39e8da3f25baee3ff5369e2bb5f22017a"; | |
1095 | }; |
|
1545 | }; | |
1096 | }; |
|
1546 | }; | |
1097 |
"babel-polyfill-6. |
|
1547 | "babel-polyfill-6.26.0" = { | |
1098 | name = "babel-polyfill"; |
|
1548 | name = "babel-polyfill"; | |
1099 | packageName = "babel-polyfill"; |
|
1549 | packageName = "babel-polyfill"; | |
1100 |
version = "6. |
|
1550 | version = "6.26.0"; | |
1101 | src = fetchurl { |
|
1551 | src = fetchurl { | |
1102 |
url = "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6. |
|
1552 | url = "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz"; | |
1103 | sha1 = "5978215c25d49a697eb78afc54e63c9d3a73d5ec"; |
|
1553 | sha1 = "379937abc67d7895970adc621f284cd966cf2153"; | |
1104 | }; |
|
1554 | }; | |
1105 | }; |
|
1555 | }; | |
1106 | "doctrine-0.7.2" = { |
|
1556 | "doctrine-0.7.2" = { | |
@@ -1112,22 +1562,31 b' let' | |||||
1112 | sha1 = "7cb860359ba3be90e040b26b729ce4bfa654c523"; |
|
1562 | sha1 = "7cb860359ba3be90e040b26b729ce4bfa654c523"; | |
1113 | }; |
|
1563 | }; | |
1114 | }; |
|
1564 | }; | |
1115 |
" |
|
1565 | "dom5-1.1.0" = { | |
|
1566 | name = "dom5"; | |||
|
1567 | packageName = "dom5"; | |||
|
1568 | version = "1.1.0"; | |||
|
1569 | src = fetchurl { | |||
|
1570 | url = "https://registry.npmjs.org/dom5/-/dom5-1.1.0.tgz"; | |||
|
1571 | sha1 = "3a0c7700c083ab4c4d26938a78b0f0c6dcc37794"; | |||
|
1572 | }; | |||
|
1573 | }; | |||
|
1574 | "escodegen-1.9.0" = { | |||
1116 | name = "escodegen"; |
|
1575 | name = "escodegen"; | |
1117 | packageName = "escodegen"; |
|
1576 | packageName = "escodegen"; | |
1118 |
version = "1. |
|
1577 | version = "1.9.0"; | |
1119 | src = fetchurl { |
|
1578 | src = fetchurl { | |
1120 |
url = "https://registry.npmjs.org/escodegen/-/escodegen-1. |
|
1579 | url = "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz"; | |
1121 | sha1 = "5a5b53af4693110bebb0867aa3430dd3b70a1018"; |
|
1580 | sha1 = "9811a2f265dc1cd3894420ee3717064b632b8852"; | |
1122 | }; |
|
1581 | }; | |
1123 | }; |
|
1582 | }; | |
1124 |
"espree-3. |
|
1583 | "espree-3.5.1" = { | |
1125 | name = "espree"; |
|
1584 | name = "espree"; | |
1126 | packageName = "espree"; |
|
1585 | packageName = "espree"; | |
1127 |
version = "3. |
|
1586 | version = "3.5.1"; | |
1128 | src = fetchurl { |
|
1587 | src = fetchurl { | |
1129 |
url = "https://registry.npmjs.org/espree/-/espree-3. |
|
1588 | url = "https://registry.npmjs.org/espree/-/espree-3.5.1.tgz"; | |
1130 | sha1 = "42107376856738a65ff3b5877f3a58bd52497643"; |
|
1589 | sha1 = "0c988b8ab46db53100a1954ae4ba995ddd27d87e"; | |
1131 | }; |
|
1590 | }; | |
1132 | }; |
|
1591 | }; | |
1133 | "estraverse-3.1.0" = { |
|
1592 | "estraverse-3.1.0" = { | |
@@ -1139,31 +1598,40 b' let' | |||||
1139 | sha1 = "15e28a446b8b82bc700ccc8b96c78af4da0d6cba"; |
|
1598 | sha1 = "15e28a446b8b82bc700ccc8b96c78af4da0d6cba"; | |
1140 | }; |
|
1599 | }; | |
1141 | }; |
|
1600 | }; | |
1142 |
"path-is-absolute-1.0. |
|
1601 | "path-is-absolute-1.0.1" = { | |
1143 | name = "path-is-absolute"; |
|
1602 | name = "path-is-absolute"; | |
1144 | packageName = "path-is-absolute"; |
|
1603 | packageName = "path-is-absolute"; | |
1145 |
version = "1.0. |
|
1604 | version = "1.0.1"; | |
1146 | src = fetchurl { |
|
1605 | src = fetchurl { | |
1147 |
url = "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0. |
|
1606 | url = "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"; | |
1148 | sha1 = "263dada66ab3f2fb10bf7f9d24dd8f3e570ef912"; |
|
1607 | sha1 = "174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"; | |
1149 | }; |
|
1608 | }; | |
1150 | }; |
|
1609 | }; | |
1151 |
"babel-runtime-6. |
|
1610 | "babel-runtime-6.26.0" = { | |
1152 | name = "babel-runtime"; |
|
1611 | name = "babel-runtime"; | |
1153 | packageName = "babel-runtime"; |
|
1612 | packageName = "babel-runtime"; | |
1154 |
version = "6. |
|
1613 | version = "6.26.0"; | |
1155 | src = fetchurl { |
|
1614 | src = fetchurl { | |
1156 |
url = "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6. |
|
1615 | url = "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz"; | |
1157 | sha1 = "6db707fef2d49c49bfa3cb64efdb436b518b8222"; |
|
1616 | sha1 = "965c7058668e82b55d7bfe04ff2337bc8b5647fe"; | |
1158 | }; |
|
1617 | }; | |
1159 | }; |
|
1618 | }; | |
1160 |
"regenerator-runtime-0. |
|
1619 | "regenerator-runtime-0.10.5" = { | |
1161 | name = "regenerator-runtime"; |
|
1620 | name = "regenerator-runtime"; | |
1162 | packageName = "regenerator-runtime"; |
|
1621 | packageName = "regenerator-runtime"; | |
1163 |
version = "0. |
|
1622 | version = "0.10.5"; | |
1164 | src = fetchurl { |
|
1623 | src = fetchurl { | |
1165 |
url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0. |
|
1624 | url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz"; | |
1166 | sha1 = "403d6d40a4bdff9c330dd9392dcbb2d9a8bba1fc"; |
|
1625 | sha1 = "336c3efc1220adcedda2c9fab67b5a7955a33658"; | |
|
1626 | }; | |||
|
1627 | }; | |||
|
1628 | "regenerator-runtime-0.11.0" = { | |||
|
1629 | name = "regenerator-runtime"; | |||
|
1630 | packageName = "regenerator-runtime"; | |||
|
1631 | version = "0.11.0"; | |||
|
1632 | src = fetchurl { | |||
|
1633 | url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz"; | |||
|
1634 | sha1 = "7e54fe5b5ccd5d6624ea6255c3473be090b802e1"; | |||
1167 | }; |
|
1635 | }; | |
1168 | }; |
|
1636 | }; | |
1169 | "esutils-1.1.6" = { |
|
1637 | "esutils-1.1.6" = { | |
@@ -1184,13 +1652,13 b' let' | |||||
1184 | sha1 = "8a18acfca9a8f4177e09abfc6038939b05d1eedf"; |
|
1652 | sha1 = "8a18acfca9a8f4177e09abfc6038939b05d1eedf"; | |
1185 | }; |
|
1653 | }; | |
1186 | }; |
|
1654 | }; | |
1187 |
"estraverse- |
|
1655 | "estraverse-4.2.0" = { | |
1188 | name = "estraverse"; |
|
1656 | name = "estraverse"; | |
1189 | packageName = "estraverse"; |
|
1657 | packageName = "estraverse"; | |
1190 |
version = " |
|
1658 | version = "4.2.0"; | |
1191 | src = fetchurl { |
|
1659 | src = fetchurl { | |
1192 |
url = "https://registry.npmjs.org/estraverse/-/estraverse- |
|
1660 | url = "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz"; | |
1193 | sha1 = "af67f2dc922582415950926091a4005d29c9bb44"; |
|
1661 | sha1 = "0dee3fed31fcd469618ce7342099fc1afa0bdb13"; | |
1194 | }; |
|
1662 | }; | |
1195 | }; |
|
1663 | }; | |
1196 | "esutils-2.0.2" = { |
|
1664 | "esutils-2.0.2" = { | |
@@ -1202,13 +1670,13 b' let' | |||||
1202 | sha1 = "0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"; |
|
1670 | sha1 = "0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"; | |
1203 | }; |
|
1671 | }; | |
1204 | }; |
|
1672 | }; | |
1205 |
"esprima- |
|
1673 | "esprima-3.1.3" = { | |
1206 | name = "esprima"; |
|
1674 | name = "esprima"; | |
1207 | packageName = "esprima"; |
|
1675 | packageName = "esprima"; | |
1208 |
version = " |
|
1676 | version = "3.1.3"; | |
1209 | src = fetchurl { |
|
1677 | src = fetchurl { | |
1210 |
url = "https://registry.npmjs.org/esprima/-/esprima- |
|
1678 | url = "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz"; | |
1211 | sha1 = "96e3b70d5779f6ad49cd032673d1c312767ba581"; |
|
1679 | sha1 = "fdca51cee6133895e3c88d535ce49dbff62a4633"; | |
1212 | }; |
|
1680 | }; | |
1213 | }; |
|
1681 | }; | |
1214 | "optionator-0.8.2" = { |
|
1682 | "optionator-0.8.2" = { | |
@@ -1220,15 +1688,6 b' let' | |||||
1220 | sha1 = "364c5e409d3f4d6301d6c0b4c05bba50180aeb64"; |
|
1688 | sha1 = "364c5e409d3f4d6301d6c0b4c05bba50180aeb64"; | |
1221 | }; |
|
1689 | }; | |
1222 | }; |
|
1690 | }; | |
1223 | "source-map-0.2.0" = { |
|
|||
1224 | name = "source-map"; |
|
|||
1225 | packageName = "source-map"; |
|
|||
1226 | version = "0.2.0"; |
|
|||
1227 | src = fetchurl { |
|
|||
1228 | url = "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz"; |
|
|||
1229 | sha1 = "dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"; |
|
|||
1230 | }; |
|
|||
1231 | }; |
|
|||
1232 | "prelude-ls-1.1.2" = { |
|
1691 | "prelude-ls-1.1.2" = { | |
1233 | name = "prelude-ls"; |
|
1692 | name = "prelude-ls"; | |
1234 | packageName = "prelude-ls"; |
|
1693 | packageName = "prelude-ls"; | |
@@ -1274,22 +1733,22 b' let' | |||||
1274 | sha1 = "3b09924edf9f083c0490fdd4c0bc4421e04764ee"; |
|
1733 | sha1 = "3b09924edf9f083c0490fdd4c0bc4421e04764ee"; | |
1275 | }; |
|
1734 | }; | |
1276 | }; |
|
1735 | }; | |
1277 |
"fast-levenshtein-2.0. |
|
1736 | "fast-levenshtein-2.0.6" = { | |
1278 | name = "fast-levenshtein"; |
|
1737 | name = "fast-levenshtein"; | |
1279 | packageName = "fast-levenshtein"; |
|
1738 | packageName = "fast-levenshtein"; | |
1280 |
version = "2.0. |
|
1739 | version = "2.0.6"; | |
1281 | src = fetchurl { |
|
1740 | src = fetchurl { | |
1282 |
url = "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0. |
|
1741 | url = "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"; | |
1283 | sha1 = "e31e729eea62233c60a7bc9dce2bdcc88b4fffe3"; |
|
1742 | sha1 = "3d8a5c66883a16a30ca8643e851f19baa7797917"; | |
1284 | }; |
|
1743 | }; | |
1285 | }; |
|
1744 | }; | |
1286 |
"acorn- |
|
1745 | "acorn-5.1.2" = { | |
1287 | name = "acorn"; |
|
1746 | name = "acorn"; | |
1288 | packageName = "acorn"; |
|
1747 | packageName = "acorn"; | |
1289 |
version = " |
|
1748 | version = "5.1.2"; | |
1290 | src = fetchurl { |
|
1749 | src = fetchurl { | |
1291 |
url = "https://registry.npmjs.org/acorn/-/acorn- |
|
1750 | url = "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz"; | |
1292 | sha1 = "1a3e850b428e73ba6b09d1cc527f5aaad4d03ef1"; |
|
1751 | sha1 = "911cb53e036807cf0fa778dc5d370fbd864246d7"; | |
1293 | }; |
|
1752 | }; | |
1294 | }; |
|
1753 | }; | |
1295 | "acorn-jsx-3.0.1" = { |
|
1754 | "acorn-jsx-3.0.1" = { | |
@@ -1301,220 +1760,166 b' let' | |||||
1301 | sha1 = "afdf9488fb1ecefc8348f6fb22f464e32a58b36b"; |
|
1760 | sha1 = "afdf9488fb1ecefc8348f6fb22f464e32a58b36b"; | |
1302 | }; |
|
1761 | }; | |
1303 | }; |
|
1762 | }; | |
1304 |
"a |
|
1763 | "object-assign-4.1.1" = { | |
1305 |
name = "a |
|
1764 | name = "object-assign"; | |
1306 |
packageName = "a |
|
1765 | packageName = "object-assign"; | |
1307 |
version = " |
|
1766 | version = "4.1.1"; | |
1308 | src = fetchurl { |
|
1767 | src = fetchurl { | |
1309 |
url = "https://registry.npmjs.org/a |
|
1768 | url = "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"; | |
1310 | sha1 = "45e37fb39e8da3f25baee3ff5369e2bb5f22017a"; |
|
1769 | sha1 = "2109adc7965887cfc05cbbd442cac8bfbb360863"; | |
1311 | }; |
|
|||
1312 | }; |
|
|||
1313 | "boxen-0.3.1" = { |
|
|||
1314 | name = "boxen"; |
|
|||
1315 | packageName = "boxen"; |
|
|||
1316 | version = "0.3.1"; |
|
|||
1317 | src = fetchurl { |
|
|||
1318 | url = "https://registry.npmjs.org/boxen/-/boxen-0.3.1.tgz"; |
|
|||
1319 | sha1 = "a7d898243ae622f7abb6bb604d740a76c6a5461b"; |
|
|||
1320 | }; |
|
1770 | }; | |
1321 | }; |
|
1771 | }; | |
1322 |
"c |
|
1772 | "crisper-1.2.0" = { | |
1323 |
name = "c |
|
1773 | name = "crisper"; | |
1324 |
packageName = "c |
|
1774 | packageName = "crisper"; | |
1325 |
version = "2 |
|
1775 | version = "1.2.0"; | |
1326 | src = fetchurl { |
|
1776 | src = fetchurl { | |
1327 |
url = "https://registry.npmjs.org/c |
|
1777 | url = "https://registry.npmjs.org/crisper/-/crisper-1.2.0.tgz"; | |
1328 | sha1 = "737a3a7036e9886102aa6099e47bb33ab1aba1a1"; |
|
1778 | sha1 = "9a91f597d71f6110294e076ad44dbb3408568e46"; | |
1329 | }; |
|
1779 | }; | |
1330 | }; |
|
1780 | }; | |
1331 |
" |
|
1781 | "optparse-1.0.5" = { | |
1332 |
name = " |
|
1782 | name = "optparse"; | |
1333 |
packageName = " |
|
1783 | packageName = "optparse"; | |
1334 |
version = "1.0. |
|
1784 | version = "1.0.5"; | |
1335 | src = fetchurl { |
|
1785 | src = fetchurl { | |
1336 |
url = "https://registry.npmjs.org/ |
|
1786 | url = "https://registry.npmjs.org/optparse/-/optparse-1.0.5.tgz"; | |
1337 | sha1 = "f2fb63a65e4905b406c86072765a1a4dc793b9f4"; |
|
1787 | sha1 = "75e75a96506611eb1c65ba89018ff08a981e2c16"; | |
1338 | }; |
|
|||
1339 | }; |
|
|||
1340 | "latest-version-2.0.0" = { |
|
|||
1341 | name = "latest-version"; |
|
|||
1342 | packageName = "latest-version"; |
|
|||
1343 | version = "2.0.0"; |
|
|||
1344 | src = fetchurl { |
|
|||
1345 | url = "https://registry.npmjs.org/latest-version/-/latest-version-2.0.0.tgz"; |
|
|||
1346 | sha1 = "56f8d6139620847b8017f8f1f4d78e211324168b"; |
|
|||
1347 | }; |
|
1788 | }; | |
1348 | }; |
|
1789 | }; | |
1349 |
"semver- |
|
1790 | "semver-5.4.1" = { | |
1350 |
name = "semver |
|
1791 | name = "semver"; | |
1351 |
packageName = "semver |
|
1792 | packageName = "semver"; | |
1352 |
version = " |
|
1793 | version = "5.4.1"; | |
1353 | src = fetchurl { |
|
1794 | src = fetchurl { | |
1354 |
url = "https://registry.npmjs.org/semver |
|
1795 | url = "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz"; | |
1355 | sha1 = "4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"; |
|
1796 | sha1 = "e059c09d8571f0540823733433505d3a2f00b18e"; | |
1356 | }; |
|
1797 | }; | |
1357 | }; |
|
1798 | }; | |
1358 | "filled-array-1.1.0" = { |
|
1799 | "npm-registry-client-8.4.0" = { | |
1359 |
name = " |
|
1800 | name = "npm-registry-client"; | |
1360 |
packageName = " |
|
1801 | packageName = "npm-registry-client"; | |
1361 |
version = " |
|
1802 | version = "8.4.0"; | |
1362 | src = fetchurl { |
|
1803 | src = fetchurl { | |
1363 |
url = "https://registry.npmjs.org/ |
|
1804 | url = "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-8.4.0.tgz"; | |
1364 | sha1 = "c3c4f6c663b923459a9aa29912d2d031f1507f84"; |
|
1805 | sha1 = "d52b901685647fc62a4c03eafecb6ceaa5018d4c"; | |
1365 | }; |
|
1806 | }; | |
1366 | }; |
|
1807 | }; | |
1367 | "object-assign-4.1.0" = { |
|
1808 | "npmconf-2.1.2" = { | |
1368 |
name = "o |
|
1809 | name = "npmconf"; | |
1369 |
packageName = "o |
|
1810 | packageName = "npmconf"; | |
1370 |
version = " |
|
1811 | version = "2.1.2"; | |
1371 | src = fetchurl { |
|
1812 | src = fetchurl { | |
1372 |
url = "https://registry.npmjs.org/o |
|
1813 | url = "https://registry.npmjs.org/npmconf/-/npmconf-2.1.2.tgz"; | |
1373 | sha1 = "7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"; |
|
1814 | sha1 = "66606a4a736f1e77a059aa071a79c94ab781853a"; | |
1374 | }; |
|
1815 | }; | |
1375 | }; |
|
1816 | }; | |
1376 |
"r |
|
1817 | "tar-3.1.15" = { | |
1377 |
name = "r |
|
1818 | name = "tar"; | |
1378 |
packageName = "r |
|
1819 | packageName = "tar"; | |
1379 |
version = " |
|
1820 | version = "3.1.15"; | |
1380 | src = fetchurl { |
|
1821 | src = fetchurl { | |
1381 |
url = "https://registry.npmjs.org/r |
|
1822 | url = "https://registry.npmjs.org/tar/-/tar-3.1.15.tgz"; | |
1382 | sha1 = "5214c53a926d3552707527fbab415dbc08d06dda"; |
|
1823 | sha1 = "cccdc35b90917d58e4c3837795d5d022d7a1f46f"; | |
1383 | }; |
|
1824 | }; | |
1384 | }; |
|
1825 | }; | |
1385 | "string-width-1.0.2" = { |
|
1826 | "temp-0.8.3" = { | |
1386 |
name = " |
|
1827 | name = "temp"; | |
1387 |
packageName = " |
|
1828 | packageName = "temp"; | |
1388 |
version = " |
|
1829 | version = "0.8.3"; | |
1389 | src = fetchurl { |
|
1830 | src = fetchurl { | |
1390 |
url = "https://registry.npmjs.org/ |
|
1831 | url = "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz"; | |
1391 | sha1 = "118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"; |
|
1832 | sha1 = "e0c6bc4d26b903124410e4fed81103014dfc1f59"; | |
1392 | }; |
|
|||
1393 | }; |
|
|||
1394 | "widest-line-1.0.0" = { |
|
|||
1395 | name = "widest-line"; |
|
|||
1396 | packageName = "widest-line"; |
|
|||
1397 | version = "1.0.0"; |
|
|||
1398 | src = fetchurl { |
|
|||
1399 | url = "https://registry.npmjs.org/widest-line/-/widest-line-1.0.0.tgz"; |
|
|||
1400 | sha1 = "0c09c85c2a94683d0d7eaf8ee097d564bf0e105c"; |
|
|||
1401 | }; |
|
1833 | }; | |
1402 | }; |
|
1834 | }; | |
1403 |
" |
|
1835 | "fs.extra-1.3.2" = { | |
1404 |
name = " |
|
1836 | name = "fs.extra"; | |
1405 |
packageName = " |
|
1837 | packageName = "fs.extra"; | |
1406 |
version = "1. |
|
1838 | version = "1.3.2"; | |
1407 | src = fetchurl { |
|
1839 | src = fetchurl { | |
1408 |
url = "https://registry.npmjs.org/ |
|
1840 | url = "https://registry.npmjs.org/fs.extra/-/fs.extra-1.3.2.tgz"; | |
1409 | sha1 = "6438603eaebe2793948ff4a4262ec8db3d62597b"; |
|
1841 | sha1 = "dd023f93013bee24531f1b33514c37b20fd93349"; | |
1410 | }; |
|
|||
1411 | }; |
|
|||
1412 | "number-is-nan-1.0.0" = { |
|
|||
1413 | name = "number-is-nan"; |
|
|||
1414 | packageName = "number-is-nan"; |
|
|||
1415 | version = "1.0.0"; |
|
|||
1416 | src = fetchurl { |
|
|||
1417 | url = "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz"; |
|
|||
1418 | sha1 = "c020f529c5282adfdd233d91d4b181c3d686dc4b"; |
|
|||
1419 | }; |
|
1842 | }; | |
1420 | }; |
|
1843 | }; | |
1421 |
" |
|
1844 | "findit-2.0.0" = { | |
1422 |
name = " |
|
1845 | name = "findit"; | |
1423 |
packageName = " |
|
1846 | packageName = "findit"; | |
1424 |
version = " |
|
1847 | version = "2.0.0"; | |
1425 | src = fetchurl { |
|
1848 | src = fetchurl { | |
1426 |
url = "https://registry.npmjs.org/ |
|
1849 | url = "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz"; | |
1427 | sha1 = "f69b192d3f7d91e382e4b71bddb77878619ab0c6"; |
|
1850 | sha1 = "6509f0126af4c178551cfa99394e032e13a4d56e"; | |
1428 | }; |
|
1851 | }; | |
1429 | }; |
|
1852 | }; | |
1430 | "is-fullwidth-code-point-1.0.0" = { |
|
1853 | "base64-js-1.2.1" = { | |
1431 | name = "is-fullwidth-code-point"; |
|
1854 | name = "base64-js"; | |
1432 |
packageName = " |
|
1855 | packageName = "base64-js"; | |
1433 |
version = "1. |
|
1856 | version = "1.2.1"; | |
1434 | src = fetchurl { |
|
1857 | src = fetchurl { | |
1435 |
url = "https://registry.npmjs.org/ |
|
1858 | url = "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz"; | |
1436 | sha1 = "ef9e31386f031a7f0d643af82fde50c457ef00cb"; |
|
1859 | sha1 = "a91947da1f4a516ea38e5b4ec0ec3773675e0886"; | |
1437 | }; |
|
1860 | }; | |
1438 | }; |
|
1861 | }; | |
1439 |
" |
|
1862 | "slasp-0.0.4" = { | |
1440 |
name = " |
|
1863 | name = "slasp"; | |
1441 |
packageName = " |
|
1864 | packageName = "slasp"; | |
1442 |
version = " |
|
1865 | version = "0.0.4"; | |
1443 | src = fetchurl { |
|
1866 | src = fetchurl { | |
1444 |
url = "https://registry.npmjs.org/ |
|
1867 | url = "https://registry.npmjs.org/slasp/-/slasp-0.0.4.tgz"; | |
1445 | sha1 = "1b708af094a49c9a0e7dbcad790aba539dac1177"; |
|
1868 | sha1 = "9adc26ee729a0f95095851a5489f87a5258d57a9"; | |
1446 | }; |
|
|||
1447 | }; |
|
|||
1448 | "os-tmpdir-1.0.1" = { |
|
|||
1449 | name = "os-tmpdir"; |
|
|||
1450 | packageName = "os-tmpdir"; |
|
|||
1451 | version = "1.0.1"; |
|
|||
1452 | src = fetchurl { |
|
|||
1453 | url = "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz"; |
|
|||
1454 | sha1 = "e9b423a1edaf479882562e92ed71d7743a071b6e"; |
|
|||
1455 | }; |
|
1869 | }; | |
1456 | }; |
|
1870 | }; | |
1457 |
" |
|
1871 | "nijs-0.0.23" = { | |
1458 |
name = " |
|
1872 | name = "nijs"; | |
1459 |
packageName = " |
|
1873 | packageName = "nijs"; | |
1460 |
version = "0. |
|
1874 | version = "0.0.23"; | |
1461 | src = fetchurl { |
|
1875 | src = fetchurl { | |
1462 |
url = "https://registry.npmjs.org/ |
|
1876 | url = "https://registry.npmjs.org/nijs/-/nijs-0.0.23.tgz"; | |
1463 | sha1 = "83cf05c6d6458fc4d5ac6362ea325d92f2754217"; |
|
1877 | sha1 = "dbf8f4a0acafbe3b8d9b71c24cbd1d851de6c31a"; | |
1464 | }; |
|
1878 | }; | |
1465 | }; |
|
1879 | }; | |
1466 | "uuid-2.0.3" = { |
|
1880 | "concat-stream-1.6.0" = { | |
1467 |
name = " |
|
1881 | name = "concat-stream"; | |
1468 |
packageName = " |
|
1882 | packageName = "concat-stream"; | |
1469 |
version = " |
|
1883 | version = "1.6.0"; | |
1470 | src = fetchurl { |
|
1884 | src = fetchurl { | |
1471 |
url = "https://registry.npmjs.org/ |
|
1885 | url = "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz"; | |
1472 | sha1 = "67e2e863797215530dff318e5bf9dcebfd47b21a"; |
|
1886 | sha1 = "0aac662fd52be78964d5532f694784e70110acf7"; | |
1473 | }; |
|
|||
1474 | }; |
|
|||
1475 | "write-file-atomic-1.2.0" = { |
|
|||
1476 | name = "write-file-atomic"; |
|
|||
1477 | packageName = "write-file-atomic"; |
|
|||
1478 | version = "1.2.0"; |
|
|||
1479 | src = fetchurl { |
|
|||
1480 | url = "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.2.0.tgz"; |
|
|||
1481 | sha1 = "14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab"; |
|
|||
1482 | }; |
|
1887 | }; | |
1483 | }; |
|
1888 | }; | |
1484 | "xdg-basedir-2.0.0" = { |
|
1889 | "normalize-package-data-2.4.0" = { | |
1485 | name = "xdg-basedir"; |
|
1890 | name = "normalize-package-data"; | |
1486 |
packageName = " |
|
1891 | packageName = "normalize-package-data"; | |
1487 |
version = "2. |
|
1892 | version = "2.4.0"; | |
1488 | src = fetchurl { |
|
1893 | src = fetchurl { | |
1489 |
url = "https://registry.npmjs.org/ |
|
1894 | url = "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz"; | |
1490 | sha1 = "edbc903cc385fc04523d966a335504b5504d1bd2"; |
|
1895 | sha1 = "12f95a307d58352075a04907b84ac8be98ac012f"; | |
1491 | }; |
|
1896 | }; | |
1492 | }; |
|
1897 | }; | |
1493 | "is-obj-1.0.1" = { |
|
1898 | "npm-package-arg-5.1.2" = { | |
1494 |
name = " |
|
1899 | name = "npm-package-arg"; | |
1495 |
packageName = " |
|
1900 | packageName = "npm-package-arg"; | |
1496 |
version = "1. |
|
1901 | version = "5.1.2"; | |
1497 | src = fetchurl { |
|
1902 | src = fetchurl { | |
1498 |
url = "https://registry.npmjs.org/ |
|
1903 | url = "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-5.1.2.tgz"; | |
1499 | sha1 = "3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"; |
|
1904 | sha1 = "fb18d17bb61e60900d6312619919bd753755ab37"; | |
1500 | }; |
|
1905 | }; | |
1501 | }; |
|
1906 | }; | |
1502 |
"o |
|
1907 | "once-1.4.0" = { | |
1503 |
name = "o |
|
1908 | name = "once"; | |
1504 |
packageName = "o |
|
1909 | packageName = "once"; | |
1505 |
version = "1.0 |
|
1910 | version = "1.4.0"; | |
1506 | src = fetchurl { |
|
1911 | src = fetchurl { | |
1507 |
url = "https://registry.npmjs.org/o |
|
1912 | url = "https://registry.npmjs.org/once/-/once-1.4.0.tgz"; | |
1508 | sha1 = "0d62bdf44b916fd3bbdcf2cab191948fb094f007"; |
|
1913 | sha1 = "583b1aa775961d4b113ac17d9c50baef9dd76bd1"; | |
1509 | }; |
|
1914 | }; | |
1510 | }; |
|
1915 | }; | |
1511 |
" |
|
1916 | "retry-0.10.1" = { | |
1512 |
name = " |
|
1917 | name = "retry"; | |
1513 |
packageName = " |
|
1918 | packageName = "retry"; | |
1514 |
version = "0.1. |
|
1919 | version = "0.10.1"; | |
1515 | src = fetchurl { |
|
1920 | src = fetchurl { | |
1516 |
url = "https://registry.npmjs.org/ |
|
1921 | url = "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz"; | |
1517 | sha1 = "9218b9b2b928a238b13dc4fb6b6d576f231453ea"; |
|
1922 | sha1 = "e76388d217992c252750241d3d3956fed98d8ff4"; | |
1518 | }; |
|
1923 | }; | |
1519 | }; |
|
1924 | }; | |
1520 | "slide-1.1.6" = { |
|
1925 | "slide-1.1.6" = { | |
@@ -1526,238 +1931,40 b' let' | |||||
1526 | sha1 = "56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"; |
|
1931 | sha1 = "56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"; | |
1527 | }; |
|
1932 | }; | |
1528 | }; |
|
1933 | }; | |
1529 | "package-json-2.4.0" = { |
|
1934 | "ssri-4.1.6" = { | |
1530 |
name = " |
|
1935 | name = "ssri"; | |
1531 |
packageName = " |
|
1936 | packageName = "ssri"; | |
1532 |
version = " |
|
1937 | version = "4.1.6"; | |
1533 | src = fetchurl { |
|
|||
1534 | url = "https://registry.npmjs.org/package-json/-/package-json-2.4.0.tgz"; |
|
|||
1535 | sha1 = "0d15bd67d1cbbddbb2ca222ff2edb86bcb31a8bb"; |
|
|||
1536 | }; |
|
|||
1537 | }; |
|
|||
1538 | "got-5.6.0" = { |
|
|||
1539 | name = "got"; |
|
|||
1540 | packageName = "got"; |
|
|||
1541 | version = "5.6.0"; |
|
|||
1542 | src = fetchurl { |
|
|||
1543 | url = "https://registry.npmjs.org/got/-/got-5.6.0.tgz"; |
|
|||
1544 | sha1 = "bb1d7ee163b78082bbc8eb836f3f395004ea6fbf"; |
|
|||
1545 | }; |
|
|||
1546 | }; |
|
|||
1547 | "registry-auth-token-3.0.1" = { |
|
|||
1548 | name = "registry-auth-token"; |
|
|||
1549 | packageName = "registry-auth-token"; |
|
|||
1550 | version = "3.0.1"; |
|
|||
1551 | src = fetchurl { |
|
|||
1552 | url = "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.0.1.tgz"; |
|
|||
1553 | sha1 = "c3ee5ec585bce29f88bf41629a3944c71ed53e25"; |
|
|||
1554 | }; |
|
|||
1555 | }; |
|
|||
1556 | "registry-url-3.1.0" = { |
|
|||
1557 | name = "registry-url"; |
|
|||
1558 | packageName = "registry-url"; |
|
|||
1559 | version = "3.1.0"; |
|
|||
1560 | src = fetchurl { |
|
|||
1561 | url = "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz"; |
|
|||
1562 | sha1 = "3d4ef870f73dde1d77f0cf9a381432444e174942"; |
|
|||
1563 | }; |
|
|||
1564 | }; |
|
|||
1565 | "semver-5.3.0" = { |
|
|||
1566 | name = "semver"; |
|
|||
1567 | packageName = "semver"; |
|
|||
1568 | version = "5.3.0"; |
|
|||
1569 | src = fetchurl { |
|
|||
1570 | url = "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz"; |
|
|||
1571 | sha1 = "9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"; |
|
|||
1572 | }; |
|
|||
1573 | }; |
|
|||
1574 | "create-error-class-3.0.2" = { |
|
|||
1575 | name = "create-error-class"; |
|
|||
1576 | packageName = "create-error-class"; |
|
|||
1577 | version = "3.0.2"; |
|
|||
1578 | src = fetchurl { |
|
1938 | src = fetchurl { | |
1579 |
url = "https://registry.npmjs.org/ |
|
1939 | url = "https://registry.npmjs.org/ssri/-/ssri-4.1.6.tgz"; | |
1580 | sha1 = "06be7abef947a3f14a30fd610671d401bca8b7b6"; |
|
1940 | sha1 = "0cb49b6ac84457e7bdd466cb730c3cb623e9a25b"; | |
1581 | }; |
|
|||
1582 | }; |
|
|||
1583 | "duplexer2-0.1.4" = { |
|
|||
1584 | name = "duplexer2"; |
|
|||
1585 | packageName = "duplexer2"; |
|
|||
1586 | version = "0.1.4"; |
|
|||
1587 | src = fetchurl { |
|
|||
1588 | url = "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz"; |
|
|||
1589 | sha1 = "8b12dab878c0d69e3e7891051662a32fc6bddcc1"; |
|
|||
1590 | }; |
|
|||
1591 | }; |
|
|||
1592 | "is-plain-obj-1.1.0" = { |
|
|||
1593 | name = "is-plain-obj"; |
|
|||
1594 | packageName = "is-plain-obj"; |
|
|||
1595 | version = "1.1.0"; |
|
|||
1596 | src = fetchurl { |
|
|||
1597 | url = "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz"; |
|
|||
1598 | sha1 = "71a50c8429dfca773c92a390a4a03b39fcd51d3e"; |
|
|||
1599 | }; |
|
|||
1600 | }; |
|
|||
1601 | "is-redirect-1.0.0" = { |
|
|||
1602 | name = "is-redirect"; |
|
|||
1603 | packageName = "is-redirect"; |
|
|||
1604 | version = "1.0.0"; |
|
|||
1605 | src = fetchurl { |
|
|||
1606 | url = "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz"; |
|
|||
1607 | sha1 = "1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"; |
|
|||
1608 | }; |
|
|||
1609 | }; |
|
|||
1610 | "is-retry-allowed-1.1.0" = { |
|
|||
1611 | name = "is-retry-allowed"; |
|
|||
1612 | packageName = "is-retry-allowed"; |
|
|||
1613 | version = "1.1.0"; |
|
|||
1614 | src = fetchurl { |
|
|||
1615 | url = "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz"; |
|
|||
1616 | sha1 = "11a060568b67339444033d0125a61a20d564fb34"; |
|
|||
1617 | }; |
|
|||
1618 | }; |
|
|||
1619 | "is-stream-1.1.0" = { |
|
|||
1620 | name = "is-stream"; |
|
|||
1621 | packageName = "is-stream"; |
|
|||
1622 | version = "1.1.0"; |
|
|||
1623 | src = fetchurl { |
|
|||
1624 | url = "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz"; |
|
|||
1625 | sha1 = "12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"; |
|
|||
1626 | }; |
|
|||
1627 | }; |
|
|||
1628 | "lowercase-keys-1.0.0" = { |
|
|||
1629 | name = "lowercase-keys"; |
|
|||
1630 | packageName = "lowercase-keys"; |
|
|||
1631 | version = "1.0.0"; |
|
|||
1632 | src = fetchurl { |
|
|||
1633 | url = "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz"; |
|
|||
1634 | sha1 = "4e3366b39e7f5457e35f1324bdf6f88d0bfc7306"; |
|
|||
1635 | }; |
|
1941 | }; | |
1636 | }; |
|
1942 | }; | |
1637 | "node-status-codes-1.0.0" = { |
|
1943 | "npmlog-4.1.2" = { | |
1638 |
name = "no |
|
1944 | name = "npmlog"; | |
1639 |
packageName = "no |
|
1945 | packageName = "npmlog"; | |
1640 |
version = "1. |
|
1946 | version = "4.1.2"; | |
1641 | src = fetchurl { |
|
|||
1642 | url = "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz"; |
|
|||
1643 | sha1 = "5ae5541d024645d32a58fcddc9ceecea7ae3ac2f"; |
|
|||
1644 | }; |
|
|||
1645 | }; |
|
|||
1646 | "parse-json-2.2.0" = { |
|
|||
1647 | name = "parse-json"; |
|
|||
1648 | packageName = "parse-json"; |
|
|||
1649 | version = "2.2.0"; |
|
|||
1650 | src = fetchurl { |
|
|||
1651 | url = "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz"; |
|
|||
1652 | sha1 = "f480f40434ef80741f8469099f8dea18f55a4dc9"; |
|
|||
1653 | }; |
|
|||
1654 | }; |
|
|||
1655 | "pinkie-promise-2.0.1" = { |
|
|||
1656 | name = "pinkie-promise"; |
|
|||
1657 | packageName = "pinkie-promise"; |
|
|||
1658 | version = "2.0.1"; |
|
|||
1659 | src = fetchurl { |
|
1947 | src = fetchurl { | |
1660 |
url = "https://registry.npmjs.org/p |
|
1948 | url = "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz"; | |
1661 | sha1 = "2135d6dfa7a358c069ac9b178776288228450ffa"; |
|
1949 | sha1 = "08a7f2a8bf734604779a9efa4ad5cc717abb954b"; | |
1662 | }; |
|
|||
1663 | }; |
|
|||
1664 | "read-all-stream-3.1.0" = { |
|
|||
1665 | name = "read-all-stream"; |
|
|||
1666 | packageName = "read-all-stream"; |
|
|||
1667 | version = "3.1.0"; |
|
|||
1668 | src = fetchurl { |
|
|||
1669 | url = "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz"; |
|
|||
1670 | sha1 = "35c3e177f2078ef789ee4bfafa4373074eaef4fa"; |
|
|||
1671 | }; |
|
|||
1672 | }; |
|
|||
1673 | "readable-stream-2.1.5" = { |
|
|||
1674 | name = "readable-stream"; |
|
|||
1675 | packageName = "readable-stream"; |
|
|||
1676 | version = "2.1.5"; |
|
|||
1677 | src = fetchurl { |
|
|||
1678 | url = "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz"; |
|
|||
1679 | sha1 = "66fa8b720e1438b364681f2ad1a63c618448c9d0"; |
|
|||
1680 | }; |
|
|||
1681 | }; |
|
|||
1682 | "timed-out-2.0.0" = { |
|
|||
1683 | name = "timed-out"; |
|
|||
1684 | packageName = "timed-out"; |
|
|||
1685 | version = "2.0.0"; |
|
|||
1686 | src = fetchurl { |
|
|||
1687 | url = "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz"; |
|
|||
1688 | sha1 = "f38b0ae81d3747d628001f41dafc652ace671c0a"; |
|
|||
1689 | }; |
|
1950 | }; | |
1690 | }; |
|
1951 | }; | |
1691 | "unzip-response-1.0.1" = { |
|
1952 | "typedarray-0.0.6" = { | |
1692 |
name = " |
|
1953 | name = "typedarray"; | |
1693 |
packageName = " |
|
1954 | packageName = "typedarray"; | |
1694 |
version = " |
|
1955 | version = "0.0.6"; | |
1695 | src = fetchurl { |
|
1956 | src = fetchurl { | |
1696 |
url = "https://registry.npmjs.org/ |
|
1957 | url = "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"; | |
1697 | sha1 = "4a73959f2989470fa503791cefb54e1dbbc68412"; |
|
1958 | sha1 = "867ac74e3864187b1d3d47d996a78ec5c8830777"; | |
1698 | }; |
|
|||
1699 | }; |
|
|||
1700 | "url-parse-lax-1.0.0" = { |
|
|||
1701 | name = "url-parse-lax"; |
|
|||
1702 | packageName = "url-parse-lax"; |
|
|||
1703 | version = "1.0.0"; |
|
|||
1704 | src = fetchurl { |
|
|||
1705 | url = "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz"; |
|
|||
1706 | sha1 = "7af8f303645e9bd79a272e7a14ac68bc0609da73"; |
|
|||
1707 | }; |
|
|||
1708 | }; |
|
|||
1709 | "capture-stack-trace-1.0.0" = { |
|
|||
1710 | name = "capture-stack-trace"; |
|
|||
1711 | packageName = "capture-stack-trace"; |
|
|||
1712 | version = "1.0.0"; |
|
|||
1713 | src = fetchurl { |
|
|||
1714 | url = "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz"; |
|
|||
1715 | sha1 = "4a6fa07399c26bba47f0b2496b4d0fb408c5550d"; |
|
|||
1716 | }; |
|
1959 | }; | |
1717 | }; |
|
1960 | }; | |
1718 | "error-ex-1.3.0" = { |
|
1961 | "readable-stream-2.3.3" = { | |
1719 |
name = "er |
|
1962 | name = "readable-stream"; | |
1720 |
packageName = "er |
|
1963 | packageName = "readable-stream"; | |
1721 |
version = " |
|
1964 | version = "2.3.3"; | |
1722 | src = fetchurl { |
|
|||
1723 | url = "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz"; |
|
|||
1724 | sha1 = "e67b43f3e82c96ea3a584ffee0b9fc3325d802d9"; |
|
|||
1725 | }; |
|
|||
1726 | }; |
|
|||
1727 | "is-arrayish-0.2.1" = { |
|
|||
1728 | name = "is-arrayish"; |
|
|||
1729 | packageName = "is-arrayish"; |
|
|||
1730 | version = "0.2.1"; |
|
|||
1731 | src = fetchurl { |
|
1965 | src = fetchurl { | |
1732 |
url = "https://registry.npmjs.org/ |
|
1966 | url = "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz"; | |
1733 | sha1 = "77c99840527aa8ecb1a8ba697b80645a7a926a9d"; |
|
1967 | sha1 = "368f2512d79f9d46fdfc71349ae7878bbc1eb95c"; | |
1734 | }; |
|
|||
1735 | }; |
|
|||
1736 | "pinkie-2.0.4" = { |
|
|||
1737 | name = "pinkie"; |
|
|||
1738 | packageName = "pinkie"; |
|
|||
1739 | version = "2.0.4"; |
|
|||
1740 | src = fetchurl { |
|
|||
1741 | url = "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz"; |
|
|||
1742 | sha1 = "72556b80cfa0d48a974e80e77248e80ed4f7f870"; |
|
|||
1743 | }; |
|
|||
1744 | }; |
|
|||
1745 | "buffer-shims-1.0.0" = { |
|
|||
1746 | name = "buffer-shims"; |
|
|||
1747 | packageName = "buffer-shims"; |
|
|||
1748 | version = "1.0.0"; |
|
|||
1749 | src = fetchurl { |
|
|||
1750 | url = "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz"; |
|
|||
1751 | sha1 = "9978ce317388c649ad8793028c3477ef044a8b51"; |
|
|||
1752 | }; |
|
|||
1753 | }; |
|
|||
1754 | "core-util-is-1.0.2" = { |
|
|||
1755 | name = "core-util-is"; |
|
|||
1756 | packageName = "core-util-is"; |
|
|||
1757 | version = "1.0.2"; |
|
|||
1758 | src = fetchurl { |
|
|||
1759 | url = "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"; |
|
|||
1760 | sha1 = "b5fd54220aa2bc5ab57aab7140c940754503c1a7"; |
|
|||
1761 | }; |
|
1968 | }; | |
1762 | }; |
|
1969 | }; | |
1763 | "isarray-1.0.0" = { |
|
1970 | "isarray-1.0.0" = { | |
@@ -1778,13 +1985,13 b' let' | |||||
1778 | sha1 = "150e20b756590ad3f91093f25a4f2ad8bff30ba3"; |
|
1985 | sha1 = "150e20b756590ad3f91093f25a4f2ad8bff30ba3"; | |
1779 | }; |
|
1986 | }; | |
1780 | }; |
|
1987 | }; | |
1781 |
"string_decoder- |
|
1988 | "string_decoder-1.0.3" = { | |
1782 | name = "string_decoder"; |
|
1989 | name = "string_decoder"; | |
1783 | packageName = "string_decoder"; |
|
1990 | packageName = "string_decoder"; | |
1784 |
version = " |
|
1991 | version = "1.0.3"; | |
1785 | src = fetchurl { |
|
1992 | src = fetchurl { | |
1786 |
url = "https://registry.npmjs.org/string_decoder/-/string_decoder- |
|
1993 | url = "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz"; | |
1787 | sha1 = "62e203bc41766c6c28c9fc84301dab1c5310fa94"; |
|
1994 | sha1 = "0fc67d7c141825de94282dd536bec6b9bce860ab"; | |
1788 | }; |
|
1995 | }; | |
1789 | }; |
|
1996 | }; | |
1790 | "util-deprecate-1.0.2" = { |
|
1997 | "util-deprecate-1.0.2" = { | |
@@ -1796,22 +2003,247 b' let' | |||||
1796 | sha1 = "450d4dc9fa70de732762fbd2d4a28981419a0ccf"; |
|
2003 | sha1 = "450d4dc9fa70de732762fbd2d4a28981419a0ccf"; | |
1797 | }; |
|
2004 | }; | |
1798 | }; |
|
2005 | }; | |
1799 | "prepend-http-1.0.4" = { |
|
2006 | "hosted-git-info-2.5.0" = { | |
1800 |
name = " |
|
2007 | name = "hosted-git-info"; | |
1801 |
packageName = " |
|
2008 | packageName = "hosted-git-info"; | |
|
2009 | version = "2.5.0"; | |||
|
2010 | src = fetchurl { | |||
|
2011 | url = "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz"; | |||
|
2012 | sha1 = "6d60e34b3abbc8313062c3b798ef8d901a07af3c"; | |||
|
2013 | }; | |||
|
2014 | }; | |||
|
2015 | "is-builtin-module-1.0.0" = { | |||
|
2016 | name = "is-builtin-module"; | |||
|
2017 | packageName = "is-builtin-module"; | |||
|
2018 | version = "1.0.0"; | |||
|
2019 | src = fetchurl { | |||
|
2020 | url = "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz"; | |||
|
2021 | sha1 = "540572d34f7ac3119f8f76c30cbc1b1e037affbe"; | |||
|
2022 | }; | |||
|
2023 | }; | |||
|
2024 | "validate-npm-package-license-3.0.1" = { | |||
|
2025 | name = "validate-npm-package-license"; | |||
|
2026 | packageName = "validate-npm-package-license"; | |||
|
2027 | version = "3.0.1"; | |||
|
2028 | src = fetchurl { | |||
|
2029 | url = "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz"; | |||
|
2030 | sha1 = "2804babe712ad3379459acfbe24746ab2c303fbc"; | |||
|
2031 | }; | |||
|
2032 | }; | |||
|
2033 | "builtin-modules-1.1.1" = { | |||
|
2034 | name = "builtin-modules"; | |||
|
2035 | packageName = "builtin-modules"; | |||
|
2036 | version = "1.1.1"; | |||
|
2037 | src = fetchurl { | |||
|
2038 | url = "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz"; | |||
|
2039 | sha1 = "270f076c5a72c02f5b65a47df94c5fe3a278892f"; | |||
|
2040 | }; | |||
|
2041 | }; | |||
|
2042 | "spdx-correct-1.0.2" = { | |||
|
2043 | name = "spdx-correct"; | |||
|
2044 | packageName = "spdx-correct"; | |||
|
2045 | version = "1.0.2"; | |||
|
2046 | src = fetchurl { | |||
|
2047 | url = "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz"; | |||
|
2048 | sha1 = "4b3073d933ff51f3912f03ac5519498a4150db40"; | |||
|
2049 | }; | |||
|
2050 | }; | |||
|
2051 | "spdx-expression-parse-1.0.4" = { | |||
|
2052 | name = "spdx-expression-parse"; | |||
|
2053 | packageName = "spdx-expression-parse"; | |||
1802 | version = "1.0.4"; |
|
2054 | version = "1.0.4"; | |
1803 | src = fetchurl { |
|
2055 | src = fetchurl { | |
1804 |
url = "https://registry.npmjs.org/prepe |
|
2056 | url = "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz"; | |
1805 | sha1 = "d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"; |
|
2057 | sha1 = "9bdf2f20e1f40ed447fbe273266191fced51626c"; | |
|
2058 | }; | |||
|
2059 | }; | |||
|
2060 | "spdx-license-ids-1.2.2" = { | |||
|
2061 | name = "spdx-license-ids"; | |||
|
2062 | packageName = "spdx-license-ids"; | |||
|
2063 | version = "1.2.2"; | |||
|
2064 | src = fetchurl { | |||
|
2065 | url = "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz"; | |||
|
2066 | sha1 = "c9df7a3424594ade6bd11900d596696dc06bac57"; | |||
|
2067 | }; | |||
|
2068 | }; | |||
|
2069 | "osenv-0.1.4" = { | |||
|
2070 | name = "osenv"; | |||
|
2071 | packageName = "osenv"; | |||
|
2072 | version = "0.1.4"; | |||
|
2073 | src = fetchurl { | |||
|
2074 | url = "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz"; | |||
|
2075 | sha1 = "42fe6d5953df06c8064be6f176c3d05aaaa34644"; | |||
|
2076 | }; | |||
|
2077 | }; | |||
|
2078 | "validate-npm-package-name-3.0.0" = { | |||
|
2079 | name = "validate-npm-package-name"; | |||
|
2080 | packageName = "validate-npm-package-name"; | |||
|
2081 | version = "3.0.0"; | |||
|
2082 | src = fetchurl { | |||
|
2083 | url = "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz"; | |||
|
2084 | sha1 = "5fa912d81eb7d0c74afc140de7317f0ca7df437e"; | |||
|
2085 | }; | |||
|
2086 | }; | |||
|
2087 | "os-homedir-1.0.2" = { | |||
|
2088 | name = "os-homedir"; | |||
|
2089 | packageName = "os-homedir"; | |||
|
2090 | version = "1.0.2"; | |||
|
2091 | src = fetchurl { | |||
|
2092 | url = "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz"; | |||
|
2093 | sha1 = "ffbc4988336e0e833de0c168c7ef152121aa7fb3"; | |||
|
2094 | }; | |||
|
2095 | }; | |||
|
2096 | "os-tmpdir-1.0.2" = { | |||
|
2097 | name = "os-tmpdir"; | |||
|
2098 | packageName = "os-tmpdir"; | |||
|
2099 | version = "1.0.2"; | |||
|
2100 | src = fetchurl { | |||
|
2101 | url = "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"; | |||
|
2102 | sha1 = "bbe67406c79aa85c5cfec766fe5734555dfa1274"; | |||
|
2103 | }; | |||
|
2104 | }; | |||
|
2105 | "builtins-1.0.3" = { | |||
|
2106 | name = "builtins"; | |||
|
2107 | packageName = "builtins"; | |||
|
2108 | version = "1.0.3"; | |||
|
2109 | src = fetchurl { | |||
|
2110 | url = "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz"; | |||
|
2111 | sha1 = "cb94faeb61c8696451db36534e1422f94f0aee88"; | |||
|
2112 | }; | |||
|
2113 | }; | |||
|
2114 | "wrappy-1.0.2" = { | |||
|
2115 | name = "wrappy"; | |||
|
2116 | packageName = "wrappy"; | |||
|
2117 | version = "1.0.2"; | |||
|
2118 | src = fetchurl { | |||
|
2119 | url = "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"; | |||
|
2120 | sha1 = "b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"; | |||
|
2121 | }; | |||
|
2122 | }; | |||
|
2123 | "are-we-there-yet-1.1.4" = { | |||
|
2124 | name = "are-we-there-yet"; | |||
|
2125 | packageName = "are-we-there-yet"; | |||
|
2126 | version = "1.1.4"; | |||
|
2127 | src = fetchurl { | |||
|
2128 | url = "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz"; | |||
|
2129 | sha1 = "bb5dca382bb94f05e15194373d16fd3ba1ca110d"; | |||
|
2130 | }; | |||
|
2131 | }; | |||
|
2132 | "console-control-strings-1.1.0" = { | |||
|
2133 | name = "console-control-strings"; | |||
|
2134 | packageName = "console-control-strings"; | |||
|
2135 | version = "1.1.0"; | |||
|
2136 | src = fetchurl { | |||
|
2137 | url = "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz"; | |||
|
2138 | sha1 = "3d7cf4464db6446ea644bf4b39507f9851008e8e"; | |||
|
2139 | }; | |||
|
2140 | }; | |||
|
2141 | "gauge-2.7.4" = { | |||
|
2142 | name = "gauge"; | |||
|
2143 | packageName = "gauge"; | |||
|
2144 | version = "2.7.4"; | |||
|
2145 | src = fetchurl { | |||
|
2146 | url = "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz"; | |||
|
2147 | sha1 = "2c03405c7538c39d7eb37b317022e325fb018bf7"; | |||
1806 | }; |
|
2148 | }; | |
1807 | }; |
|
2149 | }; | |
1808 |
" |
|
2150 | "set-blocking-2.0.0" = { | |
1809 |
name = " |
|
2151 | name = "set-blocking"; | |
1810 |
packageName = " |
|
2152 | packageName = "set-blocking"; | |
1811 |
version = " |
|
2153 | version = "2.0.0"; | |
|
2154 | src = fetchurl { | |||
|
2155 | url = "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz"; | |||
|
2156 | sha1 = "045f9782d011ae9a6803ddd382b24392b3d890f7"; | |||
|
2157 | }; | |||
|
2158 | }; | |||
|
2159 | "delegates-1.0.0" = { | |||
|
2160 | name = "delegates"; | |||
|
2161 | packageName = "delegates"; | |||
|
2162 | version = "1.0.0"; | |||
|
2163 | src = fetchurl { | |||
|
2164 | url = "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz"; | |||
|
2165 | sha1 = "84c6e159b81904fdca59a0ef44cd870d31250f9a"; | |||
|
2166 | }; | |||
|
2167 | }; | |||
|
2168 | "aproba-1.2.0" = { | |||
|
2169 | name = "aproba"; | |||
|
2170 | packageName = "aproba"; | |||
|
2171 | version = "1.2.0"; | |||
|
2172 | src = fetchurl { | |||
|
2173 | url = "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz"; | |||
|
2174 | sha1 = "6802e6264efd18c790a1b0d517f0f2627bf2c94a"; | |||
|
2175 | }; | |||
|
2176 | }; | |||
|
2177 | "has-unicode-2.0.1" = { | |||
|
2178 | name = "has-unicode"; | |||
|
2179 | packageName = "has-unicode"; | |||
|
2180 | version = "2.0.1"; | |||
|
2181 | src = fetchurl { | |||
|
2182 | url = "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz"; | |||
|
2183 | sha1 = "e0e6fe6a28cf51138855e086d1691e771de2a8b9"; | |||
|
2184 | }; | |||
|
2185 | }; | |||
|
2186 | "signal-exit-3.0.2" = { | |||
|
2187 | name = "signal-exit"; | |||
|
2188 | packageName = "signal-exit"; | |||
|
2189 | version = "3.0.2"; | |||
1812 | src = fetchurl { |
|
2190 | src = fetchurl { | |
1813 |
url = "https://registry.npmjs.org/ |
|
2191 | url = "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz"; | |
1814 | sha1 = "43651b76b6ae53b5c802f1151fa3fc3b059969c9"; |
|
2192 | sha1 = "b5fdc08f1287ea1178628e415e25132b73646c6d"; | |
|
2193 | }; | |||
|
2194 | }; | |||
|
2195 | "string-width-1.0.2" = { | |||
|
2196 | name = "string-width"; | |||
|
2197 | packageName = "string-width"; | |||
|
2198 | version = "1.0.2"; | |||
|
2199 | src = fetchurl { | |||
|
2200 | url = "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz"; | |||
|
2201 | sha1 = "118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"; | |||
|
2202 | }; | |||
|
2203 | }; | |||
|
2204 | "wide-align-1.1.2" = { | |||
|
2205 | name = "wide-align"; | |||
|
2206 | packageName = "wide-align"; | |||
|
2207 | version = "1.1.2"; | |||
|
2208 | src = fetchurl { | |||
|
2209 | url = "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz"; | |||
|
2210 | sha1 = "571e0f1b0604636ebc0dfc21b0339bbe31341710"; | |||
|
2211 | }; | |||
|
2212 | }; | |||
|
2213 | "code-point-at-1.1.0" = { | |||
|
2214 | name = "code-point-at"; | |||
|
2215 | packageName = "code-point-at"; | |||
|
2216 | version = "1.1.0"; | |||
|
2217 | src = fetchurl { | |||
|
2218 | url = "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz"; | |||
|
2219 | sha1 = "0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"; | |||
|
2220 | }; | |||
|
2221 | }; | |||
|
2222 | "is-fullwidth-code-point-1.0.0" = { | |||
|
2223 | name = "is-fullwidth-code-point"; | |||
|
2224 | packageName = "is-fullwidth-code-point"; | |||
|
2225 | version = "1.0.0"; | |||
|
2226 | src = fetchurl { | |||
|
2227 | url = "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz"; | |||
|
2228 | sha1 = "ef9e31386f031a7f0d643af82fde50c457ef00cb"; | |||
|
2229 | }; | |||
|
2230 | }; | |||
|
2231 | "number-is-nan-1.0.1" = { | |||
|
2232 | name = "number-is-nan"; | |||
|
2233 | packageName = "number-is-nan"; | |||
|
2234 | version = "1.0.1"; | |||
|
2235 | src = fetchurl { | |||
|
2236 | url = "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz"; | |||
|
2237 | sha1 = "097b602b53422a522c1afb8790318336941a011d"; | |||
|
2238 | }; | |||
|
2239 | }; | |||
|
2240 | "config-chain-1.1.11" = { | |||
|
2241 | name = "config-chain"; | |||
|
2242 | packageName = "config-chain"; | |||
|
2243 | version = "1.1.11"; | |||
|
2244 | src = fetchurl { | |||
|
2245 | url = "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz"; | |||
|
2246 | sha1 = "aba09747dfbe4c3e70e766a6e41586e1859fc6f2"; | |||
1815 | }; |
|
2247 | }; | |
1816 | }; |
|
2248 | }; | |
1817 | "ini-1.3.4" = { |
|
2249 | "ini-1.3.4" = { | |
@@ -1823,40 +2255,130 b' let' | |||||
1823 | sha1 = "0537cb79daf59b59a1a517dff706c86ec039162e"; |
|
2255 | sha1 = "0537cb79daf59b59a1a517dff706c86ec039162e"; | |
1824 | }; |
|
2256 | }; | |
1825 | }; |
|
2257 | }; | |
1826 |
" |
|
2258 | "once-1.3.3" = { | |
1827 |
name = " |
|
2259 | name = "once"; | |
1828 |
packageName = " |
|
2260 | packageName = "once"; | |
1829 |
version = "1. |
|
2261 | version = "1.3.3"; | |
|
2262 | src = fetchurl { | |||
|
2263 | url = "https://registry.npmjs.org/once/-/once-1.3.3.tgz"; | |||
|
2264 | sha1 = "b2e261557ce4c314ec8304f3fa82663e4297ca20"; | |||
|
2265 | }; | |||
|
2266 | }; | |||
|
2267 | "semver-4.3.6" = { | |||
|
2268 | name = "semver"; | |||
|
2269 | packageName = "semver"; | |||
|
2270 | version = "4.3.6"; | |||
|
2271 | src = fetchurl { | |||
|
2272 | url = "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"; | |||
|
2273 | sha1 = "300bc6e0e86374f7ba61068b5b1ecd57fc6532da"; | |||
|
2274 | }; | |||
|
2275 | }; | |||
|
2276 | "uid-number-0.0.5" = { | |||
|
2277 | name = "uid-number"; | |||
|
2278 | packageName = "uid-number"; | |||
|
2279 | version = "0.0.5"; | |||
1830 | src = fetchurl { |
|
2280 | src = fetchurl { | |
1831 |
url = "https://registry.npmjs.org/m |
|
2281 | url = "https://registry.npmjs.org/uid-number/-/uid-number-0.0.5.tgz"; | |
1832 | sha1 = "a35008b20f41383eec1fb914f4cd5df79a264284"; |
|
2282 | sha1 = "5a3db23ef5dbd55b81fce0ec9a2ac6fccdebb81e"; | |
|
2283 | }; | |||
|
2284 | }; | |||
|
2285 | "proto-list-1.2.4" = { | |||
|
2286 | name = "proto-list"; | |||
|
2287 | packageName = "proto-list"; | |||
|
2288 | version = "1.2.4"; | |||
|
2289 | src = fetchurl { | |||
|
2290 | url = "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz"; | |||
|
2291 | sha1 = "212d5bfe1318306a420f6402b8e26ff39647a849"; | |||
|
2292 | }; | |||
|
2293 | }; | |||
|
2294 | "minipass-2.2.1" = { | |||
|
2295 | name = "minipass"; | |||
|
2296 | packageName = "minipass"; | |||
|
2297 | version = "2.2.1"; | |||
|
2298 | src = fetchurl { | |||
|
2299 | url = "https://registry.npmjs.org/minipass/-/minipass-2.2.1.tgz"; | |||
|
2300 | sha1 = "5ada97538b1027b4cf7213432428578cb564011f"; | |||
|
2301 | }; | |||
|
2302 | }; | |||
|
2303 | "minizlib-1.0.3" = { | |||
|
2304 | name = "minizlib"; | |||
|
2305 | packageName = "minizlib"; | |||
|
2306 | version = "1.0.3"; | |||
|
2307 | src = fetchurl { | |||
|
2308 | url = "https://registry.npmjs.org/minizlib/-/minizlib-1.0.3.tgz"; | |||
|
2309 | sha1 = "d5c1abf77be154619952e253336eccab9b2a32f5"; | |||
1833 | }; |
|
2310 | }; | |
1834 | }; |
|
2311 | }; | |
1835 | "strip-json-comments-1.0.4" = { |
|
2312 | "yallist-3.0.2" = { | |
1836 |
name = "st |
|
2313 | name = "yallist"; | |
1837 |
packageName = "st |
|
2314 | packageName = "yallist"; | |
1838 |
version = " |
|
2315 | version = "3.0.2"; | |
1839 | src = fetchurl { |
|
2316 | src = fetchurl { | |
1840 |
url = "https://registry.npmjs.org/st |
|
2317 | url = "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz"; | |
1841 | sha1 = "1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"; |
|
2318 | sha1 = "8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"; | |
|
2319 | }; | |||
|
2320 | }; | |||
|
2321 | "fs-extra-0.6.4" = { | |||
|
2322 | name = "fs-extra"; | |||
|
2323 | packageName = "fs-extra"; | |||
|
2324 | version = "0.6.4"; | |||
|
2325 | src = fetchurl { | |||
|
2326 | url = "https://registry.npmjs.org/fs-extra/-/fs-extra-0.6.4.tgz"; | |||
|
2327 | sha1 = "f46f0c75b7841f8d200b3348cd4d691d5a099d15"; | |||
|
2328 | }; | |||
|
2329 | }; | |||
|
2330 | "mkdirp-0.3.5" = { | |||
|
2331 | name = "mkdirp"; | |||
|
2332 | packageName = "mkdirp"; | |||
|
2333 | version = "0.3.5"; | |||
|
2334 | src = fetchurl { | |||
|
2335 | url = "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz"; | |||
|
2336 | sha1 = "de3e5f8961c88c787ee1368df849ac4413eca8d7"; | |||
1842 | }; |
|
2337 | }; | |
1843 | }; |
|
2338 | }; | |
1844 |
" |
|
2339 | "walk-2.3.9" = { | |
1845 |
name = " |
|
2340 | name = "walk"; | |
1846 |
packageName = " |
|
2341 | packageName = "walk"; | |
1847 |
version = " |
|
2342 | version = "2.3.9"; | |
1848 | src = fetchurl { |
|
2343 | src = fetchurl { | |
1849 |
url = "https://registry.npmjs.org/ |
|
2344 | url = "https://registry.npmjs.org/walk/-/walk-2.3.9.tgz"; | |
1850 | sha1 = "9a91f597d71f6110294e076ad44dbb3408568e46"; |
|
2345 | sha1 = "31b4db6678f2ae01c39ea9fb8725a9031e558a7b"; | |
|
2346 | }; | |||
|
2347 | }; | |||
|
2348 | "ncp-0.4.2" = { | |||
|
2349 | name = "ncp"; | |||
|
2350 | packageName = "ncp"; | |||
|
2351 | version = "0.4.2"; | |||
|
2352 | src = fetchurl { | |||
|
2353 | url = "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz"; | |||
|
2354 | sha1 = "abcc6cbd3ec2ed2a729ff6e7c1fa8f01784a8574"; | |||
1851 | }; |
|
2355 | }; | |
1852 | }; |
|
2356 | }; | |
1853 |
" |
|
2357 | "jsonfile-1.0.1" = { | |
|
2358 | name = "jsonfile"; | |||
|
2359 | packageName = "jsonfile"; | |||
|
2360 | version = "1.0.1"; | |||
|
2361 | src = fetchurl { | |||
|
2362 | url = "https://registry.npmjs.org/jsonfile/-/jsonfile-1.0.1.tgz"; | |||
|
2363 | sha1 = "ea5efe40b83690b98667614a7392fc60e842c0dd"; | |||
|
2364 | }; | |||
|
2365 | }; | |||
|
2366 | "foreachasync-3.0.0" = { | |||
|
2367 | name = "foreachasync"; | |||
|
2368 | packageName = "foreachasync"; | |||
|
2369 | version = "3.0.0"; | |||
|
2370 | src = fetchurl { | |||
|
2371 | url = "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz"; | |||
|
2372 | sha1 = "5502987dc8714be3392097f32e0071c9dee07cf6"; | |||
|
2373 | }; | |||
|
2374 | }; | |||
|
2375 | "cli-1.0.1" = { | |||
1854 | name = "cli"; |
|
2376 | name = "cli"; | |
1855 | packageName = "cli"; |
|
2377 | packageName = "cli"; | |
1856 |
version = "1.0. |
|
2378 | version = "1.0.1"; | |
1857 | src = fetchurl { |
|
2379 | src = fetchurl { | |
1858 |
url = "https://registry.npmjs.org/cli/-/cli-1.0. |
|
2380 | url = "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz"; | |
1859 | sha1 = "ee07dfc1390e3f2e6a9957cf88e1d4bfa777719d"; |
|
2381 | sha1 = "22817534f24bfa4950c34d532d48ecbc621b8c14"; | |
1860 | }; |
|
2382 | }; | |
1861 | }; |
|
2383 | }; | |
1862 | "console-browserify-1.1.0" = { |
|
2384 | "console-browserify-1.1.0" = { | |
@@ -1877,13 +2399,13 b' let' | |||||
1877 | sha1 = "996c28b191516a8be86501a7d79757e5c70c1068"; |
|
2399 | sha1 = "996c28b191516a8be86501a7d79757e5c70c1068"; | |
1878 | }; |
|
2400 | }; | |
1879 | }; |
|
2401 | }; | |
1880 |
"minimatch-3.0. |
|
2402 | "minimatch-3.0.4" = { | |
1881 | name = "minimatch"; |
|
2403 | name = "minimatch"; | |
1882 | packageName = "minimatch"; |
|
2404 | packageName = "minimatch"; | |
1883 |
version = "3.0. |
|
2405 | version = "3.0.4"; | |
1884 | src = fetchurl { |
|
2406 | src = fetchurl { | |
1885 |
url = "https://registry.npmjs.org/minimatch/-/minimatch-3.0. |
|
2407 | url = "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz"; | |
1886 | sha1 = "2a4e4090b96b2db06a9d7df01055a62a77c9b774"; |
|
2408 | sha1 = "5166e286457f03306064be5497e8dbb0c3d32083"; | |
1887 | }; |
|
2409 | }; | |
1888 | }; |
|
2410 | }; | |
1889 | "shelljs-0.3.0" = { |
|
2411 | "shelljs-0.3.0" = { | |
@@ -1895,6 +2417,15 b' let' | |||||
1895 | sha1 = "3596e6307a781544f591f37da618360f31db57b1"; |
|
2417 | sha1 = "3596e6307a781544f591f37da618360f31db57b1"; | |
1896 | }; |
|
2418 | }; | |
1897 | }; |
|
2419 | }; | |
|
2420 | "strip-json-comments-1.0.4" = { | |||
|
2421 | name = "strip-json-comments"; | |||
|
2422 | packageName = "strip-json-comments"; | |||
|
2423 | version = "1.0.4"; | |||
|
2424 | src = fetchurl { | |||
|
2425 | url = "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz"; | |||
|
2426 | sha1 = "1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"; | |||
|
2427 | }; | |||
|
2428 | }; | |||
1898 | "lodash-3.7.0" = { |
|
2429 | "lodash-3.7.0" = { | |
1899 | name = "lodash"; |
|
2430 | name = "lodash"; | |
1900 | packageName = "lodash"; |
|
2431 | packageName = "lodash"; | |
@@ -1904,13 +2435,13 b' let' | |||||
1904 | sha1 = "3678bd8ab995057c07ade836ed2ef087da811d45"; |
|
2435 | sha1 = "3678bd8ab995057c07ade836ed2ef087da811d45"; | |
1905 | }; |
|
2436 | }; | |
1906 | }; |
|
2437 | }; | |
1907 |
"glob-7.1. |
|
2438 | "glob-7.1.2" = { | |
1908 | name = "glob"; |
|
2439 | name = "glob"; | |
1909 | packageName = "glob"; |
|
2440 | packageName = "glob"; | |
1910 |
version = "7.1. |
|
2441 | version = "7.1.2"; | |
1911 | src = fetchurl { |
|
2442 | src = fetchurl { | |
1912 |
url = "https://registry.npmjs.org/glob/-/glob-7.1. |
|
2443 | url = "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz"; | |
1913 | sha1 = "36add856d746d0d99e4cc2797bba1ae2c67272fd"; |
|
2444 | sha1 = "c19c9df9a028702d678612384a6552404c636d15"; | |
1914 | }; |
|
2445 | }; | |
1915 | }; |
|
2446 | }; | |
1916 | "fs.realpath-1.0.0" = { |
|
2447 | "fs.realpath-1.0.0" = { | |
@@ -1922,49 +2453,31 b' let' | |||||
1922 | sha1 = "1504ad2523158caa40db4a2787cb01411994ea4f"; |
|
2453 | sha1 = "1504ad2523158caa40db4a2787cb01411994ea4f"; | |
1923 | }; |
|
2454 | }; | |
1924 | }; |
|
2455 | }; | |
1925 |
"inflight-1.0. |
|
2456 | "inflight-1.0.6" = { | |
1926 | name = "inflight"; |
|
2457 | name = "inflight"; | |
1927 | packageName = "inflight"; |
|
2458 | packageName = "inflight"; | |
1928 |
version = "1.0. |
|
2459 | version = "1.0.6"; | |
1929 | src = fetchurl { |
|
2460 | src = fetchurl { | |
1930 |
url = "https://registry.npmjs.org/inflight/-/inflight-1.0. |
|
2461 | url = "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"; | |
1931 | sha1 = "db3204cd5a9de2e6cd890b85c6e2f66bcf4f620a"; |
|
2462 | sha1 = "49bd6331d7d02d0c09bc910a1075ba8165b56df9"; | |
1932 | }; |
|
|||
1933 | }; |
|
|||
1934 | "once-1.4.0" = { |
|
|||
1935 | name = "once"; |
|
|||
1936 | packageName = "once"; |
|
|||
1937 | version = "1.4.0"; |
|
|||
1938 | src = fetchurl { |
|
|||
1939 | url = "https://registry.npmjs.org/once/-/once-1.4.0.tgz"; |
|
|||
1940 | sha1 = "583b1aa775961d4b113ac17d9c50baef9dd76bd1"; |
|
|||
1941 | }; |
|
2463 | }; | |
1942 | }; |
|
2464 | }; | |
1943 |
" |
|
2465 | "brace-expansion-1.1.8" = { | |
1944 | name = "wrappy"; |
|
|||
1945 | packageName = "wrappy"; |
|
|||
1946 | version = "1.0.2"; |
|
|||
1947 | src = fetchurl { |
|
|||
1948 | url = "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"; |
|
|||
1949 | sha1 = "b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"; |
|
|||
1950 | }; |
|
|||
1951 | }; |
|
|||
1952 | "brace-expansion-1.1.6" = { |
|
|||
1953 | name = "brace-expansion"; |
|
2466 | name = "brace-expansion"; | |
1954 | packageName = "brace-expansion"; |
|
2467 | packageName = "brace-expansion"; | |
1955 |
version = "1.1. |
|
2468 | version = "1.1.8"; | |
1956 | src = fetchurl { |
|
2469 | src = fetchurl { | |
1957 |
url = "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1. |
|
2470 | url = "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz"; | |
1958 | sha1 = "7197d7eaa9b87e648390ea61fc66c84427420df9"; |
|
2471 | sha1 = "c07b211c7c952ec1f8efd51a77ef0d1d3990a292"; | |
1959 | }; |
|
2472 | }; | |
1960 | }; |
|
2473 | }; | |
1961 |
"balanced-match-0. |
|
2474 | "balanced-match-1.0.0" = { | |
1962 | name = "balanced-match"; |
|
2475 | name = "balanced-match"; | |
1963 | packageName = "balanced-match"; |
|
2476 | packageName = "balanced-match"; | |
1964 |
version = "0. |
|
2477 | version = "1.0.0"; | |
1965 | src = fetchurl { |
|
2478 | src = fetchurl { | |
1966 |
url = "https://registry.npmjs.org/balanced-match/-/balanced-match-0. |
|
2479 | url = "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz"; | |
1967 | sha1 = "cb3f3e3c732dc0f01ee70b403f302e61d7709838"; |
|
2480 | sha1 = "89b4d199ab2bee49de164ea02b89ce462d71b767"; | |
1968 | }; |
|
2481 | }; | |
1969 | }; |
|
2482 | }; | |
1970 | "concat-map-0.0.1" = { |
|
2483 | "concat-map-0.0.1" = { | |
@@ -2057,6 +2570,51 b' let' | |||||
2057 | sha1 = "6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"; |
|
2570 | sha1 = "6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"; | |
2058 | }; |
|
2571 | }; | |
2059 | }; |
|
2572 | }; | |
|
2573 | "string_decoder-0.10.31" = { | |||
|
2574 | name = "string_decoder"; | |||
|
2575 | packageName = "string_decoder"; | |||
|
2576 | version = "0.10.31"; | |||
|
2577 | src = fetchurl { | |||
|
2578 | url = "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"; | |||
|
2579 | sha1 = "62e203bc41766c6c28c9fc84301dab1c5310fa94"; | |||
|
2580 | }; | |||
|
2581 | }; | |||
|
2582 | "good-listener-1.2.2" = { | |||
|
2583 | name = "good-listener"; | |||
|
2584 | packageName = "good-listener"; | |||
|
2585 | version = "1.2.2"; | |||
|
2586 | src = fetchurl { | |||
|
2587 | url = "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz"; | |||
|
2588 | sha1 = "d53b30cdf9313dffb7dc9a0d477096aa6d145c50"; | |||
|
2589 | }; | |||
|
2590 | }; | |||
|
2591 | "select-1.1.2" = { | |||
|
2592 | name = "select"; | |||
|
2593 | packageName = "select"; | |||
|
2594 | version = "1.1.2"; | |||
|
2595 | src = fetchurl { | |||
|
2596 | url = "https://registry.npmjs.org/select/-/select-1.1.2.tgz"; | |||
|
2597 | sha1 = "0e7350acdec80b1108528786ec1d4418d11b396d"; | |||
|
2598 | }; | |||
|
2599 | }; | |||
|
2600 | "tiny-emitter-2.0.2" = { | |||
|
2601 | name = "tiny-emitter"; | |||
|
2602 | packageName = "tiny-emitter"; | |||
|
2603 | version = "2.0.2"; | |||
|
2604 | src = fetchurl { | |||
|
2605 | url = "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.2.tgz"; | |||
|
2606 | sha1 = "82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c"; | |||
|
2607 | }; | |||
|
2608 | }; | |||
|
2609 | "delegate-3.1.3" = { | |||
|
2610 | name = "delegate"; | |||
|
2611 | packageName = "delegate"; | |||
|
2612 | version = "3.1.3"; | |||
|
2613 | src = fetchurl { | |||
|
2614 | url = "https://registry.npmjs.org/delegate/-/delegate-3.1.3.tgz"; | |||
|
2615 | sha1 = "9a8251a777d7025faa55737bc3b071742127a9fd"; | |||
|
2616 | }; | |||
|
2617 | }; | |||
2060 | }; |
|
2618 | }; | |
2061 | args = { |
|
2619 | args = { | |
2062 | name = "rhodecode-enterprise"; |
|
2620 | name = "rhodecode-enterprise"; | |
@@ -2077,10 +2635,10 b' let' | |||||
2077 | ]; |
|
2635 | ]; | |
2078 | }) |
|
2636 | }) | |
2079 | sources."grunt-contrib-jshint-0.12.0" |
|
2637 | sources."grunt-contrib-jshint-0.12.0" | |
2080 |
(sources."grunt-contrib-less-1.4. |
|
2638 | (sources."grunt-contrib-less-1.4.1" // { | |
2081 | dependencies = [ |
|
2639 | dependencies = [ | |
2082 |
sources."async-2.0 |
|
2640 | sources."async-2.5.0" | |
2083 |
sources."lodash-4.1 |
|
2641 | sources."lodash-4.17.4" | |
2084 | ]; |
|
2642 | ]; | |
2085 | }) |
|
2643 | }) | |
2086 | (sources."grunt-contrib-watch-0.6.1" // { |
|
2644 | (sources."grunt-contrib-watch-0.6.1" // { | |
@@ -2089,8 +2647,8 b' let' | |||||
2089 | sources."async-0.2.10" |
|
2647 | sources."async-0.2.10" | |
2090 | ]; |
|
2648 | ]; | |
2091 | }) |
|
2649 | }) | |
2092 |
sources."crisper-2. |
|
2650 | sources."crisper-2.1.1" | |
2093 |
(sources."vulcanize-1.1 |
|
2651 | (sources."vulcanize-1.16.0" // { | |
2094 | dependencies = [ |
|
2652 | dependencies = [ | |
2095 | sources."nopt-3.0.6" |
|
2653 | sources."nopt-3.0.6" | |
2096 | ]; |
|
2654 | ]; | |
@@ -2102,15 +2660,20 b' let' | |||||
2102 | sources."nopt-3.0.6" |
|
2660 | sources."nopt-3.0.6" | |
2103 | ]; |
|
2661 | ]; | |
2104 | }) |
|
2662 | }) | |
2105 |
|
|
2663 | sources."node2nix-1.3.0" | |
|
2664 | (sources."jshint-2.9.5" // { | |||
2106 | dependencies = [ |
|
2665 | dependencies = [ | |
2107 |
sources."minimatch-3.0. |
|
2666 | sources."minimatch-3.0.4" | |
2108 | sources."lodash-3.7.0" |
|
2667 | sources."lodash-3.7.0" | |
2109 | ]; |
|
2668 | ]; | |
2110 | }) |
|
2669 | }) | |
2111 |
sources."bower-1. |
|
2670 | sources."bower-1.8.2" | |
|
2671 | sources."jquery-1.11.3" | |||
2112 | sources."favico.js-0.3.10" |
|
2672 | sources."favico.js-0.3.10" | |
2113 | sources."appenlight-client-git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.0" |
|
2673 | sources."clipboard-1.7.1" | |
|
2674 | sources."moment-2.18.1" | |||
|
2675 | sources."mousetrap-1.6.1" | |||
|
2676 | sources."appenlight-client-git+https://git@github.com/AppEnlight/appenlight-client-js.git#0.5.1" | |||
2114 | sources."async-0.1.22" |
|
2677 | sources."async-0.1.22" | |
2115 | sources."coffee-script-1.3.3" |
|
2678 | sources."coffee-script-1.3.3" | |
2116 | sources."colors-0.6.2" |
|
2679 | sources."colors-0.6.2" | |
@@ -2150,7 +2713,7 b' let' | |||||
2150 | sources."lru-cache-2.7.3" |
|
2713 | sources."lru-cache-2.7.3" | |
2151 | sources."sigmund-1.0.1" |
|
2714 | sources."sigmund-1.0.1" | |
2152 | sources."graceful-fs-1.2.3" |
|
2715 | sources."graceful-fs-1.2.3" | |
2153 |
sources."abbrev-1.0 |
|
2716 | sources."abbrev-1.1.0" | |
2154 | (sources."argparse-0.1.16" // { |
|
2717 | (sources."argparse-0.1.16" // { | |
2155 | dependencies = [ |
|
2718 | dependencies = [ | |
2156 | sources."underscore.string-2.4.0" |
|
2719 | sources."underscore.string-2.4.0" | |
@@ -2171,31 +2734,90 b' let' | |||||
2171 | sources."has-ansi-2.0.0" |
|
2734 | sources."has-ansi-2.0.0" | |
2172 | sources."strip-ansi-3.0.1" |
|
2735 | sources."strip-ansi-3.0.1" | |
2173 | sources."supports-color-2.0.0" |
|
2736 | sources."supports-color-2.0.0" | |
2174 |
sources."ansi-regex-2. |
|
2737 | sources."ansi-regex-2.1.1" | |
2175 | sources."source-map-0.3.0" |
|
2738 | sources."source-map-0.3.0" | |
2176 |
sources."amdefine-1.0. |
|
2739 | sources."amdefine-1.0.1" | |
2177 |
(sources."less-2.7. |
|
2740 | (sources."less-2.7.2" // { | |
2178 | dependencies = [ |
|
2741 | dependencies = [ | |
2179 |
sources."graceful-fs-4.1. |
|
2742 | sources."graceful-fs-4.1.11" | |
2180 |
sources."source-map-0.5. |
|
2743 | sources."source-map-0.5.7" | |
2181 | ]; |
|
2744 | ]; | |
2182 | }) |
|
2745 | }) | |
2183 | sources."errno-0.1.4" |
|
2746 | sources."errno-0.1.4" | |
2184 |
sources."image-size-0.5. |
|
2747 | sources."image-size-0.5.5" | |
2185 |
sources."mime-1. |
|
2748 | sources."mime-1.4.0" | |
2186 | sources."mkdirp-0.5.1" |
|
2749 | sources."mkdirp-0.5.1" | |
2187 |
sources."promise-7. |
|
2750 | sources."promise-7.3.1" | |
|
2751 | sources."request-2.82.0" | |||
2188 | sources."prr-0.0.0" |
|
2752 | sources."prr-0.0.0" | |
2189 | sources."minimist-0.0.8" |
|
2753 | sources."minimist-0.0.8" | |
2190 |
sources."asap-2.0. |
|
2754 | sources."asap-2.0.6" | |
|
2755 | sources."aws-sign2-0.7.0" | |||
|
2756 | sources."aws4-1.6.0" | |||
|
2757 | sources."caseless-0.12.0" | |||
|
2758 | sources."combined-stream-1.0.5" | |||
|
2759 | sources."extend-3.0.1" | |||
|
2760 | sources."forever-agent-0.6.1" | |||
|
2761 | sources."form-data-2.3.1" | |||
|
2762 | sources."har-validator-5.0.3" | |||
|
2763 | sources."hawk-6.0.2" | |||
|
2764 | sources."http-signature-1.2.0" | |||
|
2765 | sources."is-typedarray-1.0.0" | |||
|
2766 | sources."isstream-0.1.2" | |||
|
2767 | sources."json-stringify-safe-5.0.1" | |||
|
2768 | sources."mime-types-2.1.17" | |||
|
2769 | sources."oauth-sign-0.8.2" | |||
|
2770 | sources."performance-now-2.1.0" | |||
|
2771 | sources."qs-6.5.1" | |||
|
2772 | sources."safe-buffer-5.1.1" | |||
|
2773 | sources."stringstream-0.0.5" | |||
|
2774 | sources."tough-cookie-2.3.3" | |||
|
2775 | sources."tunnel-agent-0.6.0" | |||
|
2776 | sources."uuid-3.1.0" | |||
|
2777 | sources."delayed-stream-1.0.0" | |||
|
2778 | sources."asynckit-0.4.0" | |||
|
2779 | sources."ajv-5.2.2" | |||
|
2780 | sources."har-schema-2.0.0" | |||
|
2781 | sources."co-4.6.0" | |||
|
2782 | sources."fast-deep-equal-1.0.0" | |||
|
2783 | sources."json-schema-traverse-0.3.1" | |||
|
2784 | sources."json-stable-stringify-1.0.1" | |||
|
2785 | sources."jsonify-0.0.0" | |||
|
2786 | sources."hoek-4.2.0" | |||
|
2787 | sources."boom-4.3.1" | |||
|
2788 | (sources."cryptiles-3.1.2" // { | |||
|
2789 | dependencies = [ | |||
|
2790 | sources."boom-5.2.0" | |||
|
2791 | ]; | |||
|
2792 | }) | |||
|
2793 | sources."sntp-2.0.2" | |||
|
2794 | sources."assert-plus-1.0.0" | |||
|
2795 | sources."jsprim-1.4.1" | |||
|
2796 | sources."sshpk-1.13.1" | |||
|
2797 | sources."extsprintf-1.3.0" | |||
|
2798 | sources."json-schema-0.2.3" | |||
|
2799 | sources."verror-1.10.0" | |||
|
2800 | sources."core-util-is-1.0.2" | |||
|
2801 | sources."asn1-0.2.3" | |||
|
2802 | sources."dashdash-1.14.1" | |||
|
2803 | sources."getpass-0.1.7" | |||
|
2804 | sources."jsbn-0.1.1" | |||
|
2805 | sources."tweetnacl-0.14.5" | |||
|
2806 | sources."ecc-jsbn-0.1.1" | |||
|
2807 | sources."bcrypt-pbkdf-1.0.1" | |||
|
2808 | sources."mime-db-1.30.0" | |||
|
2809 | sources."punycode-1.4.1" | |||
2191 | sources."gaze-0.5.2" |
|
2810 | sources."gaze-0.5.2" | |
2192 | sources."tiny-lr-fork-0.0.5" |
|
2811 | (sources."tiny-lr-fork-0.0.5" // { | |
|
2812 | dependencies = [ | |||
|
2813 | sources."qs-0.5.6" | |||
|
2814 | ]; | |||
|
2815 | }) | |||
2193 | (sources."globule-0.1.0" // { |
|
2816 | (sources."globule-0.1.0" // { | |
2194 | dependencies = [ |
|
2817 | dependencies = [ | |
2195 | sources."lodash-1.0.2" |
|
2818 | sources."lodash-1.0.2" | |
2196 | ]; |
|
2819 | ]; | |
2197 | }) |
|
2820 | }) | |
2198 | sources."qs-0.5.6" |
|
|||
2199 | sources."faye-websocket-0.4.4" |
|
2821 | sources."faye-websocket-0.4.4" | |
2200 | (sources."noptify-0.0.3" // { |
|
2822 | (sources."noptify-0.0.3" // { | |
2201 | dependencies = [ |
|
2823 | dependencies = [ | |
@@ -2203,62 +2825,60 b' let' | |||||
2203 | ]; |
|
2825 | ]; | |
2204 | }) |
|
2826 | }) | |
2205 | sources."debug-0.7.4" |
|
2827 | sources."debug-0.7.4" | |
2206 |
sources."command-line-args- |
|
2828 | sources."command-line-args-3.0.5" | |
|
2829 | sources."command-line-usage-3.0.8" | |||
2207 | sources."dom5-1.3.6" |
|
2830 | sources."dom5-1.3.6" | |
2208 |
sources."array-back-1.0. |
|
2831 | sources."array-back-1.0.4" | |
2209 | sources."command-line-usage-2.0.5" |
|
|||
2210 | sources."core-js-2.4.1" |
|
|||
2211 | sources."feature-detect-es6-1.3.1" |
|
2832 | sources."feature-detect-es6-1.3.1" | |
2212 |
|
|
2833 | sources."find-replace-1.0.3" | |
2213 | dependencies = [ |
|
2834 | sources."typical-2.6.1" | |
2214 |
|
|
2835 | sources."test-value-2.1.0" | |
2215 | ]; |
|
2836 | sources."ansi-escape-sequences-3.0.0" | |
2216 | }) |
|
2837 | sources."table-layout-0.3.0" | |
2217 |
sources." |
|
2838 | sources."core-js-2.5.1" | |
2218 |
sources." |
|
2839 | sources."deep-extend-0.4.2" | |
2219 |
sources." |
|
2840 | sources."wordwrapjs-2.0.0" | |
2220 |
sources." |
|
2841 | sources."reduce-flatten-1.0.1" | |
2221 | sources."collect-all-0.2.1" |
|
|||
2222 | sources."stream-connect-1.0.2" |
|
|||
2223 | sources."stream-via-0.1.1" |
|
|||
2224 | (sources."collect-json-1.0.8" // { |
|
|||
2225 | dependencies = [ |
|
|||
2226 | sources."collect-all-1.0.2" |
|
|||
2227 | sources."stream-via-1.0.3" |
|
|||
2228 | ]; |
|
|||
2229 | }) |
|
|||
2230 | sources."deep-extend-0.4.1" |
|
|||
2231 | sources."object-tools-2.0.6" |
|
|||
2232 | sources."object-get-2.1.0" |
|
|||
2233 | sources."test-value-1.1.0" |
|
|||
2234 | sources."@types/clone-0.1.30" |
|
2842 | sources."@types/clone-0.1.30" | |
2235 |
sources."@types/node-4. |
|
2843 | sources."@types/node-4.2.20" | |
2236 | (sources."@types/parse5-0.0.31" // { |
|
2844 | (sources."@types/parse5-0.0.31" // { | |
2237 | dependencies = [ |
|
2845 | dependencies = [ | |
2238 |
sources."@types/node-6.0. |
|
2846 | sources."@types/node-6.0.88" | |
2239 | ]; |
|
2847 | ]; | |
2240 | }) |
|
2848 | }) | |
2241 | sources."clone-1.0.2" |
|
2849 | sources."clone-1.0.2" | |
2242 | sources."parse5-1.5.1" |
|
2850 | sources."parse5-1.5.1" | |
2243 | sources."es6-promise-2.3.0" |
|
2851 | sources."es6-promise-2.3.0" | |
2244 |
sources."hydrolysis-1.2 |
|
2852 | (sources."hydrolysis-1.25.0" // { | |
2245 | sources."path-posix-1.0.0" |
|
|||
2246 | sources."update-notifier-0.6.3" |
|
|||
2247 | sources."babel-polyfill-6.13.0" |
|
|||
2248 | sources."doctrine-0.7.2" |
|
|||
2249 | (sources."escodegen-1.8.1" // { |
|
|||
2250 | dependencies = [ |
|
2853 | dependencies = [ | |
2251 |
sources." |
|
2854 | sources."dom5-1.1.0" | |
2252 | sources."esutils-2.0.2" |
|
|||
2253 | sources."esprima-2.7.3" |
|
|||
2254 | sources."source-map-0.2.0" |
|
|||
2255 | ]; |
|
2855 | ]; | |
2256 | }) |
|
2856 | }) | |
2257 |
sources." |
|
2857 | sources."path-posix-1.0.0" | |
|
2858 | sources."acorn-3.3.0" | |||
|
2859 | sources."babel-polyfill-6.26.0" | |||
|
2860 | sources."doctrine-0.7.2" | |||
|
2861 | (sources."escodegen-1.9.0" // { | |||
|
2862 | dependencies = [ | |||
|
2863 | sources."estraverse-4.2.0" | |||
|
2864 | sources."esutils-2.0.2" | |||
|
2865 | sources."esprima-3.1.3" | |||
|
2866 | sources."source-map-0.5.7" | |||
|
2867 | ]; | |||
|
2868 | }) | |||
|
2869 | (sources."espree-3.5.1" // { | |||
|
2870 | dependencies = [ | |||
|
2871 | sources."acorn-5.1.2" | |||
|
2872 | ]; | |||
|
2873 | }) | |||
2258 | sources."estraverse-3.1.0" |
|
2874 | sources."estraverse-3.1.0" | |
2259 |
sources."path-is-absolute-1.0. |
|
2875 | sources."path-is-absolute-1.0.1" | |
2260 |
sources."babel-runtime-6. |
|
2876 | (sources."babel-runtime-6.26.0" // { | |
2261 | sources."regenerator-runtime-0.9.5" |
|
2877 | dependencies = [ | |
|
2878 | sources."regenerator-runtime-0.11.0" | |||
|
2879 | ]; | |||
|
2880 | }) | |||
|
2881 | sources."regenerator-runtime-0.10.5" | |||
2262 | sources."esutils-1.1.6" |
|
2882 | sources."esutils-1.1.6" | |
2263 | sources."isarray-0.0.1" |
|
2883 | sources."isarray-0.0.1" | |
2264 | sources."optionator-0.8.2" |
|
2884 | sources."optionator-0.8.2" | |
@@ -2267,105 +2887,112 b' let' | |||||
2267 | sources."wordwrap-1.0.0" |
|
2887 | sources."wordwrap-1.0.0" | |
2268 | sources."type-check-0.3.2" |
|
2888 | sources."type-check-0.3.2" | |
2269 | sources."levn-0.3.0" |
|
2889 | sources."levn-0.3.0" | |
2270 |
sources."fast-levenshtein-2.0. |
|
2890 | sources."fast-levenshtein-2.0.6" | |
2271 |
sources."acorn- |
|
2891 | sources."acorn-jsx-3.0.1" | |
2272 |
|
|
2892 | sources."object-assign-4.1.1" | |
|
2893 | sources."optparse-1.0.5" | |||
|
2894 | sources."semver-5.4.1" | |||
|
2895 | (sources."npm-registry-client-8.4.0" // { | |||
2273 | dependencies = [ |
|
2896 | dependencies = [ | |
2274 |
sources."ac |
|
2897 | sources."graceful-fs-4.1.11" | |
2275 | ]; |
|
2898 | ]; | |
2276 | }) |
|
2899 | }) | |
2277 |
sources." |
|
2900 | (sources."npmconf-2.1.2" // { | |
2278 | (sources."configstore-2.1.0" // { |
|
|||
2279 | dependencies = [ |
|
2901 | dependencies = [ | |
2280 |
sources." |
|
2902 | sources."nopt-3.0.6" | |
|
2903 | sources."once-1.3.3" | |||
|
2904 | sources."semver-4.3.6" | |||
2281 | ]; |
|
2905 | ]; | |
2282 | }) |
|
2906 | }) | |
2283 |
sources." |
|
2907 | sources."tar-3.1.15" | |
2284 |
sources." |
|
2908 | sources."temp-0.8.3" | |
2285 |
sources."se |
|
2909 | (sources."fs.extra-1.3.2" // { | |
2286 | sources."filled-array-1.1.0" |
|
|||
2287 | sources."object-assign-4.1.0" |
|
|||
2288 | sources."repeating-2.0.1" |
|
|||
2289 | sources."string-width-1.0.2" |
|
|||
2290 | sources."widest-line-1.0.0" |
|
|||
2291 | sources."is-finite-1.0.1" |
|
|||
2292 | sources."number-is-nan-1.0.0" |
|
|||
2293 | sources."code-point-at-1.0.0" |
|
|||
2294 | sources."is-fullwidth-code-point-1.0.0" |
|
|||
2295 | sources."dot-prop-3.0.0" |
|
|||
2296 | sources."os-tmpdir-1.0.1" |
|
|||
2297 | sources."osenv-0.1.3" |
|
|||
2298 | sources."uuid-2.0.3" |
|
|||
2299 | (sources."write-file-atomic-1.2.0" // { |
|
|||
2300 | dependencies = [ |
|
2910 | dependencies = [ | |
2301 |
sources." |
|
2911 | sources."mkdirp-0.3.5" | |
2302 | ]; |
|
2912 | ]; | |
2303 | }) |
|
2913 | }) | |
2304 |
sources." |
|
2914 | sources."findit-2.0.0" | |
2305 |
sources." |
|
2915 | sources."base64-js-1.2.1" | |
2306 |
sources." |
|
2916 | sources."slasp-0.0.4" | |
2307 |
sources."i |
|
2917 | sources."nijs-0.0.23" | |
|
2918 | sources."concat-stream-1.6.0" | |||
|
2919 | sources."normalize-package-data-2.4.0" | |||
|
2920 | sources."npm-package-arg-5.1.2" | |||
|
2921 | sources."once-1.4.0" | |||
|
2922 | sources."retry-0.10.1" | |||
2308 | sources."slide-1.1.6" |
|
2923 | sources."slide-1.1.6" | |
2309 |
sources." |
|
2924 | sources."ssri-4.1.6" | |
2310 |
sources."g |
|
2925 | sources."npmlog-4.1.2" | |
2311 |
sources."r |
|
2926 | sources."typedarray-0.0.6" | |
2312 |
sources."re |
|
2927 | (sources."readable-stream-2.3.3" // { | |
2313 | sources."semver-5.3.0" |
|
|||
2314 | sources."create-error-class-3.0.2" |
|
|||
2315 | sources."duplexer2-0.1.4" |
|
|||
2316 | sources."is-plain-obj-1.1.0" |
|
|||
2317 | sources."is-redirect-1.0.0" |
|
|||
2318 | sources."is-retry-allowed-1.1.0" |
|
|||
2319 | sources."is-stream-1.1.0" |
|
|||
2320 | sources."lowercase-keys-1.0.0" |
|
|||
2321 | sources."node-status-codes-1.0.0" |
|
|||
2322 | sources."parse-json-2.2.0" |
|
|||
2323 | sources."pinkie-promise-2.0.1" |
|
|||
2324 | sources."read-all-stream-3.1.0" |
|
|||
2325 | (sources."readable-stream-2.1.5" // { |
|
|||
2326 | dependencies = [ |
|
2928 | dependencies = [ | |
2327 | sources."isarray-1.0.0" |
|
2929 | sources."isarray-1.0.0" | |
2328 | ]; |
|
2930 | ]; | |
2329 | }) |
|
2931 | }) | |
2330 | sources."timed-out-2.0.0" |
|
|||
2331 | sources."unzip-response-1.0.1" |
|
|||
2332 | sources."url-parse-lax-1.0.0" |
|
|||
2333 | sources."capture-stack-trace-1.0.0" |
|
|||
2334 | sources."error-ex-1.3.0" |
|
|||
2335 | sources."is-arrayish-0.2.1" |
|
|||
2336 | sources."pinkie-2.0.4" |
|
|||
2337 | sources."buffer-shims-1.0.0" |
|
|||
2338 | sources."core-util-is-1.0.2" |
|
|||
2339 | sources."process-nextick-args-1.0.7" |
|
2932 | sources."process-nextick-args-1.0.7" | |
2340 |
sources."string_decoder- |
|
2933 | sources."string_decoder-1.0.3" | |
2341 | sources."util-deprecate-1.0.2" |
|
2934 | sources."util-deprecate-1.0.2" | |
2342 |
sources." |
|
2935 | sources."hosted-git-info-2.5.0" | |
2343 | (sources."rc-1.1.6" // { |
|
2936 | sources."is-builtin-module-1.0.0" | |
|
2937 | sources."validate-npm-package-license-3.0.1" | |||
|
2938 | sources."builtin-modules-1.1.1" | |||
|
2939 | sources."spdx-correct-1.0.2" | |||
|
2940 | sources."spdx-expression-parse-1.0.4" | |||
|
2941 | sources."spdx-license-ids-1.2.2" | |||
|
2942 | sources."osenv-0.1.4" | |||
|
2943 | sources."validate-npm-package-name-3.0.0" | |||
|
2944 | sources."os-homedir-1.0.2" | |||
|
2945 | sources."os-tmpdir-1.0.2" | |||
|
2946 | sources."builtins-1.0.3" | |||
|
2947 | sources."wrappy-1.0.2" | |||
|
2948 | sources."are-we-there-yet-1.1.4" | |||
|
2949 | sources."console-control-strings-1.1.0" | |||
|
2950 | sources."gauge-2.7.4" | |||
|
2951 | sources."set-blocking-2.0.0" | |||
|
2952 | sources."delegates-1.0.0" | |||
|
2953 | sources."aproba-1.2.0" | |||
|
2954 | sources."has-unicode-2.0.1" | |||
|
2955 | sources."signal-exit-3.0.2" | |||
|
2956 | sources."string-width-1.0.2" | |||
|
2957 | sources."wide-align-1.1.2" | |||
|
2958 | sources."code-point-at-1.1.0" | |||
|
2959 | sources."is-fullwidth-code-point-1.0.0" | |||
|
2960 | sources."number-is-nan-1.0.1" | |||
|
2961 | sources."config-chain-1.1.11" | |||
|
2962 | sources."ini-1.3.4" | |||
|
2963 | sources."uid-number-0.0.5" | |||
|
2964 | sources."proto-list-1.2.4" | |||
|
2965 | sources."minipass-2.2.1" | |||
|
2966 | sources."minizlib-1.0.3" | |||
|
2967 | sources."yallist-3.0.2" | |||
|
2968 | (sources."fs-extra-0.6.4" // { | |||
2344 | dependencies = [ |
|
2969 | dependencies = [ | |
2345 |
sources."mi |
|
2970 | sources."mkdirp-0.3.5" | |
2346 | ]; |
|
2971 | ]; | |
2347 | }) |
|
2972 | }) | |
2348 |
sources." |
|
2973 | sources."walk-2.3.9" | |
2349 |
sources." |
|
2974 | sources."ncp-0.4.2" | |
2350 |
|
|
2975 | sources."jsonfile-1.0.1" | |
|
2976 | sources."foreachasync-3.0.0" | |||
|
2977 | (sources."cli-1.0.1" // { | |||
2351 | dependencies = [ |
|
2978 | dependencies = [ | |
2352 |
sources."glob-7.1. |
|
2979 | sources."glob-7.1.2" | |
2353 |
sources."minimatch-3.0. |
|
2980 | sources."minimatch-3.0.4" | |
2354 | ]; |
|
2981 | ]; | |
2355 | }) |
|
2982 | }) | |
2356 | sources."console-browserify-1.1.0" |
|
2983 | sources."console-browserify-1.1.0" | |
2357 | (sources."htmlparser2-3.8.3" // { |
|
2984 | (sources."htmlparser2-3.8.3" // { | |
2358 | dependencies = [ |
|
2985 | dependencies = [ | |
2359 | sources."readable-stream-1.1.14" |
|
2986 | sources."readable-stream-1.1.14" | |
|
2987 | sources."string_decoder-0.10.31" | |||
2360 | ]; |
|
2988 | ]; | |
2361 | }) |
|
2989 | }) | |
2362 | sources."shelljs-0.3.0" |
|
2990 | sources."shelljs-0.3.0" | |
|
2991 | sources."strip-json-comments-1.0.4" | |||
2363 | sources."fs.realpath-1.0.0" |
|
2992 | sources."fs.realpath-1.0.0" | |
2364 |
sources."inflight-1.0. |
|
2993 | sources."inflight-1.0.6" | |
2365 |
sources." |
|
2994 | sources."brace-expansion-1.1.8" | |
2366 |
sources." |
|
2995 | sources."balanced-match-1.0.0" | |
2367 | sources."brace-expansion-1.1.6" |
|
|||
2368 | sources."balanced-match-0.4.2" |
|
|||
2369 | sources."concat-map-0.0.1" |
|
2996 | sources."concat-map-0.0.1" | |
2370 | sources."date-now-0.1.4" |
|
2997 | sources."date-now-0.1.4" | |
2371 | sources."domhandler-2.3.0" |
|
2998 | sources."domhandler-2.3.0" | |
@@ -2378,6 +3005,10 b' let' | |||||
2378 | sources."entities-1.1.1" |
|
3005 | sources."entities-1.1.1" | |
2379 | ]; |
|
3006 | ]; | |
2380 | }) |
|
3007 | }) | |
|
3008 | sources."good-listener-1.2.2" | |||
|
3009 | sources."select-1.1.2" | |||
|
3010 | sources."tiny-emitter-2.0.2" | |||
|
3011 | sources."delegate-3.1.3" | |||
2381 | ]; |
|
3012 | ]; | |
2382 | meta = { |
|
3013 | meta = { | |
2383 | }; |
|
3014 | }; |
@@ -16,26 +16,26 b'' | |||||
16 | }; |
|
16 | }; | |
17 | }; |
|
17 | }; | |
18 | Beaker = super.buildPythonPackage { |
|
18 | Beaker = super.buildPythonPackage { | |
19 |
name = "Beaker-1. |
|
19 | name = "Beaker-1.9.0"; | |
20 | buildInputs = with self; []; |
|
20 | buildInputs = with self; []; | |
21 | doCheck = false; |
|
21 | doCheck = false; | |
22 | propagatedBuildInputs = with self; []; |
|
22 | propagatedBuildInputs = with self; [funcsigs]; | |
23 | src = fetchurl { |
|
23 | src = fetchurl { | |
24 | url = "https://pypi.python.org/packages/97/8e/409d2e7c009b8aa803dc9e6f239f1db7c3cdf578249087a404e7c27a505d/Beaker-1.7.0.tar.gz"; |
|
24 | url = "https://pypi.python.org/packages/93/b2/12de6937b06e9615dbb3cb3a1c9af17f133f435bdef59f4ad42032b6eb49/Beaker-1.9.0.tar.gz"; | |
25 | md5 = "386be3f7fe427358881eee4622b428b3"; |
|
25 | md5 = "38b3fcdfa24faf97c6cf66991eb54e9c"; | |
26 | }; |
|
26 | }; | |
27 | meta = { |
|
27 | meta = { | |
28 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
28 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
29 | }; |
|
29 | }; | |
30 | }; |
|
30 | }; | |
31 | CProfileV = super.buildPythonPackage { |
|
31 | CProfileV = super.buildPythonPackage { | |
32 |
name = "CProfileV-1.0. |
|
32 | name = "CProfileV-1.0.7"; | |
33 | buildInputs = with self; []; |
|
33 | buildInputs = with self; []; | |
34 | doCheck = false; |
|
34 | doCheck = false; | |
35 | propagatedBuildInputs = with self; [bottle]; |
|
35 | propagatedBuildInputs = with self; [bottle]; | |
36 | src = fetchurl { |
|
36 | src = fetchurl { | |
37 |
url = "https://pypi.python.org/packages/ |
|
37 | url = "https://pypi.python.org/packages/df/50/d8c1ada7d537c64b0f76453fa31dedb6af6e27b82fcf0331e5f71a4cf98b/CProfileV-1.0.7.tar.gz"; | |
38 | md5 = "08c7c242b6e64237bc53c5d13537e03d"; |
|
38 | md5 = "db4c7640438aa3d8887e194c81c7a019"; | |
39 | }; |
|
39 | }; | |
40 | meta = { |
|
40 | meta = { | |
41 | license = [ pkgs.lib.licenses.mit ]; |
|
41 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -81,26 +81,26 b'' | |||||
81 | }; |
|
81 | }; | |
82 | }; |
|
82 | }; | |
83 | Mako = super.buildPythonPackage { |
|
83 | Mako = super.buildPythonPackage { | |
84 |
name = "Mako-1.0. |
|
84 | name = "Mako-1.0.7"; | |
85 | buildInputs = with self; []; |
|
85 | buildInputs = with self; []; | |
86 | doCheck = false; |
|
86 | doCheck = false; | |
87 | propagatedBuildInputs = with self; [MarkupSafe]; |
|
87 | propagatedBuildInputs = with self; [MarkupSafe]; | |
88 | src = fetchurl { |
|
88 | src = fetchurl { | |
89 |
url = "https://pypi.python.org/packages/ |
|
89 | url = "https://pypi.python.org/packages/eb/f3/67579bb486517c0d49547f9697e36582cd19dafb5df9e687ed8e22de57fa/Mako-1.0.7.tar.gz"; | |
90 | md5 = "a28e22a339080316b2acc352b9ee631c"; |
|
90 | md5 = "5836cc997b1b773ef389bf6629c30e65"; | |
91 | }; |
|
91 | }; | |
92 | meta = { |
|
92 | meta = { | |
93 | license = [ pkgs.lib.licenses.mit ]; |
|
93 | license = [ pkgs.lib.licenses.mit ]; | |
94 | }; |
|
94 | }; | |
95 | }; |
|
95 | }; | |
96 | Markdown = super.buildPythonPackage { |
|
96 | Markdown = super.buildPythonPackage { | |
97 |
name = "Markdown-2.6. |
|
97 | name = "Markdown-2.6.8"; | |
98 | buildInputs = with self; []; |
|
98 | buildInputs = with self; []; | |
99 | doCheck = false; |
|
99 | doCheck = false; | |
100 | propagatedBuildInputs = with self; []; |
|
100 | propagatedBuildInputs = with self; []; | |
101 | src = fetchurl { |
|
101 | src = fetchurl { | |
102 |
url = "https://pypi.python.org/packages/4 |
|
102 | url = "https://pypi.python.org/packages/1d/25/3f6d2cb31ec42ca5bd3bfbea99b63892b735d76e26f20dd2dcc34ffe4f0d/Markdown-2.6.8.tar.gz"; | |
103 | md5 = "632710a7474bbb74a82084392251061f"; |
|
103 | md5 = "d9ef057a5bd185f6f536400a31fc5d45"; | |
104 | }; |
|
104 | }; | |
105 | meta = { |
|
105 | meta = { | |
106 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
106 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
@@ -211,13 +211,13 b'' | |||||
211 | }; |
|
211 | }; | |
212 | }; |
|
212 | }; | |
213 | SQLAlchemy = super.buildPythonPackage { |
|
213 | SQLAlchemy = super.buildPythonPackage { | |
214 |
name = "SQLAlchemy- |
|
214 | name = "SQLAlchemy-1.1.11"; | |
215 | buildInputs = with self; []; |
|
215 | buildInputs = with self; []; | |
216 | doCheck = false; |
|
216 | doCheck = false; | |
217 | propagatedBuildInputs = with self; []; |
|
217 | propagatedBuildInputs = with self; []; | |
218 | src = fetchurl { |
|
218 | src = fetchurl { | |
219 | url = "https://pypi.python.org/packages/28/f7/1bbfd0d8597e8c358d5e15a166a486ad82fc5579b4e67b6ef7c05b1d182b/SQLAlchemy-0.9.9.tar.gz"; |
|
219 | url = "https://pypi.python.org/packages/59/f1/28f2205c3175e6bf32300c0f30f9d91dbc9eb910debbff3ffecb88d18528/SQLAlchemy-1.1.11.tar.gz"; | |
220 | md5 = "8a10a9bd13ed3336ef7333ac2cc679ff"; |
|
220 | md5 = "3de387eddb4012083a4562928c511e43"; | |
221 | }; |
|
221 | }; | |
222 | meta = { |
|
222 | meta = { | |
223 | license = [ pkgs.lib.licenses.mit ]; |
|
223 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -302,26 +302,26 b'' | |||||
302 | }; |
|
302 | }; | |
303 | }; |
|
303 | }; | |
304 | WebOb = super.buildPythonPackage { |
|
304 | WebOb = super.buildPythonPackage { | |
305 |
name = "WebOb-1.3 |
|
305 | name = "WebOb-1.7.3"; | |
306 | buildInputs = with self; []; |
|
306 | buildInputs = with self; []; | |
307 | doCheck = false; |
|
307 | doCheck = false; | |
308 | propagatedBuildInputs = with self; []; |
|
308 | propagatedBuildInputs = with self; []; | |
309 | src = fetchurl { |
|
309 | src = fetchurl { | |
310 |
url = "https://pypi.python.org/packages/ |
|
310 | url = "https://pypi.python.org/packages/46/87/2f96d8d43b2078fae6e1d33fa86b95c228cebed060f4e3c7576cc44ea83b/WebOb-1.7.3.tar.gz"; | |
311 | md5 = "20918251c5726956ba8fef22d1556177"; |
|
311 | md5 = "350028baffc508e3d23c078118e35316"; | |
312 | }; |
|
312 | }; | |
313 | meta = { |
|
313 | meta = { | |
314 | license = [ pkgs.lib.licenses.mit ]; |
|
314 | license = [ pkgs.lib.licenses.mit ]; | |
315 | }; |
|
315 | }; | |
316 | }; |
|
316 | }; | |
317 | WebTest = super.buildPythonPackage { |
|
317 | WebTest = super.buildPythonPackage { | |
318 |
name = "WebTest- |
|
318 | name = "WebTest-2.0.27"; | |
319 | buildInputs = with self; []; |
|
319 | buildInputs = with self; []; | |
320 | doCheck = false; |
|
320 | doCheck = false; | |
321 | propagatedBuildInputs = with self; [WebOb]; |
|
321 | propagatedBuildInputs = with self; [six WebOb waitress beautifulsoup4]; | |
322 | src = fetchurl { |
|
322 | src = fetchurl { | |
323 | url = "https://pypi.python.org/packages/51/3d/84fd0f628df10b30c7db87895f56d0158e5411206b721ca903cb51bfd948/WebTest-1.4.3.zip"; |
|
323 | url = "https://pypi.python.org/packages/80/fa/ca3a759985c72e3a124cbca3e1f8a2e931a07ffd31fd45d8f7bf21cb95cf/WebTest-2.0.27.tar.gz"; | |
324 | md5 = "631ce728bed92c681a4020a36adbc353"; |
|
324 | md5 = "54e6515ac71c51b6fc90179483c749ad"; | |
325 | }; |
|
325 | }; | |
326 | meta = { |
|
326 | meta = { | |
327 | license = [ pkgs.lib.licenses.mit ]; |
|
327 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -341,13 +341,13 b'' | |||||
341 | }; |
|
341 | }; | |
342 | }; |
|
342 | }; | |
343 | alembic = super.buildPythonPackage { |
|
343 | alembic = super.buildPythonPackage { | |
344 |
name = "alembic-0. |
|
344 | name = "alembic-0.9.2"; | |
345 | buildInputs = with self; []; |
|
345 | buildInputs = with self; []; | |
346 | doCheck = false; |
|
346 | doCheck = false; | |
347 | propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor]; |
|
347 | propagatedBuildInputs = with self; [SQLAlchemy Mako python-editor python-dateutil]; | |
348 | src = fetchurl { |
|
348 | src = fetchurl { | |
349 |
url = "https://pypi.python.org/packages/ |
|
349 | url = "https://pypi.python.org/packages/78/48/b5b26e7218b415f40b60b92c53853d242e5456c0f19f6c66101d98ff5f2a/alembic-0.9.2.tar.gz"; | |
350 | md5 = "5f95d8ee62b443f9b37eb5bee76c582d"; |
|
350 | md5 = "40daf8bae50969beea40efaaf0839ff4"; | |
351 | }; |
|
351 | }; | |
352 | meta = { |
|
352 | meta = { | |
353 | license = [ pkgs.lib.licenses.mit ]; |
|
353 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -380,16 +380,16 b'' | |||||
380 | }; |
|
380 | }; | |
381 | }; |
|
381 | }; | |
382 | appenlight-client = super.buildPythonPackage { |
|
382 | appenlight-client = super.buildPythonPackage { | |
383 |
name = "appenlight-client-0.6.1 |
|
383 | name = "appenlight-client-0.6.21"; | |
384 | buildInputs = with self; []; |
|
384 | buildInputs = with self; []; | |
385 | doCheck = false; |
|
385 | doCheck = false; | |
386 | propagatedBuildInputs = with self; [WebOb requests]; |
|
386 | propagatedBuildInputs = with self; [WebOb requests six]; | |
387 | src = fetchurl { |
|
387 | src = fetchurl { | |
388 |
url = "https://pypi.python.org/packages/ |
|
388 | url = "https://pypi.python.org/packages/c9/23/91b66cfa0b963662c10b2a06ccaadf3f3a4848a7a2aa16255cb43d5160ec/appenlight_client-0.6.21.tar.gz"; | |
389 | md5 = "578c69b09f4356d898fff1199b98a95c"; |
|
389 | md5 = "273999ac854fdaefa8d0fb61965a4ed9"; | |
390 | }; |
|
390 | }; | |
391 | meta = { |
|
391 | meta = { | |
392 |
license = [ pkgs.lib.licenses.bsdOriginal |
|
392 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
393 | }; |
|
393 | }; | |
394 | }; |
|
394 | }; | |
395 | authomatic = super.buildPythonPackage { |
|
395 | authomatic = super.buildPythonPackage { | |
@@ -405,19 +405,6 b'' | |||||
405 | license = [ pkgs.lib.licenses.mit ]; |
|
405 | license = [ pkgs.lib.licenses.mit ]; | |
406 | }; |
|
406 | }; | |
407 | }; |
|
407 | }; | |
408 | backport-ipaddress = super.buildPythonPackage { |
|
|||
409 | name = "backport-ipaddress-0.1"; |
|
|||
410 | buildInputs = with self; []; |
|
|||
411 | doCheck = false; |
|
|||
412 | propagatedBuildInputs = with self; []; |
|
|||
413 | src = fetchurl { |
|
|||
414 | url = "https://pypi.python.org/packages/d3/30/54c6dab05a4dec44db25ff309f1fbb6b7a8bde3f2bade38bb9da67bbab8f/backport_ipaddress-0.1.tar.gz"; |
|
|||
415 | md5 = "9c1f45f4361f71b124d7293a60006c05"; |
|
|||
416 | }; |
|
|||
417 | meta = { |
|
|||
418 | license = [ pkgs.lib.licenses.psfl ]; |
|
|||
419 | }; |
|
|||
420 | }; |
|
|||
421 | backports.shutil-get-terminal-size = super.buildPythonPackage { |
|
408 | backports.shutil-get-terminal-size = super.buildPythonPackage { | |
422 | name = "backports.shutil-get-terminal-size-1.0.0"; |
|
409 | name = "backports.shutil-get-terminal-size-1.0.0"; | |
423 | buildInputs = with self; []; |
|
410 | buildInputs = with self; []; | |
@@ -431,6 +418,19 b'' | |||||
431 | license = [ pkgs.lib.licenses.mit ]; |
|
418 | license = [ pkgs.lib.licenses.mit ]; | |
432 | }; |
|
419 | }; | |
433 | }; |
|
420 | }; | |
|
421 | beautifulsoup4 = super.buildPythonPackage { | |||
|
422 | name = "beautifulsoup4-4.6.0"; | |||
|
423 | buildInputs = with self; []; | |||
|
424 | doCheck = false; | |||
|
425 | propagatedBuildInputs = with self; []; | |||
|
426 | src = fetchurl { | |||
|
427 | url = "https://pypi.python.org/packages/fa/8d/1d14391fdaed5abada4e0f63543fef49b8331a34ca60c88bd521bcf7f782/beautifulsoup4-4.6.0.tar.gz"; | |||
|
428 | md5 = "c17714d0f91a23b708a592cb3c697728"; | |||
|
429 | }; | |||
|
430 | meta = { | |||
|
431 | license = [ pkgs.lib.licenses.mit ]; | |||
|
432 | }; | |||
|
433 | }; | |||
434 | bleach = super.buildPythonPackage { |
|
434 | bleach = super.buildPythonPackage { | |
435 | name = "bleach-1.5.0"; |
|
435 | name = "bleach-1.5.0"; | |
436 | buildInputs = with self; []; |
|
436 | buildInputs = with self; []; | |
@@ -510,13 +510,13 b'' | |||||
510 | }; |
|
510 | }; | |
511 | }; |
|
511 | }; | |
512 | colander = super.buildPythonPackage { |
|
512 | colander = super.buildPythonPackage { | |
513 |
name = "colander-1. |
|
513 | name = "colander-1.3.3"; | |
514 | buildInputs = with self; []; |
|
514 | buildInputs = with self; []; | |
515 | doCheck = false; |
|
515 | doCheck = false; | |
516 | propagatedBuildInputs = with self; [translationstring iso8601]; |
|
516 | propagatedBuildInputs = with self; [translationstring iso8601]; | |
517 | src = fetchurl { |
|
517 | src = fetchurl { | |
518 |
url = "https://pypi.python.org/packages/ |
|
518 | url = "https://pypi.python.org/packages/54/a9/9862a561e015b2c7b56404c0b13828a8bdc51e05ab3703bd792cec064487/colander-1.3.3.tar.gz"; | |
519 | md5 = "83db21b07936a0726e588dae1914b9ed"; |
|
519 | md5 = "f5d783768c51d73695f49bbe95778ab4"; | |
520 | }; |
|
520 | }; | |
521 | meta = { |
|
521 | meta = { | |
522 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; |
|
522 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |
@@ -614,26 +614,26 b'' | |||||
614 | }; |
|
614 | }; | |
615 | }; |
|
615 | }; | |
616 | docutils = super.buildPythonPackage { |
|
616 | docutils = super.buildPythonPackage { | |
617 |
name = "docutils-0.1 |
|
617 | name = "docutils-0.13.1"; | |
618 | buildInputs = with self; []; |
|
618 | buildInputs = with self; []; | |
619 | doCheck = false; |
|
619 | doCheck = false; | |
620 | propagatedBuildInputs = with self; []; |
|
620 | propagatedBuildInputs = with self; []; | |
621 | src = fetchurl { |
|
621 | src = fetchurl { | |
622 | url = "https://pypi.python.org/packages/37/38/ceda70135b9144d84884ae2fc5886c6baac4edea39550f28bcd144c1234d/docutils-0.12.tar.gz"; |
|
622 | url = "https://pypi.python.org/packages/05/25/7b5484aca5d46915493f1fd4ecb63c38c333bd32aa9ad6e19da8d08895ae/docutils-0.13.1.tar.gz"; | |
623 | md5 = "4622263b62c5c771c03502afa3157768"; |
|
623 | md5 = "ea4a893c633c788be9b8078b6b305d53"; | |
624 | }; |
|
624 | }; | |
625 | meta = { |
|
625 | meta = { | |
626 | 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 ]; |
|
626 | 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 ]; | |
627 | }; |
|
627 | }; | |
628 | }; |
|
628 | }; | |
629 | dogpile.cache = super.buildPythonPackage { |
|
629 | dogpile.cache = super.buildPythonPackage { | |
630 |
name = "dogpile.cache-0.6. |
|
630 | name = "dogpile.cache-0.6.4"; | |
631 | buildInputs = with self; []; |
|
631 | buildInputs = with self; []; | |
632 | doCheck = false; |
|
632 | doCheck = false; | |
633 | propagatedBuildInputs = with self; []; |
|
633 | propagatedBuildInputs = with self; []; | |
634 | src = fetchurl { |
|
634 | src = fetchurl { | |
635 |
url = "https://pypi.python.org/packages/ |
|
635 | url = "https://pypi.python.org/packages/b6/3d/35c05ca01c070bb70d9d422f2c4858ecb021b05b21af438fec5ccd7b945c/dogpile.cache-0.6.4.tar.gz"; | |
636 | md5 = "35d7fb30f22bbd0685763d894dd079a9"; |
|
636 | md5 = "66e0a6cae6c08cb1ea25f89d0eadfeb0"; | |
637 | }; |
|
637 | }; | |
638 | meta = { |
|
638 | meta = { | |
639 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
639 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
@@ -653,13 +653,13 b'' | |||||
653 | }; |
|
653 | }; | |
654 | }; |
|
654 | }; | |
655 | ecdsa = super.buildPythonPackage { |
|
655 | ecdsa = super.buildPythonPackage { | |
656 |
name = "ecdsa-0.1 |
|
656 | name = "ecdsa-0.13"; | |
657 | buildInputs = with self; []; |
|
657 | buildInputs = with self; []; | |
658 | doCheck = false; |
|
658 | doCheck = false; | |
659 | propagatedBuildInputs = with self; []; |
|
659 | propagatedBuildInputs = with self; []; | |
660 | src = fetchurl { |
|
660 | src = fetchurl { | |
661 |
url = "https://pypi.python.org/packages/ |
|
661 | url = "https://pypi.python.org/packages/f9/e5/99ebb176e47f150ac115ffeda5fedb6a3dbb3c00c74a59fd84ddf12f5857/ecdsa-0.13.tar.gz"; | |
662 | md5 = "8ef586fe4dbb156697d756900cb41d7c"; |
|
662 | md5 = "1f60eda9cb5c46722856db41a3ae6670"; | |
663 | }; |
|
663 | }; | |
664 | meta = { |
|
664 | meta = { | |
665 | license = [ pkgs.lib.licenses.mit ]; |
|
665 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -717,6 +717,19 b'' | |||||
717 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
717 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
718 | }; |
|
718 | }; | |
719 | }; |
|
719 | }; | |
|
720 | funcsigs = super.buildPythonPackage { | |||
|
721 | name = "funcsigs-1.0.2"; | |||
|
722 | buildInputs = with self; []; | |||
|
723 | doCheck = false; | |||
|
724 | propagatedBuildInputs = with self; []; | |||
|
725 | src = fetchurl { | |||
|
726 | url = "https://pypi.python.org/packages/94/4a/db842e7a0545de1cdb0439bb80e6e42dfe82aaeaadd4072f2263a4fbed23/funcsigs-1.0.2.tar.gz"; | |||
|
727 | md5 = "7e583285b1fb8a76305d6d68f4ccc14e"; | |||
|
728 | }; | |||
|
729 | meta = { | |||
|
730 | license = [ { fullName = "ASL"; } pkgs.lib.licenses.asl20 ]; | |||
|
731 | }; | |||
|
732 | }; | |||
720 | functools32 = super.buildPythonPackage { |
|
733 | functools32 = super.buildPythonPackage { | |
721 | name = "functools32-3.2.3.post2"; |
|
734 | name = "functools32-3.2.3.post2"; | |
722 | buildInputs = with self; []; |
|
735 | buildInputs = with self; []; | |
@@ -757,13 +770,13 b'' | |||||
757 | }; |
|
770 | }; | |
758 | }; |
|
771 | }; | |
759 | gevent = super.buildPythonPackage { |
|
772 | gevent = super.buildPythonPackage { | |
760 |
name = "gevent-1. |
|
773 | name = "gevent-1.2.2"; | |
761 | buildInputs = with self; []; |
|
774 | buildInputs = with self; []; | |
762 | doCheck = false; |
|
775 | doCheck = false; | |
763 | propagatedBuildInputs = with self; [greenlet]; |
|
776 | propagatedBuildInputs = with self; [greenlet]; | |
764 | src = fetchurl { |
|
777 | src = fetchurl { | |
765 | url = "https://pypi.python.org/packages/43/8f/cb3224a0e6ab663547f45c10d0651cfd52633fde4283bf68d627084df8cc/gevent-1.1.2.tar.gz"; |
|
778 | url = "https://pypi.python.org/packages/1b/92/b111f76e54d2be11375b47b213b56687214f258fd9dae703546d30b837be/gevent-1.2.2.tar.gz"; | |
766 | md5 = "bb32a2f852a4997138014d5007215c6e"; |
|
779 | md5 = "7f0baf355384fe5ff2ecf66853422554"; | |
767 | }; |
|
780 | }; | |
768 | meta = { |
|
781 | meta = { | |
769 | license = [ pkgs.lib.licenses.mit ]; |
|
782 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -796,39 +809,39 b'' | |||||
796 | }; |
|
809 | }; | |
797 | }; |
|
810 | }; | |
798 | graphviz = super.buildPythonPackage { |
|
811 | graphviz = super.buildPythonPackage { | |
799 |
name = "graphviz-0. |
|
812 | name = "graphviz-0.8"; | |
800 | buildInputs = with self; []; |
|
813 | buildInputs = with self; []; | |
801 | doCheck = false; |
|
814 | doCheck = false; | |
802 | propagatedBuildInputs = with self; []; |
|
815 | propagatedBuildInputs = with self; []; | |
803 | src = fetchurl { |
|
816 | src = fetchurl { | |
804 | url = "https://pypi.python.org/packages/7d/2d/f5cfa56467ca5a65eb44e1103d89d2f65dbc4f04cf7a1f3d38e973c3d1a8/graphviz-0.7.1.zip"; |
|
817 | url = "https://pypi.python.org/packages/da/84/0e997520323d6b01124eb01c68d5c101814d0aab53083cd62bd75a90f70b/graphviz-0.8.zip"; | |
805 | md5 = "d5926e89975121d56dec777a79bfc9d1"; |
|
818 | md5 = "9486a885360a5ee54a81eb2950470c71"; | |
806 | }; |
|
819 | }; | |
807 | meta = { |
|
820 | meta = { | |
808 | license = [ pkgs.lib.licenses.mit ]; |
|
821 | license = [ pkgs.lib.licenses.mit ]; | |
809 | }; |
|
822 | }; | |
810 | }; |
|
823 | }; | |
811 | greenlet = super.buildPythonPackage { |
|
824 | greenlet = super.buildPythonPackage { | |
812 |
name = "greenlet-0.4.1 |
|
825 | name = "greenlet-0.4.12"; | |
813 | buildInputs = with self; []; |
|
826 | buildInputs = with self; []; | |
814 | doCheck = false; |
|
827 | doCheck = false; | |
815 | propagatedBuildInputs = with self; []; |
|
828 | propagatedBuildInputs = with self; []; | |
816 | src = fetchurl { |
|
829 | src = fetchurl { | |
817 |
url = "https://pypi.python.org/packages/6 |
|
830 | url = "https://pypi.python.org/packages/be/76/82af375d98724054b7e273b5d9369346937324f9bcc20980b45b068ef0b0/greenlet-0.4.12.tar.gz"; | |
818 | md5 = "bed0c4b3b896702131f4d5c72f87c41d"; |
|
831 | md5 = "e8637647d58a26c4a1f51ca393e53c00"; | |
819 | }; |
|
832 | }; | |
820 | meta = { |
|
833 | meta = { | |
821 | license = [ pkgs.lib.licenses.mit ]; |
|
834 | license = [ pkgs.lib.licenses.mit ]; | |
822 | }; |
|
835 | }; | |
823 | }; |
|
836 | }; | |
824 | gunicorn = super.buildPythonPackage { |
|
837 | gunicorn = super.buildPythonPackage { | |
825 |
name = "gunicorn-19. |
|
838 | name = "gunicorn-19.7.1"; | |
826 | buildInputs = with self; []; |
|
839 | buildInputs = with self; []; | |
827 | doCheck = false; |
|
840 | doCheck = false; | |
828 | propagatedBuildInputs = with self; []; |
|
841 | propagatedBuildInputs = with self; []; | |
829 | src = fetchurl { |
|
842 | src = fetchurl { | |
830 |
url = "https://pypi.python.org/packages/ |
|
843 | url = "https://pypi.python.org/packages/30/3a/10bb213cede0cc4d13ac2263316c872a64bf4c819000c8ccd801f1d5f822/gunicorn-19.7.1.tar.gz"; | |
831 | md5 = "338e5e8a83ea0f0625f768dba4597530"; |
|
844 | md5 = "174d3c3cd670a5be0404d84c484e590c"; | |
832 | }; |
|
845 | }; | |
833 | meta = { |
|
846 | meta = { | |
834 | license = [ pkgs.lib.licenses.mit ]; |
|
847 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -847,6 +860,19 b'' | |||||
847 | license = [ pkgs.lib.licenses.mit ]; |
|
860 | license = [ pkgs.lib.licenses.mit ]; | |
848 | }; |
|
861 | }; | |
849 | }; |
|
862 | }; | |
|
863 | hupper = super.buildPythonPackage { | |||
|
864 | name = "hupper-1.0"; | |||
|
865 | buildInputs = with self; []; | |||
|
866 | doCheck = false; | |||
|
867 | propagatedBuildInputs = with self; []; | |||
|
868 | src = fetchurl { | |||
|
869 | url = "https://pypi.python.org/packages/2e/07/df892c564dc09bb3cf6f6deb976c26adf9117db75ba218cb4353dbc9d826/hupper-1.0.tar.gz"; | |||
|
870 | md5 = "26e77da7d5ac5858f59af050d1a6eb5a"; | |||
|
871 | }; | |||
|
872 | meta = { | |||
|
873 | license = [ pkgs.lib.licenses.mit ]; | |||
|
874 | }; | |||
|
875 | }; | |||
850 | infrae.cache = super.buildPythonPackage { |
|
876 | infrae.cache = super.buildPythonPackage { | |
851 | name = "infrae.cache-1.0.1"; |
|
877 | name = "infrae.cache-1.0.1"; | |
852 | buildInputs = with self; []; |
|
878 | buildInputs = with self; []; | |
@@ -873,14 +899,27 b'' | |||||
873 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
899 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
874 | }; |
|
900 | }; | |
875 | }; |
|
901 | }; | |
876 |
ip |
|
902 | ipaddress = super.buildPythonPackage { | |
877 |
name = "ipd |
|
903 | name = "ipaddress-1.0.18"; | |
878 | buildInputs = with self; []; |
|
904 | buildInputs = with self; []; | |
879 | doCheck = false; |
|
905 | doCheck = false; | |
880 |
propagatedBuildInputs = with self; [ |
|
906 | propagatedBuildInputs = with self; []; | |
881 | src = fetchurl { |
|
907 | src = fetchurl { | |
882 |
url = "https://pypi.python.org/packages/eb |
|
908 | url = "https://pypi.python.org/packages/4e/13/774faf38b445d0b3a844b65747175b2e0500164b7c28d78e34987a5bfe06/ipaddress-1.0.18.tar.gz"; | |
883 | md5 = "4aeab65f633ddc98ebdb5eebf08dc713"; |
|
909 | md5 = "310c2dfd64eb6f0df44aa8c59f2334a7"; | |
|
910 | }; | |||
|
911 | meta = { | |||
|
912 | license = [ pkgs.lib.licenses.psfl ]; | |||
|
913 | }; | |||
|
914 | }; | |||
|
915 | ipdb = super.buildPythonPackage { | |||
|
916 | name = "ipdb-0.10.3"; | |||
|
917 | buildInputs = with self; []; | |||
|
918 | doCheck = false; | |||
|
919 | propagatedBuildInputs = with self; [setuptools ipython]; | |||
|
920 | src = fetchurl { | |||
|
921 | url = "https://pypi.python.org/packages/ad/cc/0e7298e1fbf2efd52667c9354a12aa69fb6f796ce230cca03525051718ef/ipdb-0.10.3.tar.gz"; | |||
|
922 | md5 = "def1f6ac075d54bdee07e6501263d4fa"; | |||
884 | }; |
|
923 | }; | |
885 | meta = { |
|
924 | meta = { | |
886 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
925 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
@@ -1121,39 +1160,26 b'' | |||||
1121 | }; |
|
1160 | }; | |
1122 | }; |
|
1161 | }; | |
1123 | pandocfilters = super.buildPythonPackage { |
|
1162 | pandocfilters = super.buildPythonPackage { | |
1124 |
name = "pandocfilters-1.4. |
|
1163 | name = "pandocfilters-1.4.2"; | |
1125 | buildInputs = with self; []; |
|
1164 | buildInputs = with self; []; | |
1126 | doCheck = false; |
|
1165 | doCheck = false; | |
1127 | propagatedBuildInputs = with self; []; |
|
1166 | propagatedBuildInputs = with self; []; | |
1128 | src = fetchurl { |
|
1167 | src = fetchurl { | |
1129 |
url = "https://pypi.python.org/packages/e |
|
1168 | url = "https://pypi.python.org/packages/4c/ea/236e2584af67bb6df960832731a6e5325fd4441de001767da328c33368ce/pandocfilters-1.4.2.tar.gz"; | |
1130 | md5 = "7680d9f9ec07397dd17f380ee3818b9d"; |
|
1169 | md5 = "dc391791ef54c7de1572d7b46b63361f"; | |
1131 | }; |
|
1170 | }; | |
1132 | meta = { |
|
1171 | meta = { | |
1133 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
1172 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
1134 | }; |
|
1173 | }; | |
1135 | }; |
|
1174 | }; | |
1136 |
pa |
|
1175 | pathlib2 = super.buildPythonPackage { | |
1137 |
name = "pa |
|
1176 | name = "pathlib2-2.3.0"; | |
1138 | buildInputs = with self; []; |
|
1177 | buildInputs = with self; []; | |
1139 | doCheck = false; |
|
1178 | doCheck = false; | |
1140 |
propagatedBuildInputs = with self; [ |
|
1179 | propagatedBuildInputs = with self; [six scandir]; | |
1141 | src = fetchurl { |
|
1180 | src = fetchurl { | |
1142 | url = "https://pypi.python.org/packages/04/2b/a22d2a560c1951abbbf95a0628e245945565f70dc082d9e784666887222c/paramiko-1.15.1.tar.gz"; |
|
1181 | url = "https://pypi.python.org/packages/a1/14/df0deb867c2733f7d857523c10942b3d6612a1b222502fdffa9439943dfb/pathlib2-2.3.0.tar.gz"; | |
1143 | md5 = "48c274c3f9b1282932567b21f6acf3b5"; |
|
1182 | md5 = "89c90409d11fd5947966b6a30a47d18c"; | |
1144 | }; |
|
|||
1145 | meta = { |
|
|||
1146 | license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ]; |
|
|||
1147 | }; |
|
|||
1148 | }; |
|
|||
1149 | pathlib2 = super.buildPythonPackage { |
|
|||
1150 | name = "pathlib2-2.1.0"; |
|
|||
1151 | buildInputs = with self; []; |
|
|||
1152 | doCheck = false; |
|
|||
1153 | propagatedBuildInputs = with self; [six]; |
|
|||
1154 | src = fetchurl { |
|
|||
1155 | url = "https://pypi.python.org/packages/c9/27/8448b10d8440c08efeff0794adf7d0ed27adb98372c70c7b38f3947d4749/pathlib2-2.1.0.tar.gz"; |
|
|||
1156 | md5 = "38e4f58b4d69dfcb9edb49a54a8b28d2"; |
|
|||
1157 | }; |
|
1183 | }; | |
1158 | meta = { |
|
1184 | meta = { | |
1159 | license = [ pkgs.lib.licenses.mit ]; |
|
1185 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -1198,14 +1224,40 b'' | |||||
1198 | license = [ pkgs.lib.licenses.mit ]; |
|
1224 | license = [ pkgs.lib.licenses.mit ]; | |
1199 | }; |
|
1225 | }; | |
1200 | }; |
|
1226 | }; | |
|
1227 | plaster = super.buildPythonPackage { | |||
|
1228 | name = "plaster-0.5"; | |||
|
1229 | buildInputs = with self; []; | |||
|
1230 | doCheck = false; | |||
|
1231 | propagatedBuildInputs = with self; [setuptools]; | |||
|
1232 | src = fetchurl { | |||
|
1233 | url = "https://pypi.python.org/packages/99/b3/d7ca1fe31d2b56dba68a238721fda6820770f9c2a3de17a582d4b5b2edcc/plaster-0.5.tar.gz"; | |||
|
1234 | md5 = "c59345a67a860cfcaa1bd6a81451399d"; | |||
|
1235 | }; | |||
|
1236 | meta = { | |||
|
1237 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1238 | }; | |||
|
1239 | }; | |||
|
1240 | plaster-pastedeploy = super.buildPythonPackage { | |||
|
1241 | name = "plaster-pastedeploy-0.4.1"; | |||
|
1242 | buildInputs = with self; []; | |||
|
1243 | doCheck = false; | |||
|
1244 | propagatedBuildInputs = with self; [PasteDeploy plaster]; | |||
|
1245 | src = fetchurl { | |||
|
1246 | url = "https://pypi.python.org/packages/9d/6e/f8be01ed41c94e6c54ac97cf2eb142a702aae0c8cce31c846f785e525b40/plaster_pastedeploy-0.4.1.tar.gz"; | |||
|
1247 | md5 = "f48d5344b922e56c4978eebf1cd2e0d3"; | |||
|
1248 | }; | |||
|
1249 | meta = { | |||
|
1250 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1251 | }; | |||
|
1252 | }; | |||
1201 | prompt-toolkit = super.buildPythonPackage { |
|
1253 | prompt-toolkit = super.buildPythonPackage { | |
1202 |
name = "prompt-toolkit-1.0.1 |
|
1254 | name = "prompt-toolkit-1.0.15"; | |
1203 | buildInputs = with self; []; |
|
1255 | buildInputs = with self; []; | |
1204 | doCheck = false; |
|
1256 | doCheck = false; | |
1205 | propagatedBuildInputs = with self; [six wcwidth]; |
|
1257 | propagatedBuildInputs = with self; [six wcwidth]; | |
1206 | src = fetchurl { |
|
1258 | src = fetchurl { | |
1207 |
url = "https://pypi.python.org/packages/55 |
|
1259 | url = "https://pypi.python.org/packages/8a/ad/cf6b128866e78ad6d7f1dc5b7f99885fb813393d9860778b2984582e81b5/prompt_toolkit-1.0.15.tar.gz"; | |
1208 | md5 = "f24061ae133ed32c6b764e92bd48c496"; |
|
1260 | md5 = "8fe70295006dbc8afedd43e5eba99032"; | |
1209 | }; |
|
1261 | }; | |
1210 | meta = { |
|
1262 | meta = { | |
1211 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
1263 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
@@ -1225,39 +1277,39 b'' | |||||
1225 | }; |
|
1277 | }; | |
1226 | }; |
|
1278 | }; | |
1227 | psycopg2 = super.buildPythonPackage { |
|
1279 | psycopg2 = super.buildPythonPackage { | |
1228 |
name = "psycopg2-2. |
|
1280 | name = "psycopg2-2.7.1"; | |
1229 | buildInputs = with self; []; |
|
1281 | buildInputs = with self; []; | |
1230 | doCheck = false; |
|
1282 | doCheck = false; | |
1231 | propagatedBuildInputs = with self; []; |
|
1283 | propagatedBuildInputs = with self; []; | |
1232 | src = fetchurl { |
|
1284 | src = fetchurl { | |
1233 |
url = "https://pypi.python.org/packages/86 |
|
1285 | url = "https://pypi.python.org/packages/f8/e9/5793369ce8a41bf5467623ded8d59a434dfef9c136351aca4e70c2657ba0/psycopg2-2.7.1.tar.gz"; | |
1234 | md5 = "842b44f8c95517ed5b792081a2370da1"; |
|
1286 | md5 = "67848ac33af88336046802f6ef7081f3"; | |
1235 | }; |
|
1287 | }; | |
1236 | meta = { |
|
1288 | meta = { | |
1237 | license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ]; |
|
1289 | license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ]; | |
1238 | }; |
|
1290 | }; | |
1239 | }; |
|
1291 | }; | |
1240 | ptyprocess = super.buildPythonPackage { |
|
1292 | ptyprocess = super.buildPythonPackage { | |
1241 |
name = "ptyprocess-0.5. |
|
1293 | name = "ptyprocess-0.5.2"; | |
1242 | buildInputs = with self; []; |
|
1294 | buildInputs = with self; []; | |
1243 | doCheck = false; |
|
1295 | doCheck = false; | |
1244 | propagatedBuildInputs = with self; []; |
|
1296 | propagatedBuildInputs = with self; []; | |
1245 | src = fetchurl { |
|
1297 | src = fetchurl { | |
1246 |
url = "https://pypi.python.org/packages/d |
|
1298 | url = "https://pypi.python.org/packages/51/83/5d07dc35534640b06f9d9f1a1d2bc2513fb9cc7595a1b0e28ae5477056ce/ptyprocess-0.5.2.tar.gz"; | |
1247 | md5 = "94e537122914cc9ec9c1eadcd36e73a1"; |
|
1299 | md5 = "d3b8febae1b8c53b054bd818d0bb8665"; | |
1248 | }; |
|
1300 | }; | |
1249 | meta = { |
|
1301 | meta = { | |
1250 | license = [ ]; |
|
1302 | license = [ ]; | |
1251 | }; |
|
1303 | }; | |
1252 | }; |
|
1304 | }; | |
1253 | py = super.buildPythonPackage { |
|
1305 | py = super.buildPythonPackage { | |
1254 |
name = "py-1.4.3 |
|
1306 | name = "py-1.4.34"; | |
1255 | buildInputs = with self; []; |
|
1307 | buildInputs = with self; []; | |
1256 | doCheck = false; |
|
1308 | doCheck = false; | |
1257 | propagatedBuildInputs = with self; []; |
|
1309 | propagatedBuildInputs = with self; []; | |
1258 | src = fetchurl { |
|
1310 | src = fetchurl { | |
1259 |
url = "https://pypi.python.org/packages/ |
|
1311 | url = "https://pypi.python.org/packages/68/35/58572278f1c097b403879c1e9369069633d1cbad5239b9057944bb764782/py-1.4.34.tar.gz"; | |
1260 | md5 = "5d2c63c56dc3f2115ec35c066ecd582b"; |
|
1312 | md5 = "d9c3d8f734b0819ff48e355d77bf1730"; | |
1261 | }; |
|
1313 | }; | |
1262 | meta = { |
|
1314 | meta = { | |
1263 | license = [ pkgs.lib.licenses.mit ]; |
|
1315 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -1355,13 +1407,13 b'' | |||||
1355 | }; |
|
1407 | }; | |
1356 | }; |
|
1408 | }; | |
1357 | pyramid = super.buildPythonPackage { |
|
1409 | pyramid = super.buildPythonPackage { | |
1358 |
name = "pyramid-1. |
|
1410 | name = "pyramid-1.9.1"; | |
1359 | buildInputs = with self; []; |
|
1411 | buildInputs = with self; []; | |
1360 | doCheck = false; |
|
1412 | doCheck = false; | |
1361 | propagatedBuildInputs = with self; [setuptools WebOb repoze.lru zope.interface zope.deprecation venusian translationstring PasteDeploy]; |
|
1413 | propagatedBuildInputs = with self; [setuptools WebOb repoze.lru zope.interface zope.deprecation venusian translationstring PasteDeploy plaster plaster-pastedeploy hupper]; | |
1362 | src = fetchurl { |
|
1414 | src = fetchurl { | |
1363 | url = "https://pypi.python.org/packages/33/91/55f5c661f8923902cd1f68d75f2b937c45e7682857356cf18f0be5493899/pyramid-1.7.4.tar.gz"; |
|
1415 | url = "https://pypi.python.org/packages/9a/57/73447be9e7d0512d601e3f0a1fb9d7d1efb941911f49efdfe036d2826507/pyramid-1.9.1.tar.gz"; | |
1364 | md5 = "6ef1dfdcff9136d04490410757c4c446"; |
|
1416 | md5 = "0163e19c58c2d12976a3b6fdb57e052d"; | |
1365 | }; |
|
1417 | }; | |
1366 | meta = { |
|
1418 | meta = { | |
1367 | license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; |
|
1419 | license = [ { fullName = "Repoze Public License"; } { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |
@@ -1381,13 +1433,13 b'' | |||||
1381 | }; |
|
1433 | }; | |
1382 | }; |
|
1434 | }; | |
1383 | pyramid-debugtoolbar = super.buildPythonPackage { |
|
1435 | pyramid-debugtoolbar = super.buildPythonPackage { | |
1384 |
name = "pyramid-debugtoolbar- |
|
1436 | name = "pyramid-debugtoolbar-4.2.1"; | |
1385 | buildInputs = with self; []; |
|
1437 | buildInputs = with self; []; | |
1386 | doCheck = false; |
|
1438 | doCheck = false; | |
1387 | propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments]; |
|
1439 | propagatedBuildInputs = with self; [pyramid pyramid-mako repoze.lru Pygments ipaddress]; | |
1388 | src = fetchurl { |
|
1440 | src = fetchurl { | |
1389 |
url = "https://pypi.python.org/packages/64 |
|
1441 | url = "https://pypi.python.org/packages/db/26/94620b7752936e2cd74838263ff366db9b454f7394bfb62d1eb2f84b29c1/pyramid_debugtoolbar-4.2.1.tar.gz"; | |
1390 | md5 = "aebab8c3bfdc6f89e4d3adc1d126538e"; |
|
1442 | md5 = "3dfaced2fab1644ff5284017be9d92b9"; | |
1391 | }; |
|
1443 | }; | |
1392 | meta = { |
|
1444 | meta = { | |
1393 | license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ]; |
|
1445 | license = [ { fullName = "Repoze Public License"; } pkgs.lib.licenses.bsdOriginal ]; | |
@@ -1420,26 +1472,26 b'' | |||||
1420 | }; |
|
1472 | }; | |
1421 | }; |
|
1473 | }; | |
1422 | pysqlite = super.buildPythonPackage { |
|
1474 | pysqlite = super.buildPythonPackage { | |
1423 |
name = "pysqlite-2. |
|
1475 | name = "pysqlite-2.8.3"; | |
1424 | buildInputs = with self; []; |
|
1476 | buildInputs = with self; []; | |
1425 | doCheck = false; |
|
1477 | doCheck = false; | |
1426 | propagatedBuildInputs = with self; []; |
|
1478 | propagatedBuildInputs = with self; []; | |
1427 | src = fetchurl { |
|
1479 | src = fetchurl { | |
1428 |
url = "https://pypi.python.org/packages/ |
|
1480 | url = "https://pypi.python.org/packages/42/02/981b6703e3c83c5b25a829c6e77aad059f9481b0bbacb47e6e8ca12bd731/pysqlite-2.8.3.tar.gz"; | |
1429 | md5 = "7ff1cedee74646b50117acff87aa1cfa"; |
|
1481 | md5 = "033f17b8644577715aee55e8832ac9fc"; | |
1430 | }; |
|
1482 | }; | |
1431 | meta = { |
|
1483 | meta = { | |
1432 | license = [ { fullName = "zlib/libpng License"; } { fullName = "zlib/libpng license"; } ]; |
|
1484 | license = [ { fullName = "zlib/libpng License"; } { fullName = "zlib/libpng license"; } ]; | |
1433 | }; |
|
1485 | }; | |
1434 | }; |
|
1486 | }; | |
1435 | pytest = super.buildPythonPackage { |
|
1487 | pytest = super.buildPythonPackage { | |
1436 |
name = "pytest-3. |
|
1488 | name = "pytest-3.1.2"; | |
1437 | buildInputs = with self; []; |
|
1489 | buildInputs = with self; []; | |
1438 | doCheck = false; |
|
1490 | doCheck = false; | |
1439 | propagatedBuildInputs = with self; [py]; |
|
1491 | propagatedBuildInputs = with self; [py setuptools]; | |
1440 | src = fetchurl { |
|
1492 | src = fetchurl { | |
1441 | url = "https://pypi.python.org/packages/a8/87/b7ca49efe52d2b4169f2bfc49aa5e384173c4619ea8e635f123a0dac5b75/pytest-3.0.5.tar.gz"; |
|
1493 | url = "https://pypi.python.org/packages/72/2b/2d3155e01f45a5a04427857352ee88220ee39550b2bc078f9db3190aea46/pytest-3.1.2.tar.gz"; | |
1442 | md5 = "cefd527b59332688bf5db4a10aa8a7cb"; |
|
1494 | md5 = "c4d179f89043cc925e1c169d03128e02"; | |
1443 | }; |
|
1495 | }; | |
1444 | meta = { |
|
1496 | meta = { | |
1445 | license = [ pkgs.lib.licenses.mit ]; |
|
1497 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -1459,52 +1511,52 b'' | |||||
1459 | }; |
|
1511 | }; | |
1460 | }; |
|
1512 | }; | |
1461 | pytest-cov = super.buildPythonPackage { |
|
1513 | pytest-cov = super.buildPythonPackage { | |
1462 |
name = "pytest-cov-2. |
|
1514 | name = "pytest-cov-2.5.1"; | |
1463 | buildInputs = with self; []; |
|
1515 | buildInputs = with self; []; | |
1464 | doCheck = false; |
|
1516 | doCheck = false; | |
1465 | propagatedBuildInputs = with self; [pytest coverage]; |
|
1517 | propagatedBuildInputs = with self; [pytest coverage]; | |
1466 | src = fetchurl { |
|
1518 | src = fetchurl { | |
1467 |
url = "https://pypi.python.org/packages/0 |
|
1519 | url = "https://pypi.python.org/packages/24/b4/7290d65b2f3633db51393bdf8ae66309b37620bc3ec116c5e357e3e37238/pytest-cov-2.5.1.tar.gz"; | |
1468 | md5 = "2fda09677d232acc99ec1b3c5831e33f"; |
|
1520 | md5 = "5acf38d4909e19819eb5c1754fbfc0ac"; | |
1469 | }; |
|
1521 | }; | |
1470 | meta = { |
|
1522 | meta = { | |
1471 | license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.mit ]; |
|
1523 | license = [ pkgs.lib.licenses.bsdOriginal pkgs.lib.licenses.mit ]; | |
1472 | }; |
|
1524 | }; | |
1473 | }; |
|
1525 | }; | |
1474 | pytest-profiling = super.buildPythonPackage { |
|
1526 | pytest-profiling = super.buildPythonPackage { | |
1475 |
name = "pytest-profiling-1.2. |
|
1527 | name = "pytest-profiling-1.2.6"; | |
1476 | buildInputs = with self; []; |
|
1528 | buildInputs = with self; []; | |
1477 | doCheck = false; |
|
1529 | doCheck = false; | |
1478 | propagatedBuildInputs = with self; [six pytest gprof2dot]; |
|
1530 | propagatedBuildInputs = with self; [six pytest gprof2dot]; | |
1479 | src = fetchurl { |
|
1531 | src = fetchurl { | |
1480 |
url = "https://pypi.python.org/packages/73 |
|
1532 | url = "https://pypi.python.org/packages/f9/0d/df67fb9ce16c2cef201693da956321b1bccfbf9a4ead39748b9f9d1d74cb/pytest-profiling-1.2.6.tar.gz"; | |
1481 | md5 = "0a16d7dda2d23b91e9730fa4558cf728"; |
|
1533 | md5 = "50eb4c66c3762a2f1a49669bedc0b894"; | |
1482 | }; |
|
1534 | }; | |
1483 | meta = { |
|
1535 | meta = { | |
1484 | license = [ pkgs.lib.licenses.mit ]; |
|
1536 | license = [ pkgs.lib.licenses.mit ]; | |
1485 | }; |
|
1537 | }; | |
1486 | }; |
|
1538 | }; | |
1487 | pytest-runner = super.buildPythonPackage { |
|
1539 | pytest-runner = super.buildPythonPackage { | |
1488 |
name = "pytest-runner-2. |
|
1540 | name = "pytest-runner-2.11.1"; | |
1489 | buildInputs = with self; []; |
|
1541 | buildInputs = with self; []; | |
1490 | doCheck = false; |
|
1542 | doCheck = false; | |
1491 | propagatedBuildInputs = with self; []; |
|
1543 | propagatedBuildInputs = with self; []; | |
1492 | src = fetchurl { |
|
1544 | src = fetchurl { | |
1493 | url = "https://pypi.python.org/packages/11/d4/c335ddf94463e451109e3494e909765c3e5205787b772e3b25ee8601b86a/pytest-runner-2.9.tar.gz"; |
|
1545 | url = "https://pypi.python.org/packages/9e/4d/08889e5e27a9f5d6096b9ad257f4dea1faabb03c5ded8f665ead448f5d8a/pytest-runner-2.11.1.tar.gz"; | |
1494 | md5 = "2212a2e34404b0960b2fdc2c469247b2"; |
|
1546 | md5 = "bdb73eb18eca2727944a2dcf963c5a81"; | |
1495 | }; |
|
1547 | }; | |
1496 | meta = { |
|
1548 | meta = { | |
1497 | license = [ pkgs.lib.licenses.mit ]; |
|
1549 | license = [ pkgs.lib.licenses.mit ]; | |
1498 | }; |
|
1550 | }; | |
1499 | }; |
|
1551 | }; | |
1500 | pytest-sugar = super.buildPythonPackage { |
|
1552 | pytest-sugar = super.buildPythonPackage { | |
1501 |
name = "pytest-sugar-0. |
|
1553 | name = "pytest-sugar-0.8.0"; | |
1502 | buildInputs = with self; []; |
|
1554 | buildInputs = with self; []; | |
1503 | doCheck = false; |
|
1555 | doCheck = false; | |
1504 | propagatedBuildInputs = with self; [pytest termcolor]; |
|
1556 | propagatedBuildInputs = with self; [pytest termcolor]; | |
1505 | src = fetchurl { |
|
1557 | src = fetchurl { | |
1506 | url = "https://pypi.python.org/packages/03/97/05d988b4fa870e7373e8ee4582408543b9ca2bd35c3c67b569369c6f9c49/pytest-sugar-0.7.1.tar.gz"; |
|
1558 | url = "https://pypi.python.org/packages/a5/b0/b2773dee078f17773a5bf2dfad49b0be57b6354bbd84bbefe4313e509d87/pytest-sugar-0.8.0.tar.gz"; | |
1507 | md5 = "7400f7c11f3d572b2c2a3b60352d35fe"; |
|
1559 | md5 = "8cafbdad648068e0e44b8fc5f9faae42"; | |
1508 | }; |
|
1560 | }; | |
1509 | meta = { |
|
1561 | meta = { | |
1510 | license = [ pkgs.lib.licenses.bsdOriginal ]; |
|
1562 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |
@@ -1550,26 +1602,26 b'' | |||||
1550 | }; |
|
1602 | }; | |
1551 | }; |
|
1603 | }; | |
1552 | python-ldap = super.buildPythonPackage { |
|
1604 | python-ldap = super.buildPythonPackage { | |
1553 |
name = "python-ldap-2.4. |
|
1605 | name = "python-ldap-2.4.40"; | |
1554 | buildInputs = with self; []; |
|
1606 | buildInputs = with self; []; | |
1555 | doCheck = false; |
|
1607 | doCheck = false; | |
1556 | propagatedBuildInputs = with self; [setuptools]; |
|
1608 | propagatedBuildInputs = with self; [setuptools]; | |
1557 | src = fetchurl { |
|
1609 | src = fetchurl { | |
1558 | url = "https://pypi.python.org/packages/42/81/1b64838c82e64f14d4e246ff00b52e650a35c012551b891ada2b85d40737/python-ldap-2.4.19.tar.gz"; |
|
1610 | url = "https://pypi.python.org/packages/4a/d8/7d70a7469058a3987d224061a81d778951ac2b48220bdcc511e4b1b37176/python-ldap-2.4.40.tar.gz"; | |
1559 | md5 = "b941bf31d09739492aa19ef679e94ae3"; |
|
1611 | md5 = "aea0233f7d39b0c7549fcd310deeb0e5"; | |
1560 | }; |
|
1612 | }; | |
1561 | meta = { |
|
1613 | meta = { | |
1562 | license = [ pkgs.lib.licenses.psfl ]; |
|
1614 | license = [ pkgs.lib.licenses.psfl ]; | |
1563 | }; |
|
1615 | }; | |
1564 | }; |
|
1616 | }; | |
1565 | python-memcached = super.buildPythonPackage { |
|
1617 | python-memcached = super.buildPythonPackage { | |
1566 |
name = "python-memcached-1.5 |
|
1618 | name = "python-memcached-1.58"; | |
1567 | buildInputs = with self; []; |
|
1619 | buildInputs = with self; []; | |
1568 | doCheck = false; |
|
1620 | doCheck = false; | |
1569 | propagatedBuildInputs = with self; [six]; |
|
1621 | propagatedBuildInputs = with self; [six]; | |
1570 | src = fetchurl { |
|
1622 | src = fetchurl { | |
1571 |
url = "https://pypi.python.org/packages/ |
|
1623 | url = "https://pypi.python.org/packages/f7/62/14b2448cfb04427366f24104c9da97cf8ea380d7258a3233f066a951a8d8/python-memcached-1.58.tar.gz"; | |
1572 | md5 = "de21f64b42b2d961f3d4ad7beb5468a1"; |
|
1624 | md5 = "23b258105013d14d899828d334e6b044"; | |
1573 | }; |
|
1625 | }; | |
1574 | meta = { |
|
1626 | meta = { | |
1575 | license = [ pkgs.lib.licenses.psfl ]; |
|
1627 | license = [ pkgs.lib.licenses.psfl ]; | |
@@ -1627,6 +1679,19 b'' | |||||
1627 | license = [ { fullName = "MIT/X11"; } ]; |
|
1679 | license = [ { fullName = "MIT/X11"; } ]; | |
1628 | }; |
|
1680 | }; | |
1629 | }; |
|
1681 | }; | |
|
1682 | redis = super.buildPythonPackage { | |||
|
1683 | name = "redis-2.10.6"; | |||
|
1684 | buildInputs = with self; []; | |||
|
1685 | doCheck = false; | |||
|
1686 | propagatedBuildInputs = with self; []; | |||
|
1687 | src = fetchurl { | |||
|
1688 | url = "https://pypi.python.org/packages/09/8d/6d34b75326bf96d4139a2ddd8e74b80840f800a0a79f9294399e212cb9a7/redis-2.10.6.tar.gz"; | |||
|
1689 | md5 = "048348d8cfe0b5d0bba2f4d835005c3b"; | |||
|
1690 | }; | |||
|
1691 | meta = { | |||
|
1692 | license = [ pkgs.lib.licenses.mit ]; | |||
|
1693 | }; | |||
|
1694 | }; | |||
1630 | repoze.lru = super.buildPythonPackage { |
|
1695 | repoze.lru = super.buildPythonPackage { | |
1631 | name = "repoze.lru-0.6"; |
|
1696 | name = "repoze.lru-0.6"; | |
1632 | buildInputs = with self; []; |
|
1697 | buildInputs = with self; []; | |
@@ -1654,28 +1719,41 b'' | |||||
1654 | }; |
|
1719 | }; | |
1655 | }; |
|
1720 | }; | |
1656 | rhodecode-enterprise-ce = super.buildPythonPackage { |
|
1721 | rhodecode-enterprise-ce = super.buildPythonPackage { | |
1657 |
name = "rhodecode-enterprise-ce-4. |
|
1722 | name = "rhodecode-enterprise-ce-4.10.0"; | |
1658 | buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj]; |
|
1723 | buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj]; | |
1659 | doCheck = true; |
|
1724 | doCheck = true; | |
1660 |
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 |
|
1725 | 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]; | |
1661 | src = ./.; |
|
1726 | src = ./.; | |
1662 | meta = { |
|
1727 | meta = { | |
1663 | license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ]; |
|
1728 | license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ]; | |
1664 | }; |
|
1729 | }; | |
1665 | }; |
|
1730 | }; | |
1666 | rhodecode-tools = super.buildPythonPackage { |
|
1731 | rhodecode-tools = super.buildPythonPackage { | |
1667 |
name = "rhodecode-tools-0.1 |
|
1732 | name = "rhodecode-tools-0.13.0"; | |
1668 | buildInputs = with self; []; |
|
1733 | buildInputs = with self; []; | |
1669 | doCheck = false; |
|
1734 | doCheck = false; | |
1670 | propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh]; |
|
1735 | propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests elasticsearch elasticsearch-dsl urllib3 Whoosh]; | |
1671 | src = fetchurl { |
|
1736 | src = fetchurl { | |
1672 |
url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.1 |
|
1737 | url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.13.0.tar.gz?md5=f937b0cb34d0779103895a5ec5689ee4"; | |
1673 | md5 = "9ca040356fa7e38d3f64529a4cffdca4"; |
|
1738 | md5 = "f937b0cb34d0779103895a5ec5689ee4"; | |
1674 | }; |
|
1739 | }; | |
1675 | meta = { |
|
1740 | meta = { | |
1676 | license = [ { fullName = "AGPLv3 and Proprietary"; } ]; |
|
1741 | license = [ { fullName = "AGPLv3 and Proprietary"; } ]; | |
1677 | }; |
|
1742 | }; | |
1678 | }; |
|
1743 | }; | |
|
1744 | scandir = super.buildPythonPackage { | |||
|
1745 | name = "scandir-1.5"; | |||
|
1746 | buildInputs = with self; []; | |||
|
1747 | doCheck = false; | |||
|
1748 | propagatedBuildInputs = with self; []; | |||
|
1749 | src = fetchurl { | |||
|
1750 | url = "https://pypi.python.org/packages/bd/f4/3143e0289faf0883228017dbc6387a66d0b468df646645e29e1eb89ea10e/scandir-1.5.tar.gz"; | |||
|
1751 | md5 = "a2713043de681bba6b084be42e7a8a44"; | |||
|
1752 | }; | |||
|
1753 | meta = { | |||
|
1754 | license = [ pkgs.lib.licenses.bsdOriginal { fullName = "New BSD License"; } ]; | |||
|
1755 | }; | |||
|
1756 | }; | |||
1679 | setproctitle = super.buildPythonPackage { |
|
1757 | setproctitle = super.buildPythonPackage { | |
1680 | name = "setproctitle-1.1.8"; |
|
1758 | name = "setproctitle-1.1.8"; | |
1681 | buildInputs = with self; []; |
|
1759 | buildInputs = with self; []; | |
@@ -1729,13 +1807,13 b'' | |||||
1729 | }; |
|
1807 | }; | |
1730 | }; |
|
1808 | }; | |
1731 | simplejson = super.buildPythonPackage { |
|
1809 | simplejson = super.buildPythonPackage { | |
1732 |
name = "simplejson-3. |
|
1810 | name = "simplejson-3.11.1"; | |
1733 | buildInputs = with self; []; |
|
1811 | buildInputs = with self; []; | |
1734 | doCheck = false; |
|
1812 | doCheck = false; | |
1735 | propagatedBuildInputs = with self; []; |
|
1813 | propagatedBuildInputs = with self; []; | |
1736 | src = fetchurl { |
|
1814 | src = fetchurl { | |
1737 |
url = "https://pypi.python.org/packages/6d |
|
1815 | url = "https://pypi.python.org/packages/08/48/c97b668d6da7d7bebe7ea1817a6f76394b0ec959cb04214ca833c34359df/simplejson-3.11.1.tar.gz"; | |
1738 | md5 = "a5fc7d05d4cb38492285553def5d4b46"; |
|
1816 | md5 = "6e2f1bd5fb0a926facf5d89d217a7183"; | |
1739 | }; |
|
1817 | }; | |
1740 | meta = { |
|
1818 | meta = { | |
1741 | license = [ { fullName = "Academic Free License (AFL)"; } pkgs.lib.licenses.mit ]; |
|
1819 | license = [ { fullName = "Academic Free License (AFL)"; } pkgs.lib.licenses.mit ]; | |
@@ -1754,27 +1832,40 b'' | |||||
1754 | license = [ pkgs.lib.licenses.mit ]; |
|
1832 | license = [ pkgs.lib.licenses.mit ]; | |
1755 | }; |
|
1833 | }; | |
1756 | }; |
|
1834 | }; | |
|
1835 | sshpubkeys = super.buildPythonPackage { | |||
|
1836 | name = "sshpubkeys-2.2.0"; | |||
|
1837 | buildInputs = with self; []; | |||
|
1838 | doCheck = false; | |||
|
1839 | propagatedBuildInputs = with self; [pycrypto ecdsa]; | |||
|
1840 | src = fetchurl { | |||
|
1841 | url = "https://pypi.python.org/packages/27/da/337fabeb3dca6b62039a93ceaa636f25065e0ae92b575b1235342076cf0a/sshpubkeys-2.2.0.tar.gz"; | |||
|
1842 | md5 = "458e45f6b92b1afa84f0ffe1f1c90935"; | |||
|
1843 | }; | |||
|
1844 | meta = { | |||
|
1845 | license = [ pkgs.lib.licenses.bsdOriginal ]; | |||
|
1846 | }; | |||
|
1847 | }; | |||
1757 | subprocess32 = super.buildPythonPackage { |
|
1848 | subprocess32 = super.buildPythonPackage { | |
1758 |
name = "subprocess32-3.2. |
|
1849 | name = "subprocess32-3.2.7"; | |
1759 | buildInputs = with self; []; |
|
1850 | buildInputs = with self; []; | |
1760 | doCheck = false; |
|
1851 | doCheck = false; | |
1761 | propagatedBuildInputs = with self; []; |
|
1852 | propagatedBuildInputs = with self; []; | |
1762 | src = fetchurl { |
|
1853 | src = fetchurl { | |
1763 |
url = "https://pypi.python.org/packages/ |
|
1854 | url = "https://pypi.python.org/packages/b8/2f/49e53b0d0e94611a2dc624a1ad24d41b6d94d0f1b0a078443407ea2214c2/subprocess32-3.2.7.tar.gz"; | |
1764 | md5 = "754c5ab9f533e764f931136974b618f1"; |
|
1855 | md5 = "824c801e479d3e916879aae3e9c15e16"; | |
1765 | }; |
|
1856 | }; | |
1766 | meta = { |
|
1857 | meta = { | |
1767 | license = [ pkgs.lib.licenses.psfl ]; |
|
1858 | license = [ pkgs.lib.licenses.psfl ]; | |
1768 | }; |
|
1859 | }; | |
1769 | }; |
|
1860 | }; | |
1770 | supervisor = super.buildPythonPackage { |
|
1861 | supervisor = super.buildPythonPackage { | |
1771 |
name = "supervisor-3.3. |
|
1862 | name = "supervisor-3.3.3"; | |
1772 | buildInputs = with self; []; |
|
1863 | buildInputs = with self; []; | |
1773 | doCheck = false; |
|
1864 | doCheck = false; | |
1774 | propagatedBuildInputs = with self; [meld3]; |
|
1865 | propagatedBuildInputs = with self; [meld3]; | |
1775 | src = fetchurl { |
|
1866 | src = fetchurl { | |
1776 |
url = "https://pypi.python.org/packages/80 |
|
1867 | url = "https://pypi.python.org/packages/31/7e/788fc6566211e77c395ea272058eb71299c65cc5e55b6214d479c6c2ec9a/supervisor-3.3.3.tar.gz"; | |
1777 | md5 = "202f760f9bf4930ec06557bac73e5cf2"; |
|
1868 | md5 = "0fe86dfec4e5c5d98324d24c4cf944bd"; | |
1778 | }; |
|
1869 | }; | |
1779 | meta = { |
|
1870 | meta = { | |
1780 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; |
|
1871 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |
@@ -1794,13 +1885,13 b'' | |||||
1794 | }; |
|
1885 | }; | |
1795 | }; |
|
1886 | }; | |
1796 | testpath = super.buildPythonPackage { |
|
1887 | testpath = super.buildPythonPackage { | |
1797 | name = "testpath-0.1"; |
|
1888 | name = "testpath-0.3.1"; | |
1798 | buildInputs = with self; []; |
|
1889 | buildInputs = with self; []; | |
1799 | doCheck = false; |
|
1890 | doCheck = false; | |
1800 | propagatedBuildInputs = with self; []; |
|
1891 | propagatedBuildInputs = with self; []; | |
1801 | src = fetchurl { |
|
1892 | src = fetchurl { | |
1802 |
url = "https://pypi.python.org/packages/f |
|
1893 | url = "https://pypi.python.org/packages/f4/8b/b71e9ee10e5f751e9d959bc750ab122ba04187f5aa52aabdc4e63b0e31a7/testpath-0.3.1.tar.gz"; | |
1803 | md5 = "401918bcd0b0e5b71a9b909835117bc6"; |
|
1894 | md5 = "2cd5ed5522fda781bb497c9d80ae2fc9"; | |
1804 | }; |
|
1895 | }; | |
1805 | meta = { |
|
1896 | meta = { | |
1806 | license = [ pkgs.lib.licenses.mit ]; |
|
1897 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -1859,13 +1950,13 b'' | |||||
1859 | }; |
|
1950 | }; | |
1860 | }; |
|
1951 | }; | |
1861 | uWSGI = super.buildPythonPackage { |
|
1952 | uWSGI = super.buildPythonPackage { | |
1862 |
name = "uWSGI-2.0.1 |
|
1953 | name = "uWSGI-2.0.15"; | |
1863 | buildInputs = with self; []; |
|
1954 | buildInputs = with self; []; | |
1864 | doCheck = false; |
|
1955 | doCheck = false; | |
1865 | propagatedBuildInputs = with self; []; |
|
1956 | propagatedBuildInputs = with self; []; | |
1866 | src = fetchurl { |
|
1957 | src = fetchurl { | |
1867 | url = "https://pypi.python.org/packages/9b/78/918db0cfab0546afa580c1e565209c49aaf1476bbfe491314eadbe47c556/uwsgi-2.0.11.2.tar.gz"; |
|
1958 | url = "https://pypi.python.org/packages/bb/0a/45e5aa80dc135889594bb371c082d20fb7ee7303b174874c996888cc8511/uwsgi-2.0.15.tar.gz"; | |
1868 | md5 = "1f02dcbee7f6f61de4b1fd68350cf16f"; |
|
1959 | md5 = "fc50bd9e83b7602fa474b032167010a7"; | |
1869 | }; |
|
1960 | }; | |
1870 | meta = { |
|
1961 | meta = { | |
1871 | license = [ pkgs.lib.licenses.gpl2 ]; |
|
1962 | license = [ pkgs.lib.licenses.gpl2 ]; | |
@@ -1885,26 +1976,26 b'' | |||||
1885 | }; |
|
1976 | }; | |
1886 | }; |
|
1977 | }; | |
1887 | venusian = super.buildPythonPackage { |
|
1978 | venusian = super.buildPythonPackage { | |
1888 | name = "venusian-1.0"; |
|
1979 | name = "venusian-1.1.0"; | |
1889 | buildInputs = with self; []; |
|
1980 | buildInputs = with self; []; | |
1890 | doCheck = false; |
|
1981 | doCheck = false; | |
1891 | propagatedBuildInputs = with self; []; |
|
1982 | propagatedBuildInputs = with self; []; | |
1892 | src = fetchurl { |
|
1983 | src = fetchurl { | |
1893 | url = "https://pypi.python.org/packages/86/20/1948e0dfc4930ddde3da8c33612f6a5717c0b4bc28f591a5c5cf014dd390/venusian-1.0.tar.gz"; |
|
1984 | url = "https://pypi.python.org/packages/38/24/b4b470ab9e0a2e2e9b9030c7735828c8934b4c6b45befd1bb713ec2aeb2d/venusian-1.1.0.tar.gz"; | |
1894 | md5 = "dccf2eafb7113759d60c86faf5538756"; |
|
1985 | md5 = "56bc5e6756e4bda37bcdb94f74a72b8f"; | |
1895 | }; |
|
1986 | }; | |
1896 | meta = { |
|
1987 | meta = { | |
1897 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; |
|
1988 | license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ]; | |
1898 | }; |
|
1989 | }; | |
1899 | }; |
|
1990 | }; | |
1900 | waitress = super.buildPythonPackage { |
|
1991 | waitress = super.buildPythonPackage { | |
1901 |
name = "waitress-1.0. |
|
1992 | name = "waitress-1.0.2"; | |
1902 | buildInputs = with self; []; |
|
1993 | buildInputs = with self; []; | |
1903 | doCheck = false; |
|
1994 | doCheck = false; | |
1904 | propagatedBuildInputs = with self; []; |
|
1995 | propagatedBuildInputs = with self; []; | |
1905 | src = fetchurl { |
|
1996 | src = fetchurl { | |
1906 |
url = "https://pypi.python.org/packages/ |
|
1997 | url = "https://pypi.python.org/packages/cd/f4/400d00863afa1e03618e31fd7e2092479a71b8c9718b00eb1eeb603746c6/waitress-1.0.2.tar.gz"; | |
1907 | md5 = "dda92358a7569669086155923a46e57c"; |
|
1998 | md5 = "b968f39e95d609f6194c6e50425d4bb7"; | |
1908 | }; |
|
1999 | }; | |
1909 | meta = { |
|
2000 | meta = { | |
1910 | license = [ pkgs.lib.licenses.zpt21 ]; |
|
2001 | license = [ pkgs.lib.licenses.zpt21 ]; |
@@ -4,7 +4,11 b' pylons_config = rhodecode/tests/rhodecod' | |||||
4 | vcsserver_protocol = http |
|
4 | vcsserver_protocol = http | |
5 | vcsserver_config_http = rhodecode/tests/vcsserver_http.ini |
|
5 | vcsserver_config_http = rhodecode/tests/vcsserver_http.ini | |
6 | norecursedirs = tests/scripts |
|
6 | norecursedirs = tests/scripts | |
7 | addopts = -k "not _BaseTest" |
|
7 | ||
|
8 | addopts = | |||
|
9 | -k "not _BaseTest" | |||
|
10 | --pdbcls=IPython.terminal.debugger:TerminalPdb | |||
|
11 | ||||
8 | markers = |
|
12 | markers = | |
9 | vcs_operations: Mark tests depending on a running RhodeCode instance. |
|
13 | vcs_operations: Mark tests depending on a running RhodeCode instance. | |
10 | xfail_backends: Mark tests as xfail for given backends. |
|
14 | xfail_backends: Mark tests as xfail for given backends. |
@@ -145,9 +145,9 b' let' | |||||
145 | --repos=$PWD/repos \ |
|
145 | --repos=$PWD/repos \ | |
146 | enterprise.ini > /dev/null |
|
146 | enterprise.ini > /dev/null | |
147 |
|
147 | |||
148 | echo "Starting rcserver" |
|
148 | echo "Starting rc-server" | |
149 | vcsserver --config ${vcsserverCfg} >vcsserver.log 2>&1 & |
|
149 | vcsserver --config ${vcsserverCfg} >vcsserver.log 2>&1 & | |
150 | rcserver enterprise.ini >rcserver.log 2>&1 & |
|
150 | rc-server enterprise.ini >rc-server.log 2>&1 & | |
151 |
|
151 | |||
152 | while ! curl -f -s http://localhost:5000 > /dev/null |
|
152 | while ! curl -f -s http://localhost:5000 > /dev/null | |
153 | do |
|
153 | do | |
@@ -159,7 +159,7 b' let' | |||||
159 | echo "Starting the test run" |
|
159 | echo "Starting the test run" | |
160 | py.test -c example.ini -vs --maxfail=5 tests |
|
160 | py.test -c example.ini -vs --maxfail=5 tests | |
161 |
|
161 | |||
162 | echo "Kill rcserver" |
|
162 | echo "Kill rc-server" | |
163 | kill %2 |
|
163 | kill %2 | |
164 | kill %1 |
|
164 | kill %1 | |
165 | ''; |
|
165 | ''; | |
@@ -170,13 +170,13 b' let' | |||||
170 | mkdir -p $out |
|
170 | mkdir -p $out | |
171 | cp enterprise.ini $out |
|
171 | cp enterprise.ini $out | |
172 | cp ${vcsserverCfg} $out/vcsserver.ini |
|
172 | cp ${vcsserverCfg} $out/vcsserver.ini | |
173 | cp rcserver.log $out |
|
173 | cp rc-server.log $out | |
174 | cp vcsserver.log $out |
|
174 | cp vcsserver.log $out | |
175 |
|
175 | |||
176 | mkdir -p $out/nix-support |
|
176 | mkdir -p $out/nix-support | |
177 | echo "report config $out enterprise.ini" >> $out/nix-support/hydra-build-products |
|
177 | echo "report config $out enterprise.ini" >> $out/nix-support/hydra-build-products | |
178 | echo "report config $out vcsserver.ini" >> $out/nix-support/hydra-build-products |
|
178 | echo "report config $out vcsserver.ini" >> $out/nix-support/hydra-build-products | |
179 | echo "report rcserver $out rcserver.log" >> $out/nix-support/hydra-build-products |
|
179 | echo "report rc-server $out rc-server.log" >> $out/nix-support/hydra-build-products | |
180 | echo "report vcsserver $out vcsserver.log" >> $out/nix-support/hydra-build-products |
|
180 | echo "report vcsserver $out vcsserver.log" >> $out/nix-support/hydra-build-products | |
181 | ''; |
|
181 | ''; | |
182 | }; |
|
182 | }; |
@@ -6,21 +6,20 b' amqplib==1.0.2' | |||||
6 | anyjson==0.3.3 |
|
6 | anyjson==0.3.3 | |
7 | authomatic==0.1.0.post1 |
|
7 | authomatic==0.1.0.post1 | |
8 | Babel==1.3 |
|
8 | Babel==1.3 | |
9 | backport-ipaddress==0.1 |
|
9 | Beaker==1.9.0 | |
10 | Beaker==1.7.0 |
|
|||
11 | celery==2.2.10 |
|
10 | celery==2.2.10 | |
12 | Chameleon==2.24 |
|
11 | Chameleon==2.24 | |
13 | channelstream==0.5.2 |
|
12 | channelstream==0.5.2 | |
14 | click==5.1 |
|
13 | click==5.1 | |
15 |
colander==1. |
|
14 | colander==1.3.3 | |
16 | configobj==5.0.6 |
|
15 | configobj==5.0.6 | |
17 | cssselect==1.0.1 |
|
16 | cssselect==1.0.1 | |
18 | decorator==4.0.11 |
|
17 | decorator==4.0.11 | |
19 | deform==2.0.4 |
|
18 | deform==2.0.4 | |
20 |
docutils==0.1 |
|
19 | docutils==0.13.1 | |
21 |
dogpile.cache==0.6. |
|
20 | dogpile.cache==0.6.4 | |
22 | dogpile.core==0.4.1 |
|
21 | dogpile.core==0.4.1 | |
23 |
ecdsa==0.1 |
|
22 | ecdsa==0.13 | |
24 | FormEncode==1.2.4 |
|
23 | FormEncode==1.2.4 | |
25 | future==0.14.3 |
|
24 | future==0.14.3 | |
26 | futures==3.0.2 |
|
25 | futures==3.0.2 | |
@@ -31,8 +30,8 b' itsdangerous==0.24' | |||||
31 | Jinja2==2.7.3 |
|
30 | Jinja2==2.7.3 | |
32 | kombu==1.5.1 |
|
31 | kombu==1.5.1 | |
33 | lxml==3.7.3 |
|
32 | lxml==3.7.3 | |
34 |
Mako==1.0. |
|
33 | Mako==1.0.7 | |
35 |
Markdown==2.6. |
|
34 | Markdown==2.6.8 | |
36 | MarkupSafe==0.23 |
|
35 | MarkupSafe==0.23 | |
37 | meld3==1.0.2 |
|
36 | meld3==1.0.2 | |
38 | msgpack-python==0.4.8 |
|
37 | msgpack-python==0.4.8 | |
@@ -40,13 +39,13 b' MySQL-python==1.2.5' | |||||
40 | nose==1.3.6 |
|
39 | nose==1.3.6 | |
41 | objgraph==3.1.0 |
|
40 | objgraph==3.1.0 | |
42 | packaging==15.2 |
|
41 | packaging==15.2 | |
43 | paramiko==1.15.1 |
|
|||
44 | Paste==2.0.3 |
|
42 | Paste==2.0.3 | |
45 | PasteDeploy==1.5.2 |
|
43 | PasteDeploy==1.5.2 | |
46 | PasteScript==1.7.5 |
|
44 | PasteScript==1.7.5 | |
47 |
pathlib2==2. |
|
45 | pathlib2==2.3.0 | |
|
46 | peppercorn==0.5 | |||
48 | psutil==4.3.1 |
|
47 | psutil==4.3.1 | |
49 |
psycopg2==2. |
|
48 | psycopg2==2.7.1 | |
50 | py-bcrypt==0.4 |
|
49 | py-bcrypt==0.4 | |
51 | pycrypto==2.6.1 |
|
50 | pycrypto==2.6.1 | |
52 | pycurl==7.19.5 |
|
51 | pycurl==7.19.5 | |
@@ -55,38 +54,40 b' pygments-markdown-lexer==0.1.0.dev39' | |||||
55 | Pygments==2.2.0 |
|
54 | Pygments==2.2.0 | |
56 | pyparsing==1.5.7 |
|
55 | pyparsing==1.5.7 | |
57 | pyramid-beaker==0.8 |
|
56 | pyramid-beaker==0.8 | |
58 |
pyramid-debugtoolbar== |
|
57 | pyramid-debugtoolbar==4.2.1 | |
59 | pyramid-jinja2==2.5 |
|
58 | pyramid-jinja2==2.5 | |
60 | pyramid-mako==1.0.2 |
|
59 | pyramid-mako==1.0.2 | |
61 |
pyramid==1. |
|
60 | pyramid==1.9.1 | |
62 |
pysqlite==2. |
|
61 | pysqlite==2.8.3 | |
63 | python-dateutil==2.1 |
|
62 | python-dateutil==2.1 | |
64 |
python-ldap==2.4. |
|
63 | python-ldap==2.4.40 | |
65 |
python-memcached==1.5 |
|
64 | python-memcached==1.58 | |
66 | python-pam==1.8.2 |
|
65 | python-pam==1.8.2 | |
67 | pytz==2015.4 |
|
66 | pytz==2015.4 | |
68 | pyzmq==14.6.0 |
|
67 | pyzmq==14.6.0 | |
69 | recaptcha-client==1.0.6 |
|
68 | recaptcha-client==1.0.6 | |
|
69 | redis==2.10.6 | |||
70 | repoze.lru==0.6 |
|
70 | repoze.lru==0.6 | |
71 | requests==2.9.1 |
|
71 | requests==2.9.1 | |
72 | Routes==1.13 |
|
72 | Routes==1.13 | |
73 | setproctitle==1.1.8 |
|
73 | setproctitle==1.1.8 | |
74 |
simplejson==3. |
|
74 | simplejson==3.11.1 | |
75 | six==1.9.0 |
|
75 | six==1.9.0 | |
76 | Sphinx==1.2.2 |
|
76 | Sphinx==1.2.2 | |
77 |
SQLAlchemy== |
|
77 | SQLAlchemy==1.1.11 | |
78 | subprocess32==3.2.6 |
|
78 | sshpubkeys==2.2.0 | |
79 | supervisor==3.3.1 |
|
79 | subprocess32==3.2.7 | |
|
80 | supervisor==3.3.3 | |||
80 | Tempita==0.5.2 |
|
81 | Tempita==0.5.2 | |
81 | translationstring==1.3 |
|
82 | translationstring==1.3 | |
82 | trollius==1.0.4 |
|
83 | trollius==1.0.4 | |
83 | urllib3==1.16 |
|
84 | urllib3==1.16 | |
84 | URLObject==2.4.0 |
|
85 | URLObject==2.4.0 | |
85 | venusian==1.0 |
|
86 | venusian==1.1.0 | |
86 | WebError==0.10.3 |
|
87 | WebError==0.10.3 | |
87 | WebHelpers2==2.0 |
|
88 | WebHelpers2==2.0 | |
88 | WebHelpers==1.3 |
|
89 | WebHelpers==1.3 | |
89 |
WebOb==1. |
|
90 | WebOb==1.7.3 | |
90 | Whoosh==2.7.4 |
|
91 | Whoosh==2.7.4 | |
91 | wsgiref==0.1.2 |
|
92 | wsgiref==0.1.2 | |
92 | zope.cachedescriptors==4.0.0 |
|
93 | zope.cachedescriptors==4.0.0 | |
@@ -104,33 +105,34 b' https://code.rhodecode.com/upstream/py-g' | |||||
104 | # entrypoints backport, pypi version doesn't support egg installs |
|
105 | # entrypoints backport, pypi version doesn't support egg installs | |
105 | https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1 |
|
106 | https://code.rhodecode.com/upstream/entrypoints/archive/96e6d645684e1af3d7df5b5272f3fe85a546b233.tar.gz?md5=7db37771aea9ac9fefe093e5d6987313#egg=entrypoints==0.2.2.rhodecode-upstream1 | |
106 | nbconvert==5.1.1 |
|
107 | nbconvert==5.1.1 | |
|
108 | bleach==1.5.0 | |||
107 | nbformat==4.3.0 |
|
109 | nbformat==4.3.0 | |
108 | jupyter_client==5.0.0 |
|
110 | jupyter_client==5.0.0 | |
109 |
|
111 | |||
110 | ## cli tools |
|
112 | ## cli tools | |
111 |
alembic==0. |
|
113 | alembic==0.9.2 | |
112 | invoke==0.13.0 |
|
114 | invoke==0.13.0 | |
113 | bumpversion==0.5.3 |
|
115 | bumpversion==0.5.3 | |
114 | transifex-client==0.10 |
|
116 | transifex-client==0.10 | |
115 |
|
117 | |||
116 | ## http servers |
|
118 | ## http servers | |
117 |
gevent==1. |
|
119 | gevent==1.2.2 | |
118 |
greenlet==0.4.1 |
|
120 | greenlet==0.4.12 | |
119 |
gunicorn==19. |
|
121 | gunicorn==19.7.1 | |
120 |
waitress==1.0. |
|
122 | waitress==1.0.2 | |
121 |
uWSGI==2.0.1 |
|
123 | uWSGI==2.0.15 | |
122 |
|
124 | |||
123 | ## debug |
|
125 | ## debug | |
124 |
ipdb==0.10. |
|
126 | ipdb==0.10.3 | |
125 | ipython==5.1.0 |
|
127 | ipython==5.1.0 | |
126 |
CProfileV==1.0. |
|
128 | CProfileV==1.0.7 | |
127 | bottle==0.12.8 |
|
129 | bottle==0.12.8 | |
128 |
|
130 | |||
129 | ## rhodecode-tools, special case |
|
131 | ## rhodecode-tools, special case | |
130 |
https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.1 |
|
132 | https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.13.0.tar.gz?md5=f937b0cb34d0779103895a5ec5689ee4#egg=rhodecode-tools==0.13.0 | |
131 |
|
133 | |||
132 | ## appenlight |
|
134 | ## appenlight | |
133 |
appenlight-client==0.6.1 |
|
135 | appenlight-client==0.6.21 | |
134 |
|
136 | |||
135 | ## test related requirements |
|
137 | ## test related requirements | |
136 | -r requirements_test.txt |
|
138 | -r requirements_test.txt |
@@ -1,15 +1,15 b'' | |||||
1 | # test related requirements |
|
1 | # test related requirements | |
2 |
pytest==3. |
|
2 | pytest==3.1.2 | |
3 |
py==1.4.3 |
|
3 | py==1.4.34 | |
4 |
pytest-cov==2. |
|
4 | pytest-cov==2.5.1 | |
5 |
pytest-sugar==0. |
|
5 | pytest-sugar==0.8.0 | |
6 |
pytest-runner==2. |
|
6 | pytest-runner==2.11.1 | |
7 | pytest-catchlog==1.2.2 |
|
7 | pytest-catchlog==1.2.2 | |
8 |
pytest-profiling==1.2. |
|
8 | pytest-profiling==1.2.6 | |
9 | gprof2dot==2016.10.13 |
|
9 | gprof2dot==2016.10.13 | |
10 | pytest-timeout==1.2.0 |
|
10 | pytest-timeout==1.2.0 | |
11 |
|
11 | |||
12 | mock==1.0.1 |
|
12 | mock==1.0.1 | |
13 |
WebTest== |
|
13 | WebTest==2.0.27 | |
14 | cov-core==1.15.0 |
|
14 | cov-core==1.15.0 | |
15 | coverage==3.7.1 |
|
15 | coverage==3.7.1 |
@@ -51,7 +51,7 b' PYRAMID_SETTINGS = {}' | |||||
51 | EXTENSIONS = {} |
|
51 | EXTENSIONS = {} | |
52 |
|
52 | |||
53 | __version__ = ('.'.join((str(each) for each in VERSION[:3]))) |
|
53 | __version__ = ('.'.join((str(each) for each in VERSION[:3]))) | |
54 |
__dbversion__ = |
|
54 | __dbversion__ = 81 # defines current db version for migrations | |
55 | __platform__ = platform.system() |
|
55 | __platform__ = platform.system() | |
56 | __license__ = 'AGPLv3, and Commercial License' |
|
56 | __license__ = 'AGPLv3, and Commercial License' | |
57 | __author__ = 'RhodeCode GmbH' |
|
57 | __author__ = 'RhodeCode GmbH' |
@@ -281,8 +281,8 b' def request_view(request):' | |||||
281 | }) |
|
281 | }) | |
282 |
|
282 | |||
283 | # register some common functions for usage |
|
283 | # register some common functions for usage | |
284 | attach_context_attributes(TemplateArgs(), request, request.rpc_user.user_id, |
|
284 | attach_context_attributes( | |
285 | attach_to_request=True) |
|
285 | TemplateArgs(), request, request.rpc_user.user_id) | |
286 |
|
286 | |||
287 | try: |
|
287 | try: | |
288 | ret_value = func(**call_params) |
|
288 | ret_value = func(**call_params) |
@@ -45,7 +45,7 b' def testuser_api(request, pylonsapp):' | |||||
45 | # create TOKEN for user, if he doesn't have one |
|
45 | # create TOKEN for user, if he doesn't have one | |
46 | if not cls.test_user.api_key: |
|
46 | if not cls.test_user.api_key: | |
47 | AuthTokenModel().create( |
|
47 | AuthTokenModel().create( | |
48 | user=cls.test_user, description='TEST_USER_TOKEN') |
|
48 | user=cls.test_user, description=u'TEST_USER_TOKEN') | |
49 |
|
49 | |||
50 | Session().commit() |
|
50 | Session().commit() | |
51 | cls.TEST_USER_LOGIN = cls.test_user.username |
|
51 | cls.TEST_USER_LOGIN = cls.test_user.username |
@@ -28,7 +28,7 b' from rhodecode.api.tests.utils import (' | |||||
28 |
|
28 | |||
29 | @pytest.mark.usefixtures("testuser_api", "app") |
|
29 | @pytest.mark.usefixtures("testuser_api", "app") | |
30 | class TestApiGetGist(object): |
|
30 | class TestApiGetGist(object): | |
31 | def test_api_get_gist(self, gist_util, http_host_stub): |
|
31 | def test_api_get_gist(self, gist_util, http_host_only_stub): | |
32 | gist = gist_util.create_gist() |
|
32 | gist = gist_util.create_gist() | |
33 | gist_id = gist.gist_access_id |
|
33 | gist_id = gist.gist_access_id | |
34 | gist_created_on = gist.created_on |
|
34 | gist_created_on = gist.created_on | |
@@ -45,14 +45,14 b' class TestApiGetGist(object):' | |||||
45 | 'expires': -1.0, |
|
45 | 'expires': -1.0, | |
46 | 'gist_id': int(gist_id), |
|
46 | 'gist_id': int(gist_id), | |
47 | 'type': 'public', |
|
47 | 'type': 'public', | |
48 | 'url': 'http://%s/_admin/gists/%s' % (http_host_stub, gist_id,), |
|
48 | 'url': 'http://%s/_admin/gists/%s' % (http_host_only_stub, gist_id,), | |
49 | 'acl_level': Gist.ACL_LEVEL_PUBLIC, |
|
49 | 'acl_level': Gist.ACL_LEVEL_PUBLIC, | |
50 | 'content': None, |
|
50 | 'content': None, | |
51 | } |
|
51 | } | |
52 |
|
52 | |||
53 | assert_ok(id_, expected, given=response.body) |
|
53 | assert_ok(id_, expected, given=response.body) | |
54 |
|
54 | |||
55 | def test_api_get_gist_with_content(self, gist_util, http_host_stub): |
|
55 | def test_api_get_gist_with_content(self, gist_util, http_host_only_stub): | |
56 | mapping = { |
|
56 | mapping = { | |
57 | u'filename1.txt': {'content': u'hello world'}, |
|
57 | u'filename1.txt': {'content': u'hello world'}, | |
58 | u'filename1ą.txt': {'content': u'hello worldę'} |
|
58 | u'filename1ą.txt': {'content': u'hello worldę'} | |
@@ -73,7 +73,7 b' class TestApiGetGist(object):' | |||||
73 | 'expires': -1.0, |
|
73 | 'expires': -1.0, | |
74 | 'gist_id': int(gist_id), |
|
74 | 'gist_id': int(gist_id), | |
75 | 'type': 'public', |
|
75 | 'type': 'public', | |
76 | 'url': 'http://%s/_admin/gists/%s' % (http_host_stub, gist_id,), |
|
76 | 'url': 'http://%s/_admin/gists/%s' % (http_host_only_stub, gist_id,), | |
77 | 'acl_level': Gist.ACL_LEVEL_PUBLIC, |
|
77 | 'acl_level': Gist.ACL_LEVEL_PUBLIC, | |
78 | 'content': { |
|
78 | 'content': { | |
79 | u'filename1.txt': u'hello world', |
|
79 | u'filename1.txt': u'hello world', |
@@ -21,10 +21,10 b'' | |||||
21 |
|
21 | |||
22 | import pytest |
|
22 | import pytest | |
23 | import urlobject |
|
23 | import urlobject | |
24 | from pylons import url |
|
|||
25 |
|
24 | |||
26 | from rhodecode.api.tests.utils import ( |
|
25 | from rhodecode.api.tests.utils import ( | |
27 | build_data, api_call, assert_error, assert_ok) |
|
26 | build_data, api_call, assert_error, assert_ok) | |
|
27 | from rhodecode.lib import helpers as h | |||
28 | from rhodecode.lib.utils2 import safe_unicode |
|
28 | from rhodecode.lib.utils2 import safe_unicode | |
29 |
|
29 | |||
30 | pytestmark = pytest.mark.backends("git", "hg") |
|
30 | pytestmark = pytest.mark.backends("git", "hg") | |
@@ -46,10 +46,10 b' class TestGetPullRequest(object):' | |||||
46 | assert response.status == '200 OK' |
|
46 | assert response.status == '200 OK' | |
47 |
|
47 | |||
48 | url_obj = urlobject.URLObject( |
|
48 | url_obj = urlobject.URLObject( | |
49 | url( |
|
49 | h.route_url( | |
50 | 'pullrequest_show', |
|
50 | 'pullrequest_show', | |
51 | repo_name=pull_request.target_repo.repo_name, |
|
51 | repo_name=pull_request.target_repo.repo_name, | |
52 |
pull_request_id=pull_request.pull_request_id |
|
52 | pull_request_id=pull_request.pull_request_id)) | |
53 |
|
53 | |||
54 | pr_url = safe_unicode( |
|
54 | pr_url = safe_unicode( | |
55 | url_obj.with_netloc(http_host_only_stub)) |
|
55 | url_obj.with_netloc(http_host_only_stub)) |
@@ -116,7 +116,7 b' class TestGetRepos(object):' | |||||
116 | response = api_call(self.app, params) |
|
116 | response = api_call(self.app, params) | |
117 |
|
117 | |||
118 | user = User.get_by_username(self.TEST_USER_LOGIN) |
|
118 | user = User.get_by_username(self.TEST_USER_LOGIN) | |
119 | allowed_repos = user.AuthUser.permissions['repositories'] |
|
119 | allowed_repos = user.AuthUser().permissions['repositories'] | |
120 |
|
120 | |||
121 | result = [] |
|
121 | result = [] | |
122 | for repo in RepoModel().get_all(): |
|
122 | for repo in RepoModel().get_all(): |
@@ -274,7 +274,8 b' def merge_pull_request(' | |||||
274 |
|
274 | |||
275 | pull_request = get_pull_request_or_error(pullrequestid) |
|
275 | pull_request = get_pull_request_or_error(pullrequestid) | |
276 |
|
276 | |||
277 |
check = MergeCheck.validate( |
|
277 | check = MergeCheck.validate( | |
|
278 | pull_request, user=apiuser, translator=request.translate) | |||
278 | merge_possible = not check.failed |
|
279 | merge_possible = not check.failed | |
279 |
|
280 | |||
280 | if not merge_possible: |
|
281 | if not merge_possible: |
@@ -33,6 +33,7 b' from rhodecode.lib import user_sessions' | |||||
33 | from rhodecode.lib.utils2 import safe_int |
|
33 | from rhodecode.lib.utils2 import safe_int | |
34 | from rhodecode.model.db import UserIpMap |
|
34 | from rhodecode.model.db import UserIpMap | |
35 | from rhodecode.model.scm import ScmModel |
|
35 | from rhodecode.model.scm import ScmModel | |
|
36 | from rhodecode.model.settings import VcsSettingsModel | |||
36 |
|
37 | |||
37 | log = logging.getLogger(__name__) |
|
38 | log = logging.getLogger(__name__) | |
38 |
|
39 | |||
@@ -75,6 +76,35 b' def get_server_info(request, apiuser):' | |||||
75 |
|
76 | |||
76 |
|
77 | |||
77 | @jsonrpc_method() |
|
78 | @jsonrpc_method() | |
|
79 | def get_repo_store(request, apiuser): | |||
|
80 | """ | |||
|
81 | Returns the |RCE| repository storage information. | |||
|
82 | ||||
|
83 | :param apiuser: This is filled automatically from the |authtoken|. | |||
|
84 | :type apiuser: AuthUser | |||
|
85 | ||||
|
86 | Example output: | |||
|
87 | ||||
|
88 | .. code-block:: bash | |||
|
89 | ||||
|
90 | id : <id_given_in_input> | |||
|
91 | result : { | |||
|
92 | 'modules': [<module name>,...] | |||
|
93 | 'py_version': <python version>, | |||
|
94 | 'platform': <platform type>, | |||
|
95 | 'rhodecode_version': <rhodecode version> | |||
|
96 | } | |||
|
97 | error : null | |||
|
98 | """ | |||
|
99 | ||||
|
100 | if not has_superadmin_permission(apiuser): | |||
|
101 | raise JSONRPCForbidden() | |||
|
102 | ||||
|
103 | path = VcsSettingsModel().get_repos_location() | |||
|
104 | return {"path": path} | |||
|
105 | ||||
|
106 | ||||
|
107 | @jsonrpc_method() | |||
78 | def get_ip(request, apiuser, userid=Optional(OAttr('apiuser'))): |
|
108 | def get_ip(request, apiuser, userid=Optional(OAttr('apiuser'))): | |
79 | """ |
|
109 | """ | |
80 | Displays the IP Address as seen from the |RCE| server. |
|
110 | Displays the IP Address as seen from the |RCE| server. |
@@ -464,6 +464,7 b' def add_user_to_user_group(request, apiu' | |||||
464 | raise JSONRPCError('user group `%s` does not exist' % ( |
|
464 | raise JSONRPCError('user group `%s` does not exist' % ( | |
465 | usergroupid,)) |
|
465 | usergroupid,)) | |
466 |
|
466 | |||
|
467 | old_values = user_group.get_api_data() | |||
467 | try: |
|
468 | try: | |
468 | ugm = UserGroupModel().add_user_to_group(user_group, user) |
|
469 | ugm = UserGroupModel().add_user_to_group(user_group, user) | |
469 | success = True if ugm is not True else False |
|
470 | success = True if ugm is not True else False | |
@@ -474,7 +475,8 b' def add_user_to_user_group(request, apiu' | |||||
474 | if success: |
|
475 | if success: | |
475 | user_data = user.get_api_data() |
|
476 | user_data = user.get_api_data() | |
476 | audit_logger.store_api( |
|
477 | audit_logger.store_api( | |
477 |
'user_group.edit.member.add', |
|
478 | 'user_group.edit.member.add', | |
|
479 | action_data={'user': user_data, 'old_data': old_values}, | |||
478 | user=apiuser) |
|
480 | user=apiuser) | |
479 |
|
481 | |||
480 | Session().commit() |
|
482 | Session().commit() | |
@@ -534,6 +536,7 b' def remove_user_from_user_group(request,' | |||||
534 | raise JSONRPCError( |
|
536 | raise JSONRPCError( | |
535 | 'user group `%s` does not exist' % (usergroupid,)) |
|
537 | 'user group `%s` does not exist' % (usergroupid,)) | |
536 |
|
538 | |||
|
539 | old_values = user_group.get_api_data() | |||
537 | try: |
|
540 | try: | |
538 | success = UserGroupModel().remove_user_from_group(user_group, user) |
|
541 | success = UserGroupModel().remove_user_from_group(user_group, user) | |
539 | msg = 'removed member `%s` from user group `%s`' % ( |
|
542 | msg = 'removed member `%s` from user group `%s`' % ( | |
@@ -543,7 +546,8 b' def remove_user_from_user_group(request,' | |||||
543 | if success: |
|
546 | if success: | |
544 | user_data = user.get_api_data() |
|
547 | user_data = user.get_api_data() | |
545 | audit_logger.store_api( |
|
548 | audit_logger.store_api( | |
546 |
'user_group.edit.member.delete', |
|
549 | 'user_group.edit.member.delete', | |
|
550 | action_data={'user': user_data, 'old_data': old_values}, | |||
547 | user=apiuser) |
|
551 | user=apiuser) | |
548 |
|
552 | |||
549 | Session().commit() |
|
553 | Session().commit() |
@@ -20,16 +20,17 b'' | |||||
20 |
|
20 | |||
21 | import time |
|
21 | import time | |
22 | import logging |
|
22 | import logging | |
23 | from pylons import tmpl_context as c |
|
23 | import operator | |
|
24 | ||||
24 | from pyramid.httpexceptions import HTTPFound |
|
25 | from pyramid.httpexceptions import HTTPFound | |
25 |
|
26 | |||
26 | from rhodecode.lib import helpers as h |
|
27 | from rhodecode.lib import helpers as h | |
27 | from rhodecode.lib.utils import PartialRenderer |
|
|||
28 | from rhodecode.lib.utils2 import StrictAttributeDict, safe_int, datetime_to_time |
|
28 | from rhodecode.lib.utils2 import StrictAttributeDict, safe_int, datetime_to_time | |
29 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError |
|
29 | from rhodecode.lib.vcs.exceptions import RepositoryRequirementError | |
30 | from rhodecode.lib.ext_json import json |
|
|||
31 | from rhodecode.model import repo |
|
30 | from rhodecode.model import repo | |
32 | from rhodecode.model import repo_group |
|
31 | from rhodecode.model import repo_group | |
|
32 | from rhodecode.model import user_group | |||
|
33 | from rhodecode.model import user | |||
33 | from rhodecode.model.db import User |
|
34 | from rhodecode.model.db import User | |
34 | from rhodecode.model.scm import ScmModel |
|
35 | from rhodecode.model.scm import ScmModel | |
35 |
|
36 | |||
@@ -39,6 +40,19 b' log = logging.getLogger(__name__)' | |||||
39 | ADMIN_PREFIX = '/_admin' |
|
40 | ADMIN_PREFIX = '/_admin' | |
40 | STATIC_FILE_PREFIX = '/_static' |
|
41 | STATIC_FILE_PREFIX = '/_static' | |
41 |
|
42 | |||
|
43 | URL_NAME_REQUIREMENTS = { | |||
|
44 | # group name can have a slash in them, but they must not end with a slash | |||
|
45 | 'group_name': r'.*?[^/]', | |||
|
46 | 'repo_group_name': r'.*?[^/]', | |||
|
47 | # repo names can have a slash in them, but they must not end with a slash | |||
|
48 | 'repo_name': r'.*?[^/]', | |||
|
49 | # file path eats up everything at the end | |||
|
50 | 'f_path': r'.*', | |||
|
51 | # reference types | |||
|
52 | 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)', | |||
|
53 | 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)', | |||
|
54 | } | |||
|
55 | ||||
42 |
|
56 | |||
43 | def add_route_with_slash(config,name, pattern, **kw): |
|
57 | def add_route_with_slash(config,name, pattern, **kw): | |
44 | config.add_route(name, pattern, **kw) |
|
58 | config.add_route(name, pattern, **kw) | |
@@ -46,6 +60,17 b' def add_route_with_slash(config,name, pa' | |||||
46 | config.add_route(name + '_slash', pattern + '/', **kw) |
|
60 | config.add_route(name + '_slash', pattern + '/', **kw) | |
47 |
|
61 | |||
48 |
|
62 | |||
|
63 | def add_route_requirements(route_path, requirements=URL_NAME_REQUIREMENTS): | |||
|
64 | """ | |||
|
65 | Adds regex requirements to pyramid routes using a mapping dict | |||
|
66 | e.g:: | |||
|
67 | add_route_requirements('{repo_name}/settings') | |||
|
68 | """ | |||
|
69 | for key, regex in requirements.items(): | |||
|
70 | route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex)) | |||
|
71 | return route_path | |||
|
72 | ||||
|
73 | ||||
49 | def get_format_ref_id(repo): |
|
74 | def get_format_ref_id(repo): | |
50 | """Returns a `repo` specific reference formatter function""" |
|
75 | """Returns a `repo` specific reference formatter function""" | |
51 | if h.is_svn(repo): |
|
76 | if h.is_svn(repo): | |
@@ -105,23 +130,50 b' class BaseAppView(object):' | |||||
105 | raise HTTPFound( |
|
130 | raise HTTPFound( | |
106 | self.request.route_path('my_account_password')) |
|
131 | self.request.route_path('my_account_password')) | |
107 |
|
132 | |||
|
133 | def _log_creation_exception(self, e, repo_name): | |||
|
134 | _ = self.request.translate | |||
|
135 | reason = None | |||
|
136 | if len(e.args) == 2: | |||
|
137 | reason = e.args[1] | |||
|
138 | ||||
|
139 | if reason == 'INVALID_CERTIFICATE': | |||
|
140 | log.exception( | |||
|
141 | 'Exception creating a repository: invalid certificate') | |||
|
142 | msg = (_('Error creating repository %s: invalid certificate') | |||
|
143 | % repo_name) | |||
|
144 | else: | |||
|
145 | log.exception("Exception creating a repository") | |||
|
146 | msg = (_('Error creating repository %s') | |||
|
147 | % repo_name) | |||
|
148 | return msg | |||
|
149 | ||||
108 | def _get_local_tmpl_context(self, include_app_defaults=False): |
|
150 | def _get_local_tmpl_context(self, include_app_defaults=False): | |
109 | c = TemplateArgs() |
|
151 | c = TemplateArgs() | |
110 | c.auth_user = self.request.user |
|
152 | c.auth_user = self.request.user | |
|
153 | # TODO(marcink): migrate the usage of c.rhodecode_user to c.auth_user | |||
|
154 | c.rhodecode_user = self.request.user | |||
|
155 | ||||
111 | if include_app_defaults: |
|
156 | if include_app_defaults: | |
112 | # NOTE(marcink): after full pyramid migration include_app_defaults |
|
157 | # NOTE(marcink): after full pyramid migration include_app_defaults | |
113 | # should be turned on by default |
|
158 | # should be turned on by default | |
114 | from rhodecode.lib.base import attach_context_attributes |
|
159 | from rhodecode.lib.base import attach_context_attributes | |
115 | attach_context_attributes(c, self.request, self.request.user.user_id) |
|
160 | attach_context_attributes(c, self.request, self.request.user.user_id) | |
|
161 | ||||
116 | return c |
|
162 | return c | |
117 |
|
163 | |||
118 | def _register_global_c(self, tmpl_args): |
|
164 | def _register_global_c(self, tmpl_args): | |
119 | """ |
|
165 | """ | |
120 | Registers attributes to pylons global `c` |
|
166 | Registers attributes to pylons global `c` | |
121 | """ |
|
167 | """ | |
|
168 | ||||
122 | # TODO(marcink): remove once pyramid migration is finished |
|
169 | # TODO(marcink): remove once pyramid migration is finished | |
123 | for k, v in tmpl_args.items(): |
|
170 | from pylons import tmpl_context as c | |
124 | setattr(c, k, v) |
|
171 | try: | |
|
172 | for k, v in tmpl_args.items(): | |||
|
173 | setattr(c, k, v) | |||
|
174 | except TypeError: | |||
|
175 | log.exception('Failed to register pylons C') | |||
|
176 | pass | |||
125 |
|
177 | |||
126 | def _get_template_context(self, tmpl_args): |
|
178 | def _get_template_context(self, tmpl_args): | |
127 | self._register_global_c(tmpl_args) |
|
179 | self._register_global_c(tmpl_args) | |
@@ -129,6 +181,10 b' class BaseAppView(object):' | |||||
129 | local_tmpl_args = { |
|
181 | local_tmpl_args = { | |
130 | 'defaults': {}, |
|
182 | 'defaults': {}, | |
131 | 'errors': {}, |
|
183 | 'errors': {}, | |
|
184 | # register a fake 'c' to be used in templates instead of global | |||
|
185 | # pylons c, after migration to pyramid we should rename it to 'c' | |||
|
186 | # make sure we replace usage of _c in templates too | |||
|
187 | '_c': tmpl_args | |||
132 | } |
|
188 | } | |
133 | local_tmpl_args.update(tmpl_args) |
|
189 | local_tmpl_args.update(tmpl_args) | |
134 | return local_tmpl_args |
|
190 | return local_tmpl_args | |
@@ -160,6 +216,7 b' class RepoAppView(BaseAppView):' | |||||
160 | self.db_repo_name, error.message) |
|
216 | self.db_repo_name, error.message) | |
161 |
|
217 | |||
162 | def _get_local_tmpl_context(self, include_app_defaults=False): |
|
218 | def _get_local_tmpl_context(self, include_app_defaults=False): | |
|
219 | _ = self.request.translate | |||
163 | c = super(RepoAppView, self)._get_local_tmpl_context( |
|
220 | c = super(RepoAppView, self)._get_local_tmpl_context( | |
164 | include_app_defaults=include_app_defaults) |
|
221 | include_app_defaults=include_app_defaults) | |
165 |
|
222 | |||
@@ -174,9 +231,70 b' class RepoAppView(BaseAppView):' | |||||
174 | except RepositoryRequirementError as e: |
|
231 | except RepositoryRequirementError as e: | |
175 | c.repository_requirements_missing = True |
|
232 | c.repository_requirements_missing = True | |
176 | self._handle_missing_requirements(e) |
|
233 | self._handle_missing_requirements(e) | |
|
234 | self.rhodecode_vcs_repo = None | |||
|
235 | ||||
|
236 | if (not c.repository_requirements_missing | |||
|
237 | and self.rhodecode_vcs_repo is None): | |||
|
238 | # unable to fetch this repo as vcs instance, report back to user | |||
|
239 | h.flash(_( | |||
|
240 | "The repository `%(repo_name)s` cannot be loaded in filesystem. " | |||
|
241 | "Please check if it exist, or is not damaged.") % | |||
|
242 | {'repo_name': c.repo_name}, | |||
|
243 | category='error', ignore_duplicate=True) | |||
|
244 | raise HTTPFound(h.route_path('home')) | |||
177 |
|
245 | |||
178 | return c |
|
246 | return c | |
179 |
|
247 | |||
|
248 | def _get_f_path(self, matchdict, default=None): | |||
|
249 | f_path = matchdict.get('f_path') | |||
|
250 | if f_path: | |||
|
251 | # fix for multiple initial slashes that causes errors for GIT | |||
|
252 | return f_path.lstrip('/') | |||
|
253 | ||||
|
254 | return default | |||
|
255 | ||||
|
256 | ||||
|
257 | class RepoGroupAppView(BaseAppView): | |||
|
258 | def __init__(self, context, request): | |||
|
259 | super(RepoGroupAppView, self).__init__(context, request) | |||
|
260 | self.db_repo_group = request.db_repo_group | |||
|
261 | self.db_repo_group_name = self.db_repo_group.group_name | |||
|
262 | ||||
|
263 | def _revoke_perms_on_yourself(self, form_result): | |||
|
264 | _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), | |||
|
265 | form_result['perm_updates']) | |||
|
266 | _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), | |||
|
267 | form_result['perm_additions']) | |||
|
268 | _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]), | |||
|
269 | form_result['perm_deletions']) | |||
|
270 | admin_perm = 'group.admin' | |||
|
271 | if _updates and _updates[0][1] != admin_perm or \ | |||
|
272 | _additions and _additions[0][1] != admin_perm or \ | |||
|
273 | _deletions and _deletions[0][1] != admin_perm: | |||
|
274 | return True | |||
|
275 | return False | |||
|
276 | ||||
|
277 | ||||
|
278 | class UserGroupAppView(BaseAppView): | |||
|
279 | def __init__(self, context, request): | |||
|
280 | super(UserGroupAppView, self).__init__(context, request) | |||
|
281 | self.db_user_group = request.db_user_group | |||
|
282 | self.db_user_group_name = self.db_user_group.users_group_name | |||
|
283 | ||||
|
284 | ||||
|
285 | class UserAppView(BaseAppView): | |||
|
286 | def __init__(self, context, request): | |||
|
287 | super(UserAppView, self).__init__(context, request) | |||
|
288 | self.db_user = request.db_user | |||
|
289 | self.db_user_id = self.db_user.user_id | |||
|
290 | ||||
|
291 | _ = self.request.translate | |||
|
292 | if not request.db_user_supports_default: | |||
|
293 | if self.db_user.username == User.DEFAULT_USER: | |||
|
294 | h.flash(_("Editing user `{}` is disabled.".format( | |||
|
295 | User.DEFAULT_USER)), category='warning') | |||
|
296 | raise HTTPFound(h.route_path('users')) | |||
|
297 | ||||
180 |
|
298 | |||
181 | class DataGridAppView(object): |
|
299 | class DataGridAppView(object): | |
182 | """ |
|
300 | """ | |
@@ -203,6 +321,15 b' class DataGridAppView(object):' | |||||
203 | draw = safe_int(request.GET.get('draw')) |
|
321 | draw = safe_int(request.GET.get('draw')) | |
204 | return draw, start, length |
|
322 | return draw, start, length | |
205 |
|
323 | |||
|
324 | def _get_order_col(self, order_by, model): | |||
|
325 | if isinstance(order_by, basestring): | |||
|
326 | try: | |||
|
327 | return operator.attrgetter(order_by)(model) | |||
|
328 | except AttributeError: | |||
|
329 | return None | |||
|
330 | else: | |||
|
331 | return order_by | |||
|
332 | ||||
206 |
|
333 | |||
207 | class BaseReferencesView(RepoAppView): |
|
334 | class BaseReferencesView(RepoAppView): | |
208 | """ |
|
335 | """ | |
@@ -211,35 +338,48 b' class BaseReferencesView(RepoAppView):' | |||||
211 | def load_default_context(self): |
|
338 | def load_default_context(self): | |
212 | c = self._get_local_tmpl_context() |
|
339 | c = self._get_local_tmpl_context() | |
213 |
|
340 | |||
214 | # TODO(marcink): remove repo_info and use c.rhodecode_db_repo instead |
|
|||
215 | c.repo_info = self.db_repo |
|
|||
216 |
|
||||
217 | self._register_global_c(c) |
|
341 | self._register_global_c(c) | |
218 | return c |
|
342 | return c | |
219 |
|
343 | |||
220 | def load_refs_context(self, ref_items, partials_template): |
|
344 | def load_refs_context(self, ref_items, partials_template): | |
221 |
_render = |
|
345 | _render = self.request.get_partial_renderer(partials_template) | |
222 | _data = [] |
|
|||
223 | pre_load = ["author", "date", "message"] |
|
346 | pre_load = ["author", "date", "message"] | |
224 |
|
347 | |||
225 | is_svn = h.is_svn(self.rhodecode_vcs_repo) |
|
348 | is_svn = h.is_svn(self.rhodecode_vcs_repo) | |
|
349 | is_hg = h.is_hg(self.rhodecode_vcs_repo) | |||
|
350 | ||||
226 | format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo) |
|
351 | format_ref_id = get_format_ref_id(self.rhodecode_vcs_repo) | |
227 |
|
352 | |||
|
353 | closed_refs = {} | |||
|
354 | if is_hg: | |||
|
355 | closed_refs = self.rhodecode_vcs_repo.branches_closed | |||
|
356 | ||||
|
357 | data = [] | |||
228 | for ref_name, commit_id in ref_items: |
|
358 | for ref_name, commit_id in ref_items: | |
229 | commit = self.rhodecode_vcs_repo.get_commit( |
|
359 | commit = self.rhodecode_vcs_repo.get_commit( | |
230 | commit_id=commit_id, pre_load=pre_load) |
|
360 | commit_id=commit_id, pre_load=pre_load) | |
|
361 | closed = ref_name in closed_refs | |||
231 |
|
362 | |||
232 | # TODO: johbo: Unify generation of reference links |
|
363 | # TODO: johbo: Unify generation of reference links | |
233 | use_commit_id = '/' in ref_name or is_svn |
|
364 | use_commit_id = '/' in ref_name or is_svn | |
234 | files_url = h.url( |
|
365 | ||
235 | 'files_home', |
|
366 | if use_commit_id: | |
236 | repo_name=c.repo_name, |
|
367 | files_url = h.route_path( | |
237 | f_path=ref_name if is_svn else '', |
|
368 | 'repo_files', | |
238 | revision=commit_id if use_commit_id else ref_name, |
|
369 | repo_name=self.db_repo_name, | |
239 |
at=ref_name |
|
370 | f_path=ref_name if is_svn else '', | |
|
371 | commit_id=commit_id) | |||
240 |
|
372 | |||
241 |
|
|
373 | else: | |
242 | "name": _render('name', ref_name, files_url), |
|
374 | files_url = h.route_path( | |
|
375 | 'repo_files', | |||
|
376 | repo_name=self.db_repo_name, | |||
|
377 | f_path=ref_name if is_svn else '', | |||
|
378 | commit_id=ref_name, | |||
|
379 | _query=dict(at=ref_name)) | |||
|
380 | ||||
|
381 | data.append({ | |||
|
382 | "name": _render('name', ref_name, files_url, closed), | |||
243 | "name_raw": ref_name, |
|
383 | "name_raw": ref_name, | |
244 | "date": _render('date', commit.date), |
|
384 | "date": _render('date', commit.date), | |
245 | "date_raw": datetime_to_time(commit.date), |
|
385 | "date_raw": datetime_to_time(commit.date), | |
@@ -250,8 +390,8 b' class BaseReferencesView(RepoAppView):' | |||||
250 | "compare": _render( |
|
390 | "compare": _render( | |
251 | 'compare', format_ref_id(ref_name, commit.raw_id)), |
|
391 | 'compare', format_ref_id(ref_name, commit.raw_id)), | |
252 | }) |
|
392 | }) | |
253 | c.has_references = bool(_data) |
|
393 | ||
254 | c.data = json.dumps(_data) |
|
394 | return data | |
255 |
|
395 | |||
256 |
|
396 | |||
257 | class RepoRoutePredicate(object): |
|
397 | class RepoRoutePredicate(object): | |
@@ -273,14 +413,22 b' class RepoRoutePredicate(object):' | |||||
273 | repo_model = repo.RepoModel() |
|
413 | repo_model = repo.RepoModel() | |
274 | by_name_match = repo_model.get_by_repo_name(repo_name, cache=True) |
|
414 | by_name_match = repo_model.get_by_repo_name(repo_name, cache=True) | |
275 |
|
415 | |||
|
416 | def redirect_if_creating(db_repo): | |||
|
417 | if db_repo.repo_state in [repo.Repository.STATE_PENDING]: | |||
|
418 | raise HTTPFound( | |||
|
419 | request.route_path('repo_creating', | |||
|
420 | repo_name=db_repo.repo_name)) | |||
|
421 | ||||
276 | if by_name_match: |
|
422 | if by_name_match: | |
277 | # register this as request object we can re-use later |
|
423 | # register this as request object we can re-use later | |
278 | request.db_repo = by_name_match |
|
424 | request.db_repo = by_name_match | |
|
425 | redirect_if_creating(by_name_match) | |||
279 | return True |
|
426 | return True | |
280 |
|
427 | |||
281 | by_id_match = repo_model.get_repo_by_id(repo_name) |
|
428 | by_id_match = repo_model.get_repo_by_id(repo_name) | |
282 | if by_id_match: |
|
429 | if by_id_match: | |
283 | request.db_repo = by_id_match |
|
430 | request.db_repo = by_id_match | |
|
431 | redirect_if_creating(by_id_match) | |||
284 | return True |
|
432 | return True | |
285 |
|
433 | |||
286 | return False |
|
434 | return False | |
@@ -348,6 +496,79 b' class RepoGroupRoutePredicate(object):' | |||||
348 | return False |
|
496 | return False | |
349 |
|
497 | |||
350 |
|
498 | |||
|
499 | class UserGroupRoutePredicate(object): | |||
|
500 | def __init__(self, val, config): | |||
|
501 | self.val = val | |||
|
502 | ||||
|
503 | def text(self): | |||
|
504 | return 'user_group_route = %s' % self.val | |||
|
505 | ||||
|
506 | phash = text | |||
|
507 | ||||
|
508 | def __call__(self, info, request): | |||
|
509 | if hasattr(request, 'vcs_call'): | |||
|
510 | # skip vcs calls | |||
|
511 | return | |||
|
512 | ||||
|
513 | user_group_id = info['match']['user_group_id'] | |||
|
514 | user_group_model = user_group.UserGroup() | |||
|
515 | by_id_match = user_group_model.get( | |||
|
516 | user_group_id, cache=True) | |||
|
517 | ||||
|
518 | if by_id_match: | |||
|
519 | # register this as request object we can re-use later | |||
|
520 | request.db_user_group = by_id_match | |||
|
521 | return True | |||
|
522 | ||||
|
523 | return False | |||
|
524 | ||||
|
525 | ||||
|
526 | class UserRoutePredicateBase(object): | |||
|
527 | supports_default = None | |||
|
528 | ||||
|
529 | def __init__(self, val, config): | |||
|
530 | self.val = val | |||
|
531 | ||||
|
532 | def text(self): | |||
|
533 | raise NotImplementedError() | |||
|
534 | ||||
|
535 | def __call__(self, info, request): | |||
|
536 | if hasattr(request, 'vcs_call'): | |||
|
537 | # skip vcs calls | |||
|
538 | return | |||
|
539 | ||||
|
540 | user_id = info['match']['user_id'] | |||
|
541 | user_model = user.User() | |||
|
542 | by_id_match = user_model.get( | |||
|
543 | user_id, cache=True) | |||
|
544 | ||||
|
545 | if by_id_match: | |||
|
546 | # register this as request object we can re-use later | |||
|
547 | request.db_user = by_id_match | |||
|
548 | request.db_user_supports_default = self.supports_default | |||
|
549 | return True | |||
|
550 | ||||
|
551 | return False | |||
|
552 | ||||
|
553 | ||||
|
554 | class UserRoutePredicate(UserRoutePredicateBase): | |||
|
555 | supports_default = False | |||
|
556 | ||||
|
557 | def text(self): | |||
|
558 | return 'user_route = %s' % self.val | |||
|
559 | ||||
|
560 | phash = text | |||
|
561 | ||||
|
562 | ||||
|
563 | class UserRouteWithDefaultPredicate(UserRoutePredicateBase): | |||
|
564 | supports_default = True | |||
|
565 | ||||
|
566 | def text(self): | |||
|
567 | return 'user_with_default_route = %s' % self.val | |||
|
568 | ||||
|
569 | phash = text | |||
|
570 | ||||
|
571 | ||||
351 | def includeme(config): |
|
572 | def includeme(config): | |
352 | config.add_route_predicate( |
|
573 | config.add_route_predicate( | |
353 | 'repo_route', RepoRoutePredicate) |
|
574 | 'repo_route', RepoRoutePredicate) | |
@@ -355,3 +576,9 b' def includeme(config):' | |||||
355 | 'repo_accepted_types', RepoTypeRoutePredicate) |
|
576 | 'repo_accepted_types', RepoTypeRoutePredicate) | |
356 | config.add_route_predicate( |
|
577 | config.add_route_predicate( | |
357 | 'repo_group_route', RepoGroupRoutePredicate) |
|
578 | 'repo_group_route', RepoGroupRoutePredicate) | |
|
579 | config.add_route_predicate( | |||
|
580 | 'user_group_route', UserGroupRoutePredicate) | |||
|
581 | config.add_route_predicate( | |||
|
582 | 'user_route_with_default', UserRouteWithDefaultPredicate) | |||
|
583 | config.add_route_predicate( | |||
|
584 | 'user_route', UserRoutePredicate) No newline at end of file |
@@ -34,14 +34,18 b' def admin_routes(config):' | |||||
34 | pattern='/audit_logs') |
|
34 | pattern='/audit_logs') | |
35 |
|
35 | |||
36 | config.add_route( |
|
36 | config.add_route( | |
|
37 | name='admin_audit_log_entry', | |||
|
38 | pattern='/audit_logs/{audit_log_id}') | |||
|
39 | ||||
|
40 | config.add_route( | |||
37 | name='pull_requests_global_0', # backward compat |
|
41 | name='pull_requests_global_0', # backward compat | |
38 |
pattern='/pull_requests/{pull_request_id: |
|
42 | pattern='/pull_requests/{pull_request_id:\d+}') | |
39 | config.add_route( |
|
43 | config.add_route( | |
40 | name='pull_requests_global_1', # backward compat |
|
44 | name='pull_requests_global_1', # backward compat | |
41 |
pattern='/pull-requests/{pull_request_id: |
|
45 | pattern='/pull-requests/{pull_request_id:\d+}') | |
42 | config.add_route( |
|
46 | config.add_route( | |
43 | name='pull_requests_global', |
|
47 | name='pull_requests_global', | |
44 |
pattern='/pull-request/{pull_request_id: |
|
48 | pattern='/pull-request/{pull_request_id:\d+}') | |
45 |
|
49 | |||
46 | config.add_route( |
|
50 | config.add_route( | |
47 | name='admin_settings_open_source', |
|
51 | name='admin_settings_open_source', | |
@@ -64,11 +68,66 b' def admin_routes(config):' | |||||
64 | name='admin_settings_sessions_cleanup', |
|
68 | name='admin_settings_sessions_cleanup', | |
65 | pattern='/settings/sessions/cleanup') |
|
69 | pattern='/settings/sessions/cleanup') | |
66 |
|
70 | |||
|
71 | config.add_route( | |||
|
72 | name='admin_settings_process_management', | |||
|
73 | pattern='/settings/process_management') | |||
|
74 | config.add_route( | |||
|
75 | name='admin_settings_process_management_signal', | |||
|
76 | pattern='/settings/process_management/signal') | |||
|
77 | ||||
|
78 | # default settings | |||
|
79 | config.add_route( | |||
|
80 | name='admin_defaults_repositories', | |||
|
81 | pattern='/defaults/repositories') | |||
|
82 | config.add_route( | |||
|
83 | name='admin_defaults_repositories_update', | |||
|
84 | pattern='/defaults/repositories/update') | |||
|
85 | ||||
67 | # global permissions |
|
86 | # global permissions | |
|
87 | ||||
|
88 | config.add_route( | |||
|
89 | name='admin_permissions_application', | |||
|
90 | pattern='/permissions/application') | |||
|
91 | config.add_route( | |||
|
92 | name='admin_permissions_application_update', | |||
|
93 | pattern='/permissions/application/update') | |||
|
94 | ||||
|
95 | config.add_route( | |||
|
96 | name='admin_permissions_global', | |||
|
97 | pattern='/permissions/global') | |||
|
98 | config.add_route( | |||
|
99 | name='admin_permissions_global_update', | |||
|
100 | pattern='/permissions/global/update') | |||
|
101 | ||||
|
102 | config.add_route( | |||
|
103 | name='admin_permissions_object', | |||
|
104 | pattern='/permissions/object') | |||
|
105 | config.add_route( | |||
|
106 | name='admin_permissions_object_update', | |||
|
107 | pattern='/permissions/object/update') | |||
|
108 | ||||
68 | config.add_route( |
|
109 | config.add_route( | |
69 | name='admin_permissions_ips', |
|
110 | name='admin_permissions_ips', | |
70 | pattern='/permissions/ips') |
|
111 | pattern='/permissions/ips') | |
71 |
|
112 | |||
|
113 | config.add_route( | |||
|
114 | name='admin_permissions_overview', | |||
|
115 | pattern='/permissions/overview') | |||
|
116 | ||||
|
117 | config.add_route( | |||
|
118 | name='admin_permissions_auth_token_access', | |||
|
119 | pattern='/permissions/auth_token_access') | |||
|
120 | ||||
|
121 | config.add_route( | |||
|
122 | name='admin_permissions_ssh_keys', | |||
|
123 | pattern='/permissions/ssh_keys') | |||
|
124 | config.add_route( | |||
|
125 | name='admin_permissions_ssh_keys_data', | |||
|
126 | pattern='/permissions/ssh_keys/data') | |||
|
127 | config.add_route( | |||
|
128 | name='admin_permissions_ssh_keys_update', | |||
|
129 | pattern='/permissions/ssh_keys/update') | |||
|
130 | ||||
72 | # users admin |
|
131 | # users admin | |
73 | config.add_route( |
|
132 | config.add_route( | |
74 | name='users', |
|
133 | name='users', | |
@@ -78,52 +137,176 b' def admin_routes(config):' | |||||
78 | name='users_data', |
|
137 | name='users_data', | |
79 | pattern='/users_data') |
|
138 | pattern='/users_data') | |
80 |
|
139 | |||
|
140 | config.add_route( | |||
|
141 | name='users_create', | |||
|
142 | pattern='/users/create') | |||
|
143 | ||||
|
144 | config.add_route( | |||
|
145 | name='users_new', | |||
|
146 | pattern='/users/new') | |||
|
147 | ||||
|
148 | # user management | |||
|
149 | config.add_route( | |||
|
150 | name='user_edit', | |||
|
151 | pattern='/users/{user_id:\d+}/edit', | |||
|
152 | user_route=True) | |||
|
153 | config.add_route( | |||
|
154 | name='user_edit_advanced', | |||
|
155 | pattern='/users/{user_id:\d+}/edit/advanced', | |||
|
156 | user_route=True) | |||
|
157 | config.add_route( | |||
|
158 | name='user_edit_global_perms', | |||
|
159 | pattern='/users/{user_id:\d+}/edit/global_permissions', | |||
|
160 | user_route=True) | |||
|
161 | config.add_route( | |||
|
162 | name='user_edit_global_perms_update', | |||
|
163 | pattern='/users/{user_id:\d+}/edit/global_permissions/update', | |||
|
164 | user_route=True) | |||
|
165 | config.add_route( | |||
|
166 | name='user_update', | |||
|
167 | pattern='/users/{user_id:\d+}/update', | |||
|
168 | user_route=True) | |||
|
169 | config.add_route( | |||
|
170 | name='user_delete', | |||
|
171 | pattern='/users/{user_id:\d+}/delete', | |||
|
172 | user_route=True) | |||
|
173 | config.add_route( | |||
|
174 | name='user_force_password_reset', | |||
|
175 | pattern='/users/{user_id:\d+}/password_reset', | |||
|
176 | user_route=True) | |||
|
177 | config.add_route( | |||
|
178 | name='user_create_personal_repo_group', | |||
|
179 | pattern='/users/{user_id:\d+}/create_repo_group', | |||
|
180 | user_route=True) | |||
|
181 | ||||
81 | # user auth tokens |
|
182 | # user auth tokens | |
82 | config.add_route( |
|
183 | config.add_route( | |
83 | name='edit_user_auth_tokens', |
|
184 | name='edit_user_auth_tokens', | |
84 |
pattern='/users/{user_id:\d+}/edit/auth_tokens' |
|
185 | pattern='/users/{user_id:\d+}/edit/auth_tokens', | |
|
186 | user_route=True) | |||
85 | config.add_route( |
|
187 | config.add_route( | |
86 | name='edit_user_auth_tokens_add', |
|
188 | name='edit_user_auth_tokens_add', | |
87 |
pattern='/users/{user_id:\d+}/edit/auth_tokens/new' |
|
189 | pattern='/users/{user_id:\d+}/edit/auth_tokens/new', | |
|
190 | user_route=True) | |||
88 | config.add_route( |
|
191 | config.add_route( | |
89 | name='edit_user_auth_tokens_delete', |
|
192 | name='edit_user_auth_tokens_delete', | |
90 |
pattern='/users/{user_id:\d+}/edit/auth_tokens/delete' |
|
193 | pattern='/users/{user_id:\d+}/edit/auth_tokens/delete', | |
|
194 | user_route=True) | |||
|
195 | ||||
|
196 | # user ssh keys | |||
|
197 | config.add_route( | |||
|
198 | name='edit_user_ssh_keys', | |||
|
199 | pattern='/users/{user_id:\d+}/edit/ssh_keys', | |||
|
200 | user_route=True) | |||
|
201 | config.add_route( | |||
|
202 | name='edit_user_ssh_keys_generate_keypair', | |||
|
203 | pattern='/users/{user_id:\d+}/edit/ssh_keys/generate', | |||
|
204 | user_route=True) | |||
|
205 | config.add_route( | |||
|
206 | name='edit_user_ssh_keys_add', | |||
|
207 | pattern='/users/{user_id:\d+}/edit/ssh_keys/new', | |||
|
208 | user_route=True) | |||
|
209 | config.add_route( | |||
|
210 | name='edit_user_ssh_keys_delete', | |||
|
211 | pattern='/users/{user_id:\d+}/edit/ssh_keys/delete', | |||
|
212 | user_route=True) | |||
91 |
|
213 | |||
92 | # user emails |
|
214 | # user emails | |
93 | config.add_route( |
|
215 | config.add_route( | |
94 | name='edit_user_emails', |
|
216 | name='edit_user_emails', | |
95 |
pattern='/users/{user_id:\d+}/edit/emails' |
|
217 | pattern='/users/{user_id:\d+}/edit/emails', | |
|
218 | user_route=True) | |||
96 | config.add_route( |
|
219 | config.add_route( | |
97 | name='edit_user_emails_add', |
|
220 | name='edit_user_emails_add', | |
98 |
pattern='/users/{user_id:\d+}/edit/emails/new' |
|
221 | pattern='/users/{user_id:\d+}/edit/emails/new', | |
|
222 | user_route=True) | |||
99 | config.add_route( |
|
223 | config.add_route( | |
100 | name='edit_user_emails_delete', |
|
224 | name='edit_user_emails_delete', | |
101 |
pattern='/users/{user_id:\d+}/edit/emails/delete' |
|
225 | pattern='/users/{user_id:\d+}/edit/emails/delete', | |
|
226 | user_route=True) | |||
102 |
|
227 | |||
103 | # user IPs |
|
228 | # user IPs | |
104 | config.add_route( |
|
229 | config.add_route( | |
105 | name='edit_user_ips', |
|
230 | name='edit_user_ips', | |
106 |
pattern='/users/{user_id:\d+}/edit/ips' |
|
231 | pattern='/users/{user_id:\d+}/edit/ips', | |
|
232 | user_route=True) | |||
107 | config.add_route( |
|
233 | config.add_route( | |
108 | name='edit_user_ips_add', |
|
234 | name='edit_user_ips_add', | |
109 |
pattern='/users/{user_id:\d+}/edit/ips/new' |
|
235 | pattern='/users/{user_id:\d+}/edit/ips/new', | |
|
236 | user_route_with_default=True) # enabled for default user too | |||
110 | config.add_route( |
|
237 | config.add_route( | |
111 | name='edit_user_ips_delete', |
|
238 | name='edit_user_ips_delete', | |
112 |
pattern='/users/{user_id:\d+}/edit/ips/delete' |
|
239 | pattern='/users/{user_id:\d+}/edit/ips/delete', | |
|
240 | user_route_with_default=True) # enabled for default user too | |||
113 |
|
241 | |||
114 | # user groups management |
|
242 | # user perms | |
|
243 | config.add_route( | |||
|
244 | name='edit_user_perms_summary', | |||
|
245 | pattern='/users/{user_id:\d+}/edit/permissions_summary', | |||
|
246 | user_route=True) | |||
|
247 | config.add_route( | |||
|
248 | name='edit_user_perms_summary_json', | |||
|
249 | pattern='/users/{user_id:\d+}/edit/permissions_summary/json', | |||
|
250 | user_route=True) | |||
|
251 | ||||
|
252 | # user user groups management | |||
115 | config.add_route( |
|
253 | config.add_route( | |
116 | name='edit_user_groups_management', |
|
254 | name='edit_user_groups_management', | |
117 |
pattern='/users/{user_id:\d+}/edit/groups_management' |
|
255 | pattern='/users/{user_id:\d+}/edit/groups_management', | |
|
256 | user_route=True) | |||
118 |
|
257 | |||
119 | config.add_route( |
|
258 | config.add_route( | |
120 | name='edit_user_groups_management_updates', |
|
259 | name='edit_user_groups_management_updates', | |
121 |
pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates' |
|
260 | pattern='/users/{user_id:\d+}/edit/edit_user_groups_management/updates', | |
|
261 | user_route=True) | |||
122 |
|
262 | |||
123 | # user audit logs |
|
263 | # user audit logs | |
124 | config.add_route( |
|
264 | config.add_route( | |
125 | name='edit_user_audit_logs', |
|
265 | name='edit_user_audit_logs', | |
126 | pattern='/users/{user_id:\d+}/edit/audit') |
|
266 | pattern='/users/{user_id:\d+}/edit/audit', user_route=True) | |
|
267 | ||||
|
268 | # user-groups admin | |||
|
269 | config.add_route( | |||
|
270 | name='user_groups', | |||
|
271 | pattern='/user_groups') | |||
|
272 | ||||
|
273 | config.add_route( | |||
|
274 | name='user_groups_data', | |||
|
275 | pattern='/user_groups_data') | |||
|
276 | ||||
|
277 | config.add_route( | |||
|
278 | name='user_groups_new', | |||
|
279 | pattern='/user_groups/new') | |||
|
280 | ||||
|
281 | config.add_route( | |||
|
282 | name='user_groups_create', | |||
|
283 | pattern='/user_groups/create') | |||
|
284 | ||||
|
285 | # repos admin | |||
|
286 | config.add_route( | |||
|
287 | name='repos', | |||
|
288 | pattern='/repos') | |||
|
289 | ||||
|
290 | config.add_route( | |||
|
291 | name='repo_new', | |||
|
292 | pattern='/repos/new') | |||
|
293 | ||||
|
294 | config.add_route( | |||
|
295 | name='repo_create', | |||
|
296 | pattern='/repos/create') | |||
|
297 | ||||
|
298 | # repo groups admin | |||
|
299 | config.add_route( | |||
|
300 | name='repo_groups', | |||
|
301 | pattern='/repo_groups') | |||
|
302 | ||||
|
303 | config.add_route( | |||
|
304 | name='repo_group_new', | |||
|
305 | pattern='/repo_group/new') | |||
|
306 | ||||
|
307 | config.add_route( | |||
|
308 | name='repo_group_create', | |||
|
309 | pattern='/repo_group/create') | |||
127 |
|
310 | |||
128 |
|
311 | |||
129 | def includeme(config): |
|
312 | def includeme(config): | |
@@ -139,4 +322,4 b' def includeme(config):' | |||||
139 | config.include(admin_routes, route_prefix=ADMIN_PREFIX) |
|
322 | config.include(admin_routes, route_prefix=ADMIN_PREFIX) | |
140 |
|
323 | |||
141 | # Scan module for configuration decorators. |
|
324 | # Scan module for configuration decorators. | |
142 | config.scan() |
|
325 | config.scan('.views', ignore='.tests') |
@@ -22,7 +22,6 b'' | |||||
22 | import logging |
|
22 | import logging | |
23 | import collections |
|
23 | import collections | |
24 |
|
24 | |||
25 | from pylons import url |
|
|||
26 | from zope.interface import implementer |
|
25 | from zope.interface import implementer | |
27 |
|
26 | |||
28 | from rhodecode.apps.admin.interfaces import IAdminNavigationRegistry |
|
27 | from rhodecode.apps.admin.interfaces import IAdminNavigationRegistry | |
@@ -64,6 +63,7 b' class NavEntry(object):' | |||||
64 | pyramid_request = get_current_request() |
|
63 | pyramid_request = get_current_request() | |
65 | return pyramid_request.route_path(self.view_name) |
|
64 | return pyramid_request.route_path(self.view_name) | |
66 | else: |
|
65 | else: | |
|
66 | from pylons import url | |||
67 | return url(self.view_name) |
|
67 | return url(self.view_name) | |
68 |
|
68 | |||
69 | def get_localized_name(self, request): |
|
69 | def get_localized_name(self, request): | |
@@ -94,6 +94,8 b' class NavigationRegistry(object):' | |||||
94 | 'global_integrations_home', pyramid=True), |
|
94 | 'global_integrations_home', pyramid=True), | |
95 | NavEntry('system', _('System Info'), |
|
95 | NavEntry('system', _('System Info'), | |
96 | 'admin_settings_system', pyramid=True), |
|
96 | 'admin_settings_system', pyramid=True), | |
|
97 | NavEntry('process_management', _('Processes'), | |||
|
98 | 'admin_settings_process_management', pyramid=True), | |||
97 | NavEntry('sessions', _('User Sessions'), |
|
99 | NavEntry('sessions', _('User Sessions'), | |
98 | 'admin_settings_sessions', pyramid=True), |
|
100 | 'admin_settings_sessions', pyramid=True), | |
99 | NavEntry('open_source', _('Open Source Licenses'), |
|
101 | NavEntry('open_source', _('Open Source Licenses'), |
@@ -20,15 +20,31 b'' | |||||
20 |
|
20 | |||
21 | import pytest |
|
21 | import pytest | |
22 |
|
22 | |||
23 |
from rhodecode.tests import assert_session_flash |
|
23 | from rhodecode.tests import assert_session_flash | |
24 | from rhodecode.model.settings import SettingsModel |
|
24 | from rhodecode.model.settings import SettingsModel | |
25 |
|
25 | |||
26 |
|
26 | |||
|
27 | def route_path(name, params=None, **kwargs): | |||
|
28 | import urllib | |||
|
29 | from rhodecode.apps._base import ADMIN_PREFIX | |||
|
30 | ||||
|
31 | base_url = { | |||
|
32 | 'admin_defaults_repositories': | |||
|
33 | ADMIN_PREFIX + '/defaults/repositories', | |||
|
34 | 'admin_defaults_repositories_update': | |||
|
35 | ADMIN_PREFIX + '/defaults/repositories/update', | |||
|
36 | }[name].format(**kwargs) | |||
|
37 | ||||
|
38 | if params: | |||
|
39 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |||
|
40 | return base_url | |||
|
41 | ||||
|
42 | ||||
27 | @pytest.mark.usefixtures("app") |
|
43 | @pytest.mark.usefixtures("app") | |
28 |
class TestDefaults |
|
44 | class TestDefaultsView(object): | |
29 |
|
45 | |||
30 | def test_index(self, autologin_user): |
|
46 | def test_index(self, autologin_user): | |
31 |
response = self.app.get( |
|
47 | response = self.app.get(route_path('admin_defaults_repositories')) | |
32 | response.mustcontain('default_repo_private') |
|
48 | response.mustcontain('default_repo_private') | |
33 | response.mustcontain('default_repo_enable_statistics') |
|
49 | response.mustcontain('default_repo_enable_statistics') | |
34 | response.mustcontain('default_repo_enable_downloads') |
|
50 | response.mustcontain('default_repo_enable_downloads') | |
@@ -44,7 +60,7 b' class TestDefaultsController:' | |||||
44 | 'csrf_token': csrf_token, |
|
60 | 'csrf_token': csrf_token, | |
45 | } |
|
61 | } | |
46 | response = self.app.post( |
|
62 | response = self.app.post( | |
47 |
|
|
63 | route_path('admin_defaults_repositories_update'), params=params) | |
48 | assert_session_flash(response, 'Default settings updated successfully') |
|
64 | assert_session_flash(response, 'Default settings updated successfully') | |
49 |
|
65 | |||
50 | defs = SettingsModel().get_default_repo_settings() |
|
66 | defs = SettingsModel().get_default_repo_settings() | |
@@ -61,8 +77,9 b' class TestDefaultsController:' | |||||
61 | 'csrf_token': csrf_token, |
|
77 | 'csrf_token': csrf_token, | |
62 | } |
|
78 | } | |
63 | response = self.app.post( |
|
79 | response = self.app.post( | |
64 |
|
|
80 | route_path('admin_defaults_repositories_update'), params=params) | |
65 | assert_session_flash(response, 'Default settings updated successfully') |
|
81 | assert_session_flash(response, 'Default settings updated successfully') | |
|
82 | ||||
66 | defs = SettingsModel().get_default_repo_settings() |
|
83 | defs = SettingsModel().get_default_repo_settings() | |
67 | del params['csrf_token'] |
|
84 | del params['csrf_token'] | |
68 | assert params == defs |
|
85 | assert params == defs |
@@ -18,11 +18,14 b'' | |||||
18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
|
21 | import mock | |||
21 | import pytest |
|
22 | import pytest | |
22 | from rhodecode.model.db import User, UserIpMap |
|
23 | from rhodecode.model.db import User, UserIpMap | |
|
24 | from rhodecode.model.meta import Session | |||
23 | from rhodecode.model.permission import PermissionModel |
|
25 | from rhodecode.model.permission import PermissionModel | |
|
26 | from rhodecode.model.ssh_key import SshKeyModel | |||
24 | from rhodecode.tests import ( |
|
27 | from rhodecode.tests import ( | |
25 |
TestController |
|
28 | TestController, clear_all_caches, assert_session_flash) | |
26 |
|
29 | |||
27 |
|
30 | |||
28 | def route_path(name, params=None, **kwargs): |
|
31 | def route_path(name, params=None, **kwargs): | |
@@ -36,6 +39,34 b' def route_path(name, params=None, **kwar' | |||||
36 | ADMIN_PREFIX + '/users/{user_id}/edit/ips/new', |
|
39 | ADMIN_PREFIX + '/users/{user_id}/edit/ips/new', | |
37 | 'edit_user_ips_delete': |
|
40 | 'edit_user_ips_delete': | |
38 | ADMIN_PREFIX + '/users/{user_id}/edit/ips/delete', |
|
41 | ADMIN_PREFIX + '/users/{user_id}/edit/ips/delete', | |
|
42 | ||||
|
43 | 'admin_permissions_application': | |||
|
44 | ADMIN_PREFIX + '/permissions/application', | |||
|
45 | 'admin_permissions_application_update': | |||
|
46 | ADMIN_PREFIX + '/permissions/application/update', | |||
|
47 | ||||
|
48 | 'admin_permissions_global': | |||
|
49 | ADMIN_PREFIX + '/permissions/global', | |||
|
50 | 'admin_permissions_global_update': | |||
|
51 | ADMIN_PREFIX + '/permissions/global/update', | |||
|
52 | ||||
|
53 | 'admin_permissions_object': | |||
|
54 | ADMIN_PREFIX + '/permissions/object', | |||
|
55 | 'admin_permissions_object_update': | |||
|
56 | ADMIN_PREFIX + '/permissions/object/update', | |||
|
57 | ||||
|
58 | 'admin_permissions_ips': | |||
|
59 | ADMIN_PREFIX + '/permissions/ips', | |||
|
60 | 'admin_permissions_overview': | |||
|
61 | ADMIN_PREFIX + '/permissions/overview', | |||
|
62 | ||||
|
63 | 'admin_permissions_ssh_keys': | |||
|
64 | ADMIN_PREFIX + '/permissions/ssh_keys', | |||
|
65 | 'admin_permissions_ssh_keys_data': | |||
|
66 | ADMIN_PREFIX + '/permissions/ssh_keys/data', | |||
|
67 | 'admin_permissions_ssh_keys_update': | |||
|
68 | ADMIN_PREFIX + '/permissions/ssh_keys/update' | |||
|
69 | ||||
39 | }[name].format(**kwargs) |
|
70 | }[name].format(**kwargs) | |
40 |
|
71 | |||
41 | if params: |
|
72 | if params: | |
@@ -55,7 +86,7 b' class TestAdminPermissionsController(Tes' | |||||
55 |
|
86 | |||
56 | def test_index_application(self): |
|
87 | def test_index_application(self): | |
57 | self.log_user() |
|
88 | self.log_user() | |
58 |
self.app.get( |
|
89 | self.app.get(route_path('admin_permissions_application')) | |
59 |
|
90 | |||
60 | @pytest.mark.parametrize( |
|
91 | @pytest.mark.parametrize( | |
61 | 'anonymous, default_register, default_register_message, default_password_reset,' |
|
92 | 'anonymous, default_register, default_register_message, default_password_reset,' | |
@@ -87,7 +118,7 b' class TestAdminPermissionsController(Tes' | |||||
87 | 'default_password_reset': default_password_reset, |
|
118 | 'default_password_reset': default_password_reset, | |
88 | 'default_extern_activate': default_extern_activate, |
|
119 | 'default_extern_activate': default_extern_activate, | |
89 | } |
|
120 | } | |
90 |
response = self.app.post( |
|
121 | response = self.app.post(route_path('admin_permissions_application_update'), | |
91 | params=params) |
|
122 | params=params) | |
92 | if expect_form_error: |
|
123 | if expect_form_error: | |
93 | assert response.status_int == 200 |
|
124 | assert response.status_int == 200 | |
@@ -101,7 +132,7 b' class TestAdminPermissionsController(Tes' | |||||
101 |
|
132 | |||
102 | def test_index_object(self): |
|
133 | def test_index_object(self): | |
103 | self.log_user() |
|
134 | self.log_user() | |
104 |
self.app.get( |
|
135 | self.app.get(route_path('admin_permissions_object')) | |
105 |
|
136 | |||
106 | @pytest.mark.parametrize( |
|
137 | @pytest.mark.parametrize( | |
107 | 'repo, repo_group, user_group, expect_error, expect_form_error', [ |
|
138 | 'repo, repo_group, user_group, expect_error, expect_form_error', [ | |
@@ -127,7 +158,7 b' class TestAdminPermissionsController(Tes' | |||||
127 | 'default_user_group_perm': user_group, |
|
158 | 'default_user_group_perm': user_group, | |
128 | 'overwrite_default_user_group': False, |
|
159 | 'overwrite_default_user_group': False, | |
129 | } |
|
160 | } | |
130 |
response = self.app.post( |
|
161 | response = self.app.post(route_path('admin_permissions_object_update'), | |
131 | params=params) |
|
162 | params=params) | |
132 | if expect_form_error: |
|
163 | if expect_form_error: | |
133 | assert response.status_int == 200 |
|
164 | assert response.status_int == 200 | |
@@ -141,7 +172,7 b' class TestAdminPermissionsController(Tes' | |||||
141 |
|
172 | |||
142 | def test_index_global(self): |
|
173 | def test_index_global(self): | |
143 | self.log_user() |
|
174 | self.log_user() | |
144 |
self.app.get( |
|
175 | self.app.get(route_path('admin_permissions_global')) | |
145 |
|
176 | |||
146 | @pytest.mark.parametrize( |
|
177 | @pytest.mark.parametrize( | |
147 | 'repo_create, repo_create_write, user_group_create, repo_group_create,' |
|
178 | 'repo_create, repo_create_write, user_group_create, repo_group_create,' | |
@@ -175,7 +206,7 b' class TestAdminPermissionsController(Tes' | |||||
175 | 'default_fork_create': fork_create, |
|
206 | 'default_fork_create': fork_create, | |
176 | 'default_inherit_default_permissions': inherit_default_permissions |
|
207 | 'default_inherit_default_permissions': inherit_default_permissions | |
177 | } |
|
208 | } | |
178 |
response = self.app.post( |
|
209 | response = self.app.post(route_path('admin_permissions_global_update'), | |
179 | params=params) |
|
210 | params=params) | |
180 | if expect_form_error: |
|
211 | if expect_form_error: | |
181 | assert response.status_int == 200 |
|
212 | assert response.status_int == 200 | |
@@ -189,7 +220,7 b' class TestAdminPermissionsController(Tes' | |||||
189 |
|
220 | |||
190 | def test_index_ips(self): |
|
221 | def test_index_ips(self): | |
191 | self.log_user() |
|
222 | self.log_user() | |
192 |
response = self.app.get( |
|
223 | response = self.app.get(route_path('admin_permissions_ips')) | |
193 | # TODO: Test response... |
|
224 | # TODO: Test response... | |
194 | response.mustcontain('All IP addresses are allowed') |
|
225 | response.mustcontain('All IP addresses are allowed') | |
195 |
|
226 | |||
@@ -203,7 +234,7 b' class TestAdminPermissionsController(Tes' | |||||
203 | route_path('edit_user_ips_add', user_id=default_user_id), |
|
234 | route_path('edit_user_ips_add', user_id=default_user_id), | |
204 | params={'new_ip': '127.0.0.0/24', 'csrf_token': self.csrf_token}) |
|
235 | params={'new_ip': '127.0.0.0/24', 'csrf_token': self.csrf_token}) | |
205 |
|
236 | |||
206 |
response = self.app.get( |
|
237 | response = self.app.get(route_path('admin_permissions_ips')) | |
207 | response.mustcontain('127.0.0.0/24') |
|
238 | response.mustcontain('127.0.0.0/24') | |
208 | response.mustcontain('127.0.0.0 - 127.0.0.255') |
|
239 | response.mustcontain('127.0.0.0 - 127.0.0.255') | |
209 |
|
240 | |||
@@ -219,11 +250,51 b' class TestAdminPermissionsController(Tes' | |||||
219 | assert_session_flash(response, 'Removed ip address from user whitelist') |
|
250 | assert_session_flash(response, 'Removed ip address from user whitelist') | |
220 |
|
251 | |||
221 | clear_all_caches() |
|
252 | clear_all_caches() | |
222 |
response = self.app.get( |
|
253 | response = self.app.get(route_path('admin_permissions_ips')) | |
223 | response.mustcontain('All IP addresses are allowed') |
|
254 | response.mustcontain('All IP addresses are allowed') | |
224 | response.mustcontain(no=['127.0.0.0/24']) |
|
255 | response.mustcontain(no=['127.0.0.0/24']) | |
225 | response.mustcontain(no=['127.0.0.0 - 127.0.0.255']) |
|
256 | response.mustcontain(no=['127.0.0.0 - 127.0.0.255']) | |
226 |
|
257 | |||
227 | def test_index_overview(self): |
|
258 | def test_index_overview(self): | |
228 | self.log_user() |
|
259 | self.log_user() | |
229 |
self.app.get( |
|
260 | self.app.get(route_path('admin_permissions_overview')) | |
|
261 | ||||
|
262 | def test_ssh_keys(self): | |||
|
263 | self.log_user() | |||
|
264 | self.app.get(route_path('admin_permissions_ssh_keys'), status=200) | |||
|
265 | ||||
|
266 | def test_ssh_keys_data(self, user_util, xhr_header): | |||
|
267 | self.log_user() | |||
|
268 | response = self.app.get(route_path('admin_permissions_ssh_keys_data'), | |||
|
269 | extra_environ=xhr_header) | |||
|
270 | assert response.json == {u'data': [], u'draw': None, | |||
|
271 | u'recordsFiltered': 0, u'recordsTotal': 0} | |||
|
272 | ||||
|
273 | dummy_user = user_util.create_user() | |||
|
274 | SshKeyModel().create(dummy_user, 'ab:cd:ef', 'KEYKEY', 'test_key') | |||
|
275 | Session().commit() | |||
|
276 | response = self.app.get(route_path('admin_permissions_ssh_keys_data'), | |||
|
277 | extra_environ=xhr_header) | |||
|
278 | assert response.json['data'][0]['fingerprint'] == 'ab:cd:ef' | |||
|
279 | ||||
|
280 | def test_ssh_keys_update(self): | |||
|
281 | self.log_user() | |||
|
282 | response = self.app.post( | |||
|
283 | route_path('admin_permissions_ssh_keys_update'), | |||
|
284 | dict(csrf_token=self.csrf_token), status=302) | |||
|
285 | ||||
|
286 | assert_session_flash( | |||
|
287 | response, 'Updated SSH keys file') | |||
|
288 | ||||
|
289 | def test_ssh_keys_update_disabled(self): | |||
|
290 | self.log_user() | |||
|
291 | ||||
|
292 | from rhodecode.apps.admin.views.permissions import AdminPermissionsView | |||
|
293 | with mock.patch.object(AdminPermissionsView, 'ssh_enabled', | |||
|
294 | return_value=False): | |||
|
295 | response = self.app.post( | |||
|
296 | route_path('admin_permissions_ssh_keys_update'), | |||
|
297 | dict(csrf_token=self.csrf_token), status=302) | |||
|
298 | ||||
|
299 | assert_session_flash( | |||
|
300 | response, 'SSH key support is disabled in .ini file') No newline at end of file |
This diff has been collapsed as it changes many lines, (730 lines changed) Show them Hide them | |||||
@@ -23,55 +23,83 b' import urllib' | |||||
23 | import mock |
|
23 | import mock | |
24 | import pytest |
|
24 | import pytest | |
25 |
|
25 | |||
|
26 | from rhodecode.apps._base import ADMIN_PREFIX | |||
26 | from rhodecode.lib import auth |
|
27 | from rhodecode.lib import auth | |
27 |
from rhodecode.lib.utils2 import safe_str |
|
28 | from rhodecode.lib.utils2 import safe_str | |
28 | from rhodecode.lib import helpers as h |
|
29 | from rhodecode.lib import helpers as h | |
29 | from rhodecode.model.db import ( |
|
30 | from rhodecode.model.db import ( | |
30 | Repository, RepoGroup, UserRepoToPerm, User, Permission) |
|
31 | Repository, RepoGroup, UserRepoToPerm, User, Permission) | |
31 | from rhodecode.model.meta import Session |
|
32 | from rhodecode.model.meta import Session | |
32 | from rhodecode.model.repo import RepoModel |
|
33 | from rhodecode.model.repo import RepoModel | |
33 | from rhodecode.model.repo_group import RepoGroupModel |
|
34 | from rhodecode.model.repo_group import RepoGroupModel | |
34 | from rhodecode.model.settings import SettingsModel, VcsSettingsModel |
|
|||
35 | from rhodecode.model.user import UserModel |
|
35 | from rhodecode.model.user import UserModel | |
36 | from rhodecode.tests import ( |
|
36 | from rhodecode.tests import ( | |
37 |
login_user_session |
|
37 | login_user_session, assert_session_flash, TEST_USER_ADMIN_LOGIN, | |
38 |
TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS |
|
38 | TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
39 | logout_user_session) |
|
|||
40 | from rhodecode.tests.fixture import Fixture, error_function |
|
39 | from rhodecode.tests.fixture import Fixture, error_function | |
41 | from rhodecode.tests.utils import AssertResponse, repo_on_filesystem |
|
40 | from rhodecode.tests.utils import AssertResponse, repo_on_filesystem | |
42 |
|
41 | |||
43 | fixture = Fixture() |
|
42 | fixture = Fixture() | |
44 |
|
43 | |||
45 |
|
44 | |||
|
45 | def route_path(name, params=None, **kwargs): | |||
|
46 | import urllib | |||
|
47 | ||||
|
48 | base_url = { | |||
|
49 | 'repos': ADMIN_PREFIX + '/repos', | |||
|
50 | 'repo_new': ADMIN_PREFIX + '/repos/new', | |||
|
51 | 'repo_create': ADMIN_PREFIX + '/repos/create', | |||
|
52 | ||||
|
53 | 'repo_creating_check': '/{repo_name}/repo_creating_check', | |||
|
54 | }[name].format(**kwargs) | |||
|
55 | ||||
|
56 | if params: | |||
|
57 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |||
|
58 | return base_url | |||
|
59 | ||||
|
60 | ||||
|
61 | def _get_permission_for_user(user, repo): | |||
|
62 | perm = UserRepoToPerm.query()\ | |||
|
63 | .filter(UserRepoToPerm.repository == | |||
|
64 | Repository.get_by_repo_name(repo))\ | |||
|
65 | .filter(UserRepoToPerm.user == User.get_by_username(user))\ | |||
|
66 | .all() | |||
|
67 | return perm | |||
|
68 | ||||
|
69 | ||||
46 | @pytest.mark.usefixtures("app") |
|
70 | @pytest.mark.usefixtures("app") | |
47 | class TestAdminRepos(object): |
|
71 | class TestAdminRepos(object): | |
48 |
|
72 | |||
49 | def test_index(self): |
|
73 | def test_repo_list(self, autologin_user, user_util): | |
50 | self.app.get(url('repos')) |
|
74 | repo = user_util.create_repo() | |
|
75 | response = self.app.get( | |||
|
76 | route_path('repos'), status=200) | |||
51 |
|
77 | |||
52 | def test_create_page_restricted(self, autologin_user, backend): |
|
78 | response.mustcontain(repo.repo_name) | |
|
79 | ||||
|
80 | def test_create_page_restricted_to_single_backend(self, autologin_user, backend): | |||
53 | with mock.patch('rhodecode.BACKENDS', {'git': 'git'}): |
|
81 | with mock.patch('rhodecode.BACKENDS', {'git': 'git'}): | |
54 |
response = self.app.get( |
|
82 | response = self.app.get(route_path('repo_new'), status=200) | |
55 | assert_response = AssertResponse(response) |
|
83 | assert_response = AssertResponse(response) | |
56 | element = assert_response.get_element('#repo_type') |
|
84 | element = assert_response.get_element('#repo_type') | |
57 | assert element.text_content() == '\ngit\n' |
|
85 | assert element.text_content() == '\ngit\n' | |
58 |
|
86 | |||
59 | def test_create_page_non_restricted(self, autologin_user, backend): |
|
87 | def test_create_page_non_restricted_backends(self, autologin_user, backend): | |
60 |
response = self.app.get( |
|
88 | response = self.app.get(route_path('repo_new'), status=200) | |
61 | assert_response = AssertResponse(response) |
|
89 | assert_response = AssertResponse(response) | |
62 | assert_response.element_contains('#repo_type', 'git') |
|
90 | assert_response.element_contains('#repo_type', 'git') | |
63 | assert_response.element_contains('#repo_type', 'svn') |
|
91 | assert_response.element_contains('#repo_type', 'svn') | |
64 | assert_response.element_contains('#repo_type', 'hg') |
|
92 | assert_response.element_contains('#repo_type', 'hg') | |
65 |
|
93 | |||
66 |
@pytest.mark.parametrize( |
|
94 | @pytest.mark.parametrize( | |
67 |
|
|
95 | "suffix", [u'', u'xxa'], ids=['', 'non-ascii']) | |
68 | def test_create(self, autologin_user, backend, suffix, csrf_token): |
|
96 | def test_create(self, autologin_user, backend, suffix, csrf_token): | |
69 | repo_name_unicode = backend.new_repo_name(suffix=suffix) |
|
97 | repo_name_unicode = backend.new_repo_name(suffix=suffix) | |
70 | repo_name = repo_name_unicode.encode('utf8') |
|
98 | repo_name = repo_name_unicode.encode('utf8') | |
71 | description_unicode = u'description for newly created repo' + suffix |
|
99 | description_unicode = u'description for newly created repo' + suffix | |
72 | description = description_unicode.encode('utf8') |
|
100 | description = description_unicode.encode('utf8') | |
73 | response = self.app.post( |
|
101 | response = self.app.post( | |
74 |
|
|
102 | route_path('repo_create'), | |
75 | fixture._get_repo_create_params( |
|
103 | fixture._get_repo_create_params( | |
76 | repo_private=False, |
|
104 | repo_private=False, | |
77 | repo_name=repo_name, |
|
105 | repo_name=repo_name, | |
@@ -83,12 +111,12 b' class TestAdminRepos(object):' | |||||
83 | self.assert_repository_is_created_correctly( |
|
111 | self.assert_repository_is_created_correctly( | |
84 | repo_name, description, backend) |
|
112 | repo_name, description, backend) | |
85 |
|
113 | |||
86 | def test_create_numeric(self, autologin_user, backend, csrf_token): |
|
114 | def test_create_numeric_name(self, autologin_user, backend, csrf_token): | |
87 | numeric_repo = '1234' |
|
115 | numeric_repo = '1234' | |
88 | repo_name = numeric_repo |
|
116 | repo_name = numeric_repo | |
89 | description = 'description for newly created repo' + numeric_repo |
|
117 | description = 'description for newly created repo' + numeric_repo | |
90 | self.app.post( |
|
118 | self.app.post( | |
91 |
|
|
119 | route_path('repo_create'), | |
92 | fixture._get_repo_create_params( |
|
120 | fixture._get_repo_create_params( | |
93 | repo_private=False, |
|
121 | repo_private=False, | |
94 | repo_name=repo_name, |
|
122 | repo_name=repo_name, | |
@@ -114,7 +142,7 b' class TestAdminRepos(object):' | |||||
114 | [group_name, repo_name]) |
|
142 | [group_name, repo_name]) | |
115 | description = u'description for newly created repo' |
|
143 | description = u'description for newly created repo' | |
116 | self.app.post( |
|
144 | self.app.post( | |
117 |
|
|
145 | route_path('repo_create'), | |
118 | fixture._get_repo_create_params( |
|
146 | fixture._get_repo_create_params( | |
119 | repo_private=False, |
|
147 | repo_private=False, | |
120 | repo_name=safe_str(repo_name), |
|
148 | repo_name=safe_str(repo_name), | |
@@ -137,7 +165,7 b' class TestAdminRepos(object):' | |||||
137 | RepoGroupModel().delete(group_name) |
|
165 | RepoGroupModel().delete(group_name) | |
138 | Session().commit() |
|
166 | Session().commit() | |
139 |
|
167 | |||
140 | def test_create_in_group_numeric( |
|
168 | def test_create_in_group_numeric_name( | |
141 | self, autologin_user, backend, csrf_token): |
|
169 | self, autologin_user, backend, csrf_token): | |
142 | # create GROUP |
|
170 | # create GROUP | |
143 | group_name = 'sometest_%s' % backend.alias |
|
171 | group_name = 'sometest_%s' % backend.alias | |
@@ -150,7 +178,7 b' class TestAdminRepos(object):' | |||||
150 | repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) |
|
178 | repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) | |
151 | description = 'description for newly created repo' |
|
179 | description = 'description for newly created repo' | |
152 | self.app.post( |
|
180 | self.app.post( | |
153 |
|
|
181 | route_path('repo_create'), | |
154 | fixture._get_repo_create_params( |
|
182 | fixture._get_repo_create_params( | |
155 | repo_private=False, |
|
183 | repo_private=False, | |
156 | repo_name=repo_name, |
|
184 | repo_name=repo_name, | |
@@ -209,7 +237,7 b' class TestAdminRepos(object):' | |||||
209 | repo_name = 'ingroup' |
|
237 | repo_name = 'ingroup' | |
210 | description = 'description for newly created repo' |
|
238 | description = 'description for newly created repo' | |
211 | response = self.app.post( |
|
239 | response = self.app.post( | |
212 |
|
|
240 | route_path('repo_create'), | |
213 | fixture._get_repo_create_params( |
|
241 | fixture._get_repo_create_params( | |
214 | repo_private=False, |
|
242 | repo_private=False, | |
215 | repo_name=repo_name, |
|
243 | repo_name=repo_name, | |
@@ -226,7 +254,7 b' class TestAdminRepos(object):' | |||||
226 | [group_name_allowed, repo_name]) |
|
254 | [group_name_allowed, repo_name]) | |
227 | description = 'description for newly created repo' |
|
255 | description = 'description for newly created repo' | |
228 | response = self.app.post( |
|
256 | response = self.app.post( | |
229 |
|
|
257 | route_path('repo_create'), | |
230 | fixture._get_repo_create_params( |
|
258 | fixture._get_repo_create_params( | |
231 | repo_private=False, |
|
259 | repo_private=False, | |
232 | repo_name=repo_name, |
|
260 | repo_name=repo_name, | |
@@ -270,7 +298,7 b' class TestAdminRepos(object):' | |||||
270 | repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) |
|
298 | repo_name_full = RepoGroup.url_sep().join([group_name, repo_name]) | |
271 | description = 'description for newly created repo' |
|
299 | description = 'description for newly created repo' | |
272 | self.app.post( |
|
300 | self.app.post( | |
273 |
|
|
301 | route_path('repo_create'), | |
274 | fixture._get_repo_create_params( |
|
302 | fixture._get_repo_create_params( | |
275 | repo_private=False, |
|
303 | repo_private=False, | |
276 | repo_name=repo_name, |
|
304 | repo_name=repo_name, | |
@@ -314,7 +342,7 b' class TestAdminRepos(object):' | |||||
314 |
|
342 | |||
315 | repo_name = backend.new_repo_name() |
|
343 | repo_name = backend.new_repo_name() | |
316 | response = self.app.post( |
|
344 | response = self.app.post( | |
317 |
|
|
345 | route_path('repo_create'), | |
318 | fixture._get_repo_create_params( |
|
346 | fixture._get_repo_create_params( | |
319 | repo_private=False, |
|
347 | repo_private=False, | |
320 | repo_name=repo_name, |
|
348 | repo_name=repo_name, | |
@@ -342,7 +370,7 b' class TestAdminRepos(object):' | |||||
342 | repo_name = backend.new_repo_name() |
|
370 | repo_name = backend.new_repo_name() | |
343 | description = 'description for newly created repo' |
|
371 | description = 'description for newly created repo' | |
344 | response = self.app.post( |
|
372 | response = self.app.post( | |
345 |
|
|
373 | route_path('repo_create'), | |
346 | fixture._get_repo_create_params( |
|
374 | fixture._get_repo_create_params( | |
347 | repo_private=False, |
|
375 | repo_private=False, | |
348 | repo_name=repo_name, |
|
376 | repo_name=repo_name, | |
@@ -358,7 +386,7 b' class TestAdminRepos(object):' | |||||
358 | repo_name = backend.new_repo_name() |
|
386 | repo_name = backend.new_repo_name() | |
359 | description = 'description for newly created repo' |
|
387 | description = 'description for newly created repo' | |
360 | response = self.app.post( |
|
388 | response = self.app.post( | |
361 |
|
|
389 | route_path('repo_create'), | |
362 | fixture._get_repo_create_params( |
|
390 | fixture._get_repo_create_params( | |
363 | repo_private=False, |
|
391 | repo_private=False, | |
364 | repo_name=repo_name, |
|
392 | repo_name=repo_name, | |
@@ -373,7 +401,7 b' class TestAdminRepos(object):' | |||||
373 | repo_name = backend.new_repo_name() + ".git" |
|
401 | repo_name = backend.new_repo_name() + ".git" | |
374 | description = 'description for newly created repo' |
|
402 | description = 'description for newly created repo' | |
375 | response = self.app.post( |
|
403 | response = self.app.post( | |
376 |
|
|
404 | route_path('repo_create'), | |
377 | fixture._get_repo_create_params( |
|
405 | fixture._get_repo_create_params( | |
378 | repo_private=False, |
|
406 | repo_private=False, | |
379 | repo_name=repo_name, |
|
407 | repo_name=repo_name, | |
@@ -382,11 +410,8 b' class TestAdminRepos(object):' | |||||
382 | csrf_token=csrf_token)) |
|
410 | csrf_token=csrf_token)) | |
383 | response.mustcontain('Repository name cannot end with .git') |
|
411 | response.mustcontain('Repository name cannot end with .git') | |
384 |
|
412 | |||
385 | def test_show(self, autologin_user, backend): |
|
|||
386 | self.app.get(url('repo', repo_name=backend.repo_name)) |
|
|||
387 |
|
||||
388 | def test_default_user_cannot_access_private_repo_in_a_group( |
|
413 | def test_default_user_cannot_access_private_repo_in_a_group( | |
389 |
self, autologin_user, user_util, backend |
|
414 | self, autologin_user, user_util, backend): | |
390 |
|
415 | |||
391 | group = user_util.create_repo_group() |
|
416 | group = user_util.create_repo_group() | |
392 |
|
417 | |||
@@ -422,7 +447,7 b' class TestAdminRepos(object):' | |||||
422 | repo_name = backend.new_repo_name() |
|
447 | repo_name = backend.new_repo_name() | |
423 | description = 'description for newly created repo' |
|
448 | description = 'description for newly created repo' | |
424 | response = self.app.post( |
|
449 | response = self.app.post( | |
425 |
|
|
450 | route_path('repo_create'), | |
426 | fixture._get_repo_create_params( |
|
451 | fixture._get_repo_create_params( | |
427 | repo_private=False, |
|
452 | repo_private=False, | |
428 | repo_name=repo_name, |
|
453 | repo_name=repo_name, | |
@@ -441,7 +466,7 b' class TestAdminRepos(object):' | |||||
441 | description = 'description for newly created repo' |
|
466 | description = 'description for newly created repo' | |
442 |
|
467 | |||
443 | response = self.app.post( |
|
468 | response = self.app.post( | |
444 |
|
|
469 | route_path('repo_create'), | |
445 | fixture._get_repo_create_params( |
|
470 | fixture._get_repo_create_params( | |
446 | repo_private=False, |
|
471 | repo_private=False, | |
447 | repo_name=repo_name, |
|
472 | repo_name=repo_name, | |
@@ -461,7 +486,8 b' class TestAdminRepos(object):' | |||||
461 | repo_name_utf8 = safe_str(repo_name) |
|
486 | repo_name_utf8 = safe_str(repo_name) | |
462 |
|
487 | |||
463 | # run the check page that triggers the flash message |
|
488 | # run the check page that triggers the flash message | |
464 | response = self.app.get(url('repo_check_home', repo_name=repo_name)) |
|
489 | response = self.app.get( | |
|
490 | route_path('repo_creating_check', repo_name=safe_str(repo_name))) | |||
465 | assert response.json == {u'result': True} |
|
491 | assert response.json == {u'result': True} | |
466 |
|
492 | |||
467 | flash_msg = u'Created repository <a href="/{}">{}</a>'.format( |
|
493 | flash_msg = u'Created repository <a href="/{}">{}</a>'.format( | |
@@ -475,643 +501,9 b' class TestAdminRepos(object):' | |||||
475 | assert new_repo.description == description |
|
501 | assert new_repo.description == description | |
476 |
|
502 | |||
477 | # test if the repository is visible in the list ? |
|
503 | # test if the repository is visible in the list ? | |
478 | response = self.app.get(h.route_path('repo_summary', repo_name=repo_name)) |
|
504 | response = self.app.get( | |
|
505 | h.route_path('repo_summary', repo_name=safe_str(repo_name))) | |||
479 | response.mustcontain(repo_name) |
|
506 | response.mustcontain(repo_name) | |
480 | response.mustcontain(backend.alias) |
|
507 | response.mustcontain(backend.alias) | |
481 |
|
508 | |||
482 | assert repo_on_filesystem(repo_name) |
|
509 | assert repo_on_filesystem(repo_name) | |
483 |
|
||||
484 |
|
||||
485 | @pytest.mark.usefixtures("app") |
|
|||
486 | class TestVcsSettings(object): |
|
|||
487 | FORM_DATA = { |
|
|||
488 | 'inherit_global_settings': False, |
|
|||
489 | 'hooks_changegroup_repo_size': False, |
|
|||
490 | 'hooks_changegroup_push_logger': False, |
|
|||
491 | 'hooks_outgoing_pull_logger': False, |
|
|||
492 | 'extensions_largefiles': False, |
|
|||
493 | 'extensions_evolve': False, |
|
|||
494 | 'phases_publish': 'False', |
|
|||
495 | 'rhodecode_pr_merge_enabled': False, |
|
|||
496 | 'rhodecode_use_outdated_comments': False, |
|
|||
497 | 'new_svn_branch': '', |
|
|||
498 | 'new_svn_tag': '' |
|
|||
499 | } |
|
|||
500 |
|
||||
501 | @pytest.mark.skip_backends('svn') |
|
|||
502 | def test_global_settings_initial_values(self, autologin_user, backend): |
|
|||
503 | repo_name = backend.repo_name |
|
|||
504 | response = self.app.get(url('repo_vcs_settings', repo_name=repo_name)) |
|
|||
505 |
|
||||
506 | expected_settings = ( |
|
|||
507 | 'rhodecode_use_outdated_comments', 'rhodecode_pr_merge_enabled', |
|
|||
508 | 'hooks_changegroup_repo_size', 'hooks_changegroup_push_logger', |
|
|||
509 | 'hooks_outgoing_pull_logger' |
|
|||
510 | ) |
|
|||
511 | for setting in expected_settings: |
|
|||
512 | self.assert_repo_value_equals_global_value(response, setting) |
|
|||
513 |
|
||||
514 | def test_show_settings_requires_repo_admin_permission( |
|
|||
515 | self, backend, user_util, settings_util): |
|
|||
516 | repo = backend.create_repo() |
|
|||
517 | repo_name = repo.repo_name |
|
|||
518 | user = UserModel().get_by_username(TEST_USER_REGULAR_LOGIN) |
|
|||
519 | user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') |
|
|||
520 | login_user_session( |
|
|||
521 | self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
|||
522 | self.app.get(url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
523 |
|
||||
524 | def test_inherit_global_settings_flag_is_true_by_default( |
|
|||
525 | self, autologin_user, backend): |
|
|||
526 | repo_name = backend.repo_name |
|
|||
527 | response = self.app.get(url('repo_vcs_settings', repo_name=repo_name)) |
|
|||
528 |
|
||||
529 | assert_response = AssertResponse(response) |
|
|||
530 | element = assert_response.get_element('#inherit_global_settings') |
|
|||
531 | assert element.checked |
|
|||
532 |
|
||||
533 | @pytest.mark.parametrize('checked_value', [True, False]) |
|
|||
534 | def test_inherit_global_settings_value( |
|
|||
535 | self, autologin_user, backend, checked_value, settings_util): |
|
|||
536 | repo = backend.create_repo() |
|
|||
537 | repo_name = repo.repo_name |
|
|||
538 | settings_util.create_repo_rhodecode_setting( |
|
|||
539 | repo, 'inherit_vcs_settings', checked_value, 'bool') |
|
|||
540 | response = self.app.get(url('repo_vcs_settings', repo_name=repo_name)) |
|
|||
541 |
|
||||
542 | assert_response = AssertResponse(response) |
|
|||
543 | element = assert_response.get_element('#inherit_global_settings') |
|
|||
544 | assert element.checked == checked_value |
|
|||
545 |
|
||||
546 | @pytest.mark.skip_backends('svn') |
|
|||
547 | def test_hooks_settings_are_created( |
|
|||
548 | self, autologin_user, backend, csrf_token): |
|
|||
549 | repo_name = backend.repo_name |
|
|||
550 | data = self.FORM_DATA.copy() |
|
|||
551 | data['csrf_token'] = csrf_token |
|
|||
552 | self.app.post( |
|
|||
553 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
554 | settings = SettingsModel(repo=repo_name) |
|
|||
555 | try: |
|
|||
556 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
557 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
558 | assert ui.ui_active is False |
|
|||
559 | finally: |
|
|||
560 | self._cleanup_repo_settings(settings) |
|
|||
561 |
|
||||
562 | def test_hooks_settings_are_not_created_for_svn( |
|
|||
563 | self, autologin_user, backend_svn, csrf_token): |
|
|||
564 | repo_name = backend_svn.repo_name |
|
|||
565 | data = self.FORM_DATA.copy() |
|
|||
566 | data['csrf_token'] = csrf_token |
|
|||
567 | self.app.post( |
|
|||
568 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
569 | settings = SettingsModel(repo=repo_name) |
|
|||
570 | try: |
|
|||
571 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
572 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
573 | assert ui is None |
|
|||
574 | finally: |
|
|||
575 | self._cleanup_repo_settings(settings) |
|
|||
576 |
|
||||
577 | @pytest.mark.skip_backends('svn') |
|
|||
578 | def test_hooks_settings_are_updated( |
|
|||
579 | self, autologin_user, backend, csrf_token): |
|
|||
580 | repo_name = backend.repo_name |
|
|||
581 | settings = SettingsModel(repo=repo_name) |
|
|||
582 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
583 | settings.create_ui_section_value(section, '', key=key, active=True) |
|
|||
584 |
|
||||
585 | data = self.FORM_DATA.copy() |
|
|||
586 | data['csrf_token'] = csrf_token |
|
|||
587 | self.app.post( |
|
|||
588 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
589 | try: |
|
|||
590 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
591 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
592 | assert ui.ui_active is False |
|
|||
593 | finally: |
|
|||
594 | self._cleanup_repo_settings(settings) |
|
|||
595 |
|
||||
596 | def test_hooks_settings_are_not_updated_for_svn( |
|
|||
597 | self, autologin_user, backend_svn, csrf_token): |
|
|||
598 | repo_name = backend_svn.repo_name |
|
|||
599 | settings = SettingsModel(repo=repo_name) |
|
|||
600 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
601 | settings.create_ui_section_value(section, '', key=key, active=True) |
|
|||
602 |
|
||||
603 | data = self.FORM_DATA.copy() |
|
|||
604 | data['csrf_token'] = csrf_token |
|
|||
605 | self.app.post( |
|
|||
606 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
607 | try: |
|
|||
608 | for section, key in VcsSettingsModel.HOOKS_SETTINGS: |
|
|||
609 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
610 | assert ui.ui_active is True |
|
|||
611 | finally: |
|
|||
612 | self._cleanup_repo_settings(settings) |
|
|||
613 |
|
||||
614 | @pytest.mark.skip_backends('svn') |
|
|||
615 | def test_pr_settings_are_created( |
|
|||
616 | self, autologin_user, backend, csrf_token): |
|
|||
617 | repo_name = backend.repo_name |
|
|||
618 | data = self.FORM_DATA.copy() |
|
|||
619 | data['csrf_token'] = csrf_token |
|
|||
620 | self.app.post( |
|
|||
621 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
622 | settings = SettingsModel(repo=repo_name) |
|
|||
623 | try: |
|
|||
624 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
625 | setting = settings.get_setting_by_name(name) |
|
|||
626 | assert setting.app_settings_value is False |
|
|||
627 | finally: |
|
|||
628 | self._cleanup_repo_settings(settings) |
|
|||
629 |
|
||||
630 | def test_pr_settings_are_not_created_for_svn( |
|
|||
631 | self, autologin_user, backend_svn, csrf_token): |
|
|||
632 | repo_name = backend_svn.repo_name |
|
|||
633 | data = self.FORM_DATA.copy() |
|
|||
634 | data['csrf_token'] = csrf_token |
|
|||
635 | self.app.post( |
|
|||
636 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
637 | settings = SettingsModel(repo=repo_name) |
|
|||
638 | try: |
|
|||
639 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
640 | setting = settings.get_setting_by_name(name) |
|
|||
641 | assert setting is None |
|
|||
642 | finally: |
|
|||
643 | self._cleanup_repo_settings(settings) |
|
|||
644 |
|
||||
645 | def test_pr_settings_creation_requires_repo_admin_permission( |
|
|||
646 | self, backend, user_util, settings_util, csrf_token): |
|
|||
647 | repo = backend.create_repo() |
|
|||
648 | repo_name = repo.repo_name |
|
|||
649 |
|
||||
650 | logout_user_session(self.app, csrf_token) |
|
|||
651 | session = login_user_session( |
|
|||
652 | self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
|||
653 | new_csrf_token = auth.get_csrf_token(session) |
|
|||
654 |
|
||||
655 | user = UserModel().get_by_username(TEST_USER_REGULAR_LOGIN) |
|
|||
656 | repo = Repository.get_by_repo_name(repo_name) |
|
|||
657 | user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') |
|
|||
658 | data = self.FORM_DATA.copy() |
|
|||
659 | data['csrf_token'] = new_csrf_token |
|
|||
660 | settings = SettingsModel(repo=repo_name) |
|
|||
661 |
|
||||
662 | try: |
|
|||
663 | self.app.post( |
|
|||
664 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
665 | status=302) |
|
|||
666 | finally: |
|
|||
667 | self._cleanup_repo_settings(settings) |
|
|||
668 |
|
||||
669 | @pytest.mark.skip_backends('svn') |
|
|||
670 | def test_pr_settings_are_updated( |
|
|||
671 | self, autologin_user, backend, csrf_token): |
|
|||
672 | repo_name = backend.repo_name |
|
|||
673 | settings = SettingsModel(repo=repo_name) |
|
|||
674 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
675 | settings.create_or_update_setting(name, True, 'bool') |
|
|||
676 |
|
||||
677 | data = self.FORM_DATA.copy() |
|
|||
678 | data['csrf_token'] = csrf_token |
|
|||
679 | self.app.post( |
|
|||
680 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
681 | try: |
|
|||
682 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
683 | setting = settings.get_setting_by_name(name) |
|
|||
684 | assert setting.app_settings_value is False |
|
|||
685 | finally: |
|
|||
686 | self._cleanup_repo_settings(settings) |
|
|||
687 |
|
||||
688 | def test_pr_settings_are_not_updated_for_svn( |
|
|||
689 | self, autologin_user, backend_svn, csrf_token): |
|
|||
690 | repo_name = backend_svn.repo_name |
|
|||
691 | settings = SettingsModel(repo=repo_name) |
|
|||
692 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
693 | settings.create_or_update_setting(name, True, 'bool') |
|
|||
694 |
|
||||
695 | data = self.FORM_DATA.copy() |
|
|||
696 | data['csrf_token'] = csrf_token |
|
|||
697 | self.app.post( |
|
|||
698 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
699 | try: |
|
|||
700 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
701 | setting = settings.get_setting_by_name(name) |
|
|||
702 | assert setting.app_settings_value is True |
|
|||
703 | finally: |
|
|||
704 | self._cleanup_repo_settings(settings) |
|
|||
705 |
|
||||
706 | def test_svn_settings_are_created( |
|
|||
707 | self, autologin_user, backend_svn, csrf_token, settings_util): |
|
|||
708 | repo_name = backend_svn.repo_name |
|
|||
709 | data = self.FORM_DATA.copy() |
|
|||
710 | data['new_svn_tag'] = 'svn-tag' |
|
|||
711 | data['new_svn_branch'] = 'svn-branch' |
|
|||
712 | data['csrf_token'] = csrf_token |
|
|||
713 |
|
||||
714 | # Create few global settings to make sure that uniqueness validators |
|
|||
715 | # are not triggered |
|
|||
716 | settings_util.create_rhodecode_ui( |
|
|||
717 | VcsSettingsModel.SVN_BRANCH_SECTION, 'svn-branch') |
|
|||
718 | settings_util.create_rhodecode_ui( |
|
|||
719 | VcsSettingsModel.SVN_TAG_SECTION, 'svn-tag') |
|
|||
720 |
|
||||
721 | self.app.post( |
|
|||
722 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
723 | settings = SettingsModel(repo=repo_name) |
|
|||
724 | try: |
|
|||
725 | svn_branches = settings.get_ui_by_section( |
|
|||
726 | VcsSettingsModel.SVN_BRANCH_SECTION) |
|
|||
727 | svn_branch_names = [b.ui_value for b in svn_branches] |
|
|||
728 | svn_tags = settings.get_ui_by_section( |
|
|||
729 | VcsSettingsModel.SVN_TAG_SECTION) |
|
|||
730 | svn_tag_names = [b.ui_value for b in svn_tags] |
|
|||
731 | assert 'svn-branch' in svn_branch_names |
|
|||
732 | assert 'svn-tag' in svn_tag_names |
|
|||
733 | finally: |
|
|||
734 | self._cleanup_repo_settings(settings) |
|
|||
735 |
|
||||
736 | def test_svn_settings_are_unique( |
|
|||
737 | self, autologin_user, backend_svn, csrf_token, settings_util): |
|
|||
738 | repo = backend_svn.repo |
|
|||
739 | repo_name = repo.repo_name |
|
|||
740 | data = self.FORM_DATA.copy() |
|
|||
741 | data['new_svn_tag'] = 'test_tag' |
|
|||
742 | data['new_svn_branch'] = 'test_branch' |
|
|||
743 | data['csrf_token'] = csrf_token |
|
|||
744 | settings_util.create_repo_rhodecode_ui( |
|
|||
745 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch') |
|
|||
746 | settings_util.create_repo_rhodecode_ui( |
|
|||
747 | repo, VcsSettingsModel.SVN_TAG_SECTION, 'test_tag') |
|
|||
748 |
|
||||
749 | response = self.app.post( |
|
|||
750 | url('repo_vcs_settings', repo_name=repo_name), data, status=200) |
|
|||
751 | response.mustcontain('Pattern already exists') |
|
|||
752 |
|
||||
753 | def test_svn_settings_with_empty_values_are_not_created( |
|
|||
754 | self, autologin_user, backend_svn, csrf_token): |
|
|||
755 | repo_name = backend_svn.repo_name |
|
|||
756 | data = self.FORM_DATA.copy() |
|
|||
757 | data['csrf_token'] = csrf_token |
|
|||
758 | self.app.post( |
|
|||
759 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
760 | settings = SettingsModel(repo=repo_name) |
|
|||
761 | try: |
|
|||
762 | svn_branches = settings.get_ui_by_section( |
|
|||
763 | VcsSettingsModel.SVN_BRANCH_SECTION) |
|
|||
764 | svn_tags = settings.get_ui_by_section( |
|
|||
765 | VcsSettingsModel.SVN_TAG_SECTION) |
|
|||
766 | assert len(svn_branches) == 0 |
|
|||
767 | assert len(svn_tags) == 0 |
|
|||
768 | finally: |
|
|||
769 | self._cleanup_repo_settings(settings) |
|
|||
770 |
|
||||
771 | def test_svn_settings_are_shown_for_svn_repository( |
|
|||
772 | self, autologin_user, backend_svn, csrf_token): |
|
|||
773 | repo_name = backend_svn.repo_name |
|
|||
774 | response = self.app.get( |
|
|||
775 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
776 | response.mustcontain('Subversion Settings') |
|
|||
777 |
|
||||
778 | @pytest.mark.skip_backends('svn') |
|
|||
779 | def test_svn_settings_are_not_created_for_not_svn_repository( |
|
|||
780 | self, autologin_user, backend, csrf_token): |
|
|||
781 | repo_name = backend.repo_name |
|
|||
782 | data = self.FORM_DATA.copy() |
|
|||
783 | data['csrf_token'] = csrf_token |
|
|||
784 | self.app.post( |
|
|||
785 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
786 | settings = SettingsModel(repo=repo_name) |
|
|||
787 | try: |
|
|||
788 | svn_branches = settings.get_ui_by_section( |
|
|||
789 | VcsSettingsModel.SVN_BRANCH_SECTION) |
|
|||
790 | svn_tags = settings.get_ui_by_section( |
|
|||
791 | VcsSettingsModel.SVN_TAG_SECTION) |
|
|||
792 | assert len(svn_branches) == 0 |
|
|||
793 | assert len(svn_tags) == 0 |
|
|||
794 | finally: |
|
|||
795 | self._cleanup_repo_settings(settings) |
|
|||
796 |
|
||||
797 | @pytest.mark.skip_backends('svn') |
|
|||
798 | def test_svn_settings_are_shown_only_for_svn_repository( |
|
|||
799 | self, autologin_user, backend, csrf_token): |
|
|||
800 | repo_name = backend.repo_name |
|
|||
801 | response = self.app.get( |
|
|||
802 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
803 | response.mustcontain(no='Subversion Settings') |
|
|||
804 |
|
||||
805 | def test_hg_settings_are_created( |
|
|||
806 | self, autologin_user, backend_hg, csrf_token): |
|
|||
807 | repo_name = backend_hg.repo_name |
|
|||
808 | data = self.FORM_DATA.copy() |
|
|||
809 | data['new_svn_tag'] = 'svn-tag' |
|
|||
810 | data['new_svn_branch'] = 'svn-branch' |
|
|||
811 | data['csrf_token'] = csrf_token |
|
|||
812 | self.app.post( |
|
|||
813 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
814 | settings = SettingsModel(repo=repo_name) |
|
|||
815 | try: |
|
|||
816 | largefiles_ui = settings.get_ui_by_section_and_key( |
|
|||
817 | 'extensions', 'largefiles') |
|
|||
818 | assert largefiles_ui.ui_active is False |
|
|||
819 | phases_ui = settings.get_ui_by_section_and_key( |
|
|||
820 | 'phases', 'publish') |
|
|||
821 | assert str2bool(phases_ui.ui_value) is False |
|
|||
822 | finally: |
|
|||
823 | self._cleanup_repo_settings(settings) |
|
|||
824 |
|
||||
825 | def test_hg_settings_are_updated( |
|
|||
826 | self, autologin_user, backend_hg, csrf_token): |
|
|||
827 | repo_name = backend_hg.repo_name |
|
|||
828 | settings = SettingsModel(repo=repo_name) |
|
|||
829 | settings.create_ui_section_value( |
|
|||
830 | 'extensions', '', key='largefiles', active=True) |
|
|||
831 | settings.create_ui_section_value( |
|
|||
832 | 'phases', '1', key='publish', active=True) |
|
|||
833 |
|
||||
834 | data = self.FORM_DATA.copy() |
|
|||
835 | data['csrf_token'] = csrf_token |
|
|||
836 | self.app.post( |
|
|||
837 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
838 | try: |
|
|||
839 | largefiles_ui = settings.get_ui_by_section_and_key( |
|
|||
840 | 'extensions', 'largefiles') |
|
|||
841 | assert largefiles_ui.ui_active is False |
|
|||
842 | phases_ui = settings.get_ui_by_section_and_key( |
|
|||
843 | 'phases', 'publish') |
|
|||
844 | assert str2bool(phases_ui.ui_value) is False |
|
|||
845 | finally: |
|
|||
846 | self._cleanup_repo_settings(settings) |
|
|||
847 |
|
||||
848 | def test_hg_settings_are_shown_for_hg_repository( |
|
|||
849 | self, autologin_user, backend_hg, csrf_token): |
|
|||
850 | repo_name = backend_hg.repo_name |
|
|||
851 | response = self.app.get( |
|
|||
852 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
853 | response.mustcontain('Mercurial Settings') |
|
|||
854 |
|
||||
855 | @pytest.mark.skip_backends('hg') |
|
|||
856 | def test_hg_settings_are_created_only_for_hg_repository( |
|
|||
857 | self, autologin_user, backend, csrf_token): |
|
|||
858 | repo_name = backend.repo_name |
|
|||
859 | data = self.FORM_DATA.copy() |
|
|||
860 | data['csrf_token'] = csrf_token |
|
|||
861 | self.app.post( |
|
|||
862 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
863 | settings = SettingsModel(repo=repo_name) |
|
|||
864 | try: |
|
|||
865 | largefiles_ui = settings.get_ui_by_section_and_key( |
|
|||
866 | 'extensions', 'largefiles') |
|
|||
867 | assert largefiles_ui is None |
|
|||
868 | phases_ui = settings.get_ui_by_section_and_key( |
|
|||
869 | 'phases', 'publish') |
|
|||
870 | assert phases_ui is None |
|
|||
871 | finally: |
|
|||
872 | self._cleanup_repo_settings(settings) |
|
|||
873 |
|
||||
874 | @pytest.mark.skip_backends('hg') |
|
|||
875 | def test_hg_settings_are_shown_only_for_hg_repository( |
|
|||
876 | self, autologin_user, backend, csrf_token): |
|
|||
877 | repo_name = backend.repo_name |
|
|||
878 | response = self.app.get( |
|
|||
879 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
880 | response.mustcontain(no='Mercurial Settings') |
|
|||
881 |
|
||||
882 | @pytest.mark.skip_backends('hg') |
|
|||
883 | def test_hg_settings_are_updated_only_for_hg_repository( |
|
|||
884 | self, autologin_user, backend, csrf_token): |
|
|||
885 | repo_name = backend.repo_name |
|
|||
886 | settings = SettingsModel(repo=repo_name) |
|
|||
887 | settings.create_ui_section_value( |
|
|||
888 | 'extensions', '', key='largefiles', active=True) |
|
|||
889 | settings.create_ui_section_value( |
|
|||
890 | 'phases', '1', key='publish', active=True) |
|
|||
891 |
|
||||
892 | data = self.FORM_DATA.copy() |
|
|||
893 | data['csrf_token'] = csrf_token |
|
|||
894 | self.app.post( |
|
|||
895 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
896 | try: |
|
|||
897 | largefiles_ui = settings.get_ui_by_section_and_key( |
|
|||
898 | 'extensions', 'largefiles') |
|
|||
899 | assert largefiles_ui.ui_active is True |
|
|||
900 | phases_ui = settings.get_ui_by_section_and_key( |
|
|||
901 | 'phases', 'publish') |
|
|||
902 | assert phases_ui.ui_value == '1' |
|
|||
903 | finally: |
|
|||
904 | self._cleanup_repo_settings(settings) |
|
|||
905 |
|
||||
906 | def test_per_repo_svn_settings_are_displayed( |
|
|||
907 | self, autologin_user, backend_svn, settings_util): |
|
|||
908 | repo = backend_svn.create_repo() |
|
|||
909 | repo_name = repo.repo_name |
|
|||
910 | branches = [ |
|
|||
911 | settings_util.create_repo_rhodecode_ui( |
|
|||
912 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, |
|
|||
913 | 'branch_{}'.format(i)) |
|
|||
914 | for i in range(10)] |
|
|||
915 | tags = [ |
|
|||
916 | settings_util.create_repo_rhodecode_ui( |
|
|||
917 | repo, VcsSettingsModel.SVN_TAG_SECTION, 'tag_{}'.format(i)) |
|
|||
918 | for i in range(10)] |
|
|||
919 |
|
||||
920 | response = self.app.get( |
|
|||
921 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
922 | assert_response = AssertResponse(response) |
|
|||
923 | for branch in branches: |
|
|||
924 | css_selector = '[name=branch_value_{}]'.format(branch.ui_id) |
|
|||
925 | element = assert_response.get_element(css_selector) |
|
|||
926 | assert element.value == branch.ui_value |
|
|||
927 | for tag in tags: |
|
|||
928 | css_selector = '[name=tag_ui_value_new_{}]'.format(tag.ui_id) |
|
|||
929 | element = assert_response.get_element(css_selector) |
|
|||
930 | assert element.value == tag.ui_value |
|
|||
931 |
|
||||
932 | def test_per_repo_hg_and_pr_settings_are_not_displayed_for_svn( |
|
|||
933 | self, autologin_user, backend_svn, settings_util): |
|
|||
934 | repo = backend_svn.create_repo() |
|
|||
935 | repo_name = repo.repo_name |
|
|||
936 | response = self.app.get( |
|
|||
937 | url('repo_vcs_settings', repo_name=repo_name), status=200) |
|
|||
938 | response.mustcontain(no='<label>Hooks:</label>') |
|
|||
939 | response.mustcontain(no='<label>Pull Request Settings:</label>') |
|
|||
940 |
|
||||
941 | def test_inherit_global_settings_value_is_saved( |
|
|||
942 | self, autologin_user, backend, csrf_token): |
|
|||
943 | repo_name = backend.repo_name |
|
|||
944 | data = self.FORM_DATA.copy() |
|
|||
945 | data['csrf_token'] = csrf_token |
|
|||
946 | data['inherit_global_settings'] = True |
|
|||
947 | self.app.post( |
|
|||
948 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
949 |
|
||||
950 | settings = SettingsModel(repo=repo_name) |
|
|||
951 | vcs_settings = VcsSettingsModel(repo=repo_name) |
|
|||
952 | try: |
|
|||
953 | assert vcs_settings.inherit_global_settings is True |
|
|||
954 | finally: |
|
|||
955 | self._cleanup_repo_settings(settings) |
|
|||
956 |
|
||||
957 | def test_repo_cache_is_invalidated_when_settings_are_updated( |
|
|||
958 | self, autologin_user, backend, csrf_token): |
|
|||
959 | repo_name = backend.repo_name |
|
|||
960 | data = self.FORM_DATA.copy() |
|
|||
961 | data['csrf_token'] = csrf_token |
|
|||
962 | data['inherit_global_settings'] = True |
|
|||
963 | settings = SettingsModel(repo=repo_name) |
|
|||
964 |
|
||||
965 | invalidation_patcher = mock.patch( |
|
|||
966 | 'rhodecode.controllers.admin.repos.ScmModel.mark_for_invalidation') |
|
|||
967 | with invalidation_patcher as invalidation_mock: |
|
|||
968 | self.app.post( |
|
|||
969 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
970 | status=302) |
|
|||
971 | try: |
|
|||
972 | invalidation_mock.assert_called_once_with(repo_name, delete=True) |
|
|||
973 | finally: |
|
|||
974 | self._cleanup_repo_settings(settings) |
|
|||
975 |
|
||||
976 | def test_other_settings_not_saved_inherit_global_settings_is_true( |
|
|||
977 | self, autologin_user, backend, csrf_token): |
|
|||
978 | repo_name = backend.repo_name |
|
|||
979 | data = self.FORM_DATA.copy() |
|
|||
980 | data['csrf_token'] = csrf_token |
|
|||
981 | data['inherit_global_settings'] = True |
|
|||
982 | self.app.post( |
|
|||
983 | url('repo_vcs_settings', repo_name=repo_name), data, status=302) |
|
|||
984 |
|
||||
985 | settings = SettingsModel(repo=repo_name) |
|
|||
986 | ui_settings = ( |
|
|||
987 | VcsSettingsModel.HOOKS_SETTINGS + VcsSettingsModel.HG_SETTINGS) |
|
|||
988 |
|
||||
989 | vcs_settings = [] |
|
|||
990 | try: |
|
|||
991 | for section, key in ui_settings: |
|
|||
992 | ui = settings.get_ui_by_section_and_key(section, key) |
|
|||
993 | if ui: |
|
|||
994 | vcs_settings.append(ui) |
|
|||
995 | vcs_settings.extend(settings.get_ui_by_section( |
|
|||
996 | VcsSettingsModel.SVN_BRANCH_SECTION)) |
|
|||
997 | vcs_settings.extend(settings.get_ui_by_section( |
|
|||
998 | VcsSettingsModel.SVN_TAG_SECTION)) |
|
|||
999 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
1000 | setting = settings.get_setting_by_name(name) |
|
|||
1001 | if setting: |
|
|||
1002 | vcs_settings.append(setting) |
|
|||
1003 | assert vcs_settings == [] |
|
|||
1004 | finally: |
|
|||
1005 | self._cleanup_repo_settings(settings) |
|
|||
1006 |
|
||||
1007 | def test_delete_svn_branch_and_tag_patterns( |
|
|||
1008 | self, autologin_user, backend_svn, settings_util, csrf_token): |
|
|||
1009 | repo = backend_svn.create_repo() |
|
|||
1010 | repo_name = repo.repo_name |
|
|||
1011 | branch = settings_util.create_repo_rhodecode_ui( |
|
|||
1012 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch', |
|
|||
1013 | cleanup=False) |
|
|||
1014 | tag = settings_util.create_repo_rhodecode_ui( |
|
|||
1015 | repo, VcsSettingsModel.SVN_TAG_SECTION, 'test_tag', cleanup=False) |
|
|||
1016 | data = { |
|
|||
1017 | '_method': 'delete', |
|
|||
1018 | 'csrf_token': csrf_token |
|
|||
1019 | } |
|
|||
1020 | for id_ in (branch.ui_id, tag.ui_id): |
|
|||
1021 | data['delete_svn_pattern'] = id_, |
|
|||
1022 | self.app.post( |
|
|||
1023 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
1024 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) |
|
|||
1025 | settings = VcsSettingsModel(repo=repo_name) |
|
|||
1026 | assert settings.get_repo_svn_branch_patterns() == [] |
|
|||
1027 |
|
||||
1028 | def test_delete_svn_branch_requires_repo_admin_permission( |
|
|||
1029 | self, backend_svn, user_util, settings_util, csrf_token): |
|
|||
1030 | repo = backend_svn.create_repo() |
|
|||
1031 | repo_name = repo.repo_name |
|
|||
1032 |
|
||||
1033 | logout_user_session(self.app, csrf_token) |
|
|||
1034 | session = login_user_session( |
|
|||
1035 | self.app, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
|||
1036 | csrf_token = auth.get_csrf_token(session) |
|
|||
1037 |
|
||||
1038 | repo = Repository.get_by_repo_name(repo_name) |
|
|||
1039 | user = UserModel().get_by_username(TEST_USER_REGULAR_LOGIN) |
|
|||
1040 | user_util.grant_user_permission_to_repo(repo, user, 'repository.admin') |
|
|||
1041 | branch = settings_util.create_repo_rhodecode_ui( |
|
|||
1042 | repo, VcsSettingsModel.SVN_BRANCH_SECTION, 'test_branch', |
|
|||
1043 | cleanup=False) |
|
|||
1044 | data = { |
|
|||
1045 | '_method': 'delete', |
|
|||
1046 | 'csrf_token': csrf_token, |
|
|||
1047 | 'delete_svn_pattern': branch.ui_id |
|
|||
1048 | } |
|
|||
1049 | self.app.post( |
|
|||
1050 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
1051 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=200) |
|
|||
1052 |
|
||||
1053 | def test_delete_svn_branch_raises_400_when_not_found( |
|
|||
1054 | self, autologin_user, backend_svn, settings_util, csrf_token): |
|
|||
1055 | repo_name = backend_svn.repo_name |
|
|||
1056 | data = { |
|
|||
1057 | '_method': 'delete', |
|
|||
1058 | 'delete_svn_pattern': 123, |
|
|||
1059 | 'csrf_token': csrf_token |
|
|||
1060 | } |
|
|||
1061 | self.app.post( |
|
|||
1062 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
1063 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=400) |
|
|||
1064 |
|
||||
1065 | def test_delete_svn_branch_raises_400_when_no_id_specified( |
|
|||
1066 | self, autologin_user, backend_svn, settings_util, csrf_token): |
|
|||
1067 | repo_name = backend_svn.repo_name |
|
|||
1068 | data = { |
|
|||
1069 | '_method': 'delete', |
|
|||
1070 | 'csrf_token': csrf_token |
|
|||
1071 | } |
|
|||
1072 | self.app.post( |
|
|||
1073 | url('repo_vcs_settings', repo_name=repo_name), data, |
|
|||
1074 | headers={'X-REQUESTED-WITH': 'XMLHttpRequest', }, status=400) |
|
|||
1075 |
|
||||
1076 | def _cleanup_repo_settings(self, settings_model): |
|
|||
1077 | cleanup = [] |
|
|||
1078 | ui_settings = ( |
|
|||
1079 | VcsSettingsModel.HOOKS_SETTINGS + VcsSettingsModel.HG_SETTINGS) |
|
|||
1080 |
|
||||
1081 | for section, key in ui_settings: |
|
|||
1082 | ui = settings_model.get_ui_by_section_and_key(section, key) |
|
|||
1083 | if ui: |
|
|||
1084 | cleanup.append(ui) |
|
|||
1085 |
|
||||
1086 | cleanup.extend(settings_model.get_ui_by_section( |
|
|||
1087 | VcsSettingsModel.INHERIT_SETTINGS)) |
|
|||
1088 | cleanup.extend(settings_model.get_ui_by_section( |
|
|||
1089 | VcsSettingsModel.SVN_BRANCH_SECTION)) |
|
|||
1090 | cleanup.extend(settings_model.get_ui_by_section( |
|
|||
1091 | VcsSettingsModel.SVN_TAG_SECTION)) |
|
|||
1092 |
|
||||
1093 | for name in VcsSettingsModel.GENERAL_SETTINGS: |
|
|||
1094 | setting = settings_model.get_setting_by_name(name) |
|
|||
1095 | if setting: |
|
|||
1096 | cleanup.append(setting) |
|
|||
1097 |
|
||||
1098 | for object_ in cleanup: |
|
|||
1099 | Session().delete(object_) |
|
|||
1100 | Session().commit() |
|
|||
1101 |
|
||||
1102 | def assert_repo_value_equals_global_value(self, response, setting): |
|
|||
1103 | assert_response = AssertResponse(response) |
|
|||
1104 | global_css_selector = '[name={}_inherited]'.format(setting) |
|
|||
1105 | repo_css_selector = '[name={}]'.format(setting) |
|
|||
1106 | repo_element = assert_response.get_element(repo_css_selector) |
|
|||
1107 | global_element = assert_response.get_element(global_css_selector) |
|
|||
1108 | assert repo_element.value == global_element.value |
|
|||
1109 |
|
||||
1110 |
|
||||
1111 | def _get_permission_for_user(user, repo): |
|
|||
1112 | perm = UserRepoToPerm.query()\ |
|
|||
1113 | .filter(UserRepoToPerm.repository == |
|
|||
1114 | Repository.get_by_repo_name(repo))\ |
|
|||
1115 | .filter(UserRepoToPerm.user == User.get_by_username(user))\ |
|
|||
1116 | .all() |
|
|||
1117 | return perm |
|
This diff has been collapsed as it changes many lines, (518 lines changed) Show them Hide them | |||||
@@ -19,8 +19,12 b'' | |||||
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
21 | import pytest |
|
21 | import pytest | |
|
22 | from sqlalchemy.orm.exc import NoResultFound | |||
22 |
|
23 | |||
23 | from rhodecode.model.db import User, UserApiKeys, UserEmailMap |
|
24 | from rhodecode.lib import auth | |
|
25 | from rhodecode.lib import helpers as h | |||
|
26 | from rhodecode.model import validators | |||
|
27 | from rhodecode.model.db import User, UserApiKeys, UserEmailMap, Repository | |||
24 | from rhodecode.model.meta import Session |
|
28 | from rhodecode.model.meta import Session | |
25 | from rhodecode.model.user import UserModel |
|
29 | from rhodecode.model.user import UserModel | |
26 |
|
30 | |||
@@ -40,6 +44,27 b' def route_path(name, params=None, **kwar' | |||||
40 | ADMIN_PREFIX + '/users', |
|
44 | ADMIN_PREFIX + '/users', | |
41 | 'users_data': |
|
45 | 'users_data': | |
42 | ADMIN_PREFIX + '/users_data', |
|
46 | ADMIN_PREFIX + '/users_data', | |
|
47 | 'users_create': | |||
|
48 | ADMIN_PREFIX + '/users/create', | |||
|
49 | 'users_new': | |||
|
50 | ADMIN_PREFIX + '/users/new', | |||
|
51 | 'user_edit': | |||
|
52 | ADMIN_PREFIX + '/users/{user_id}/edit', | |||
|
53 | 'user_edit_advanced': | |||
|
54 | ADMIN_PREFIX + '/users/{user_id}/edit/advanced', | |||
|
55 | 'user_edit_global_perms': | |||
|
56 | ADMIN_PREFIX + '/users/{user_id}/edit/global_permissions', | |||
|
57 | 'user_edit_global_perms_update': | |||
|
58 | ADMIN_PREFIX + '/users/{user_id}/edit/global_permissions/update', | |||
|
59 | 'user_update': | |||
|
60 | ADMIN_PREFIX + '/users/{user_id}/update', | |||
|
61 | 'user_delete': | |||
|
62 | ADMIN_PREFIX + '/users/{user_id}/delete', | |||
|
63 | 'user_force_password_reset': | |||
|
64 | ADMIN_PREFIX + '/users/{user_id}/password_reset', | |||
|
65 | 'user_create_personal_repo_group': | |||
|
66 | ADMIN_PREFIX + '/users/{user_id}/create_repo_group', | |||
|
67 | ||||
43 | 'edit_user_auth_tokens': |
|
68 | 'edit_user_auth_tokens': | |
44 | ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens', |
|
69 | ADMIN_PREFIX + '/users/{user_id}/edit/auth_tokens', | |
45 | 'edit_user_auth_tokens_add': |
|
70 | 'edit_user_auth_tokens_add': | |
@@ -60,6 +85,15 b' def route_path(name, params=None, **kwar' | |||||
60 | ADMIN_PREFIX + '/users/{user_id}/edit/ips/new', |
|
85 | ADMIN_PREFIX + '/users/{user_id}/edit/ips/new', | |
61 | 'edit_user_ips_delete': |
|
86 | 'edit_user_ips_delete': | |
62 | ADMIN_PREFIX + '/users/{user_id}/edit/ips/delete', |
|
87 | ADMIN_PREFIX + '/users/{user_id}/edit/ips/delete', | |
|
88 | ||||
|
89 | 'edit_user_perms_summary': | |||
|
90 | ADMIN_PREFIX + '/users/{user_id}/edit/permissions_summary', | |||
|
91 | 'edit_user_perms_summary_json': | |||
|
92 | ADMIN_PREFIX + '/users/{user_id}/edit/permissions_summary/json', | |||
|
93 | ||||
|
94 | 'edit_user_audit_logs': | |||
|
95 | ADMIN_PREFIX + '/users/{user_id}/edit/audit', | |||
|
96 | ||||
63 | }[name].format(**kwargs) |
|
97 | }[name].format(**kwargs) | |
64 |
|
98 | |||
65 | if params: |
|
99 | if params: | |
@@ -135,7 +169,7 b' class TestAdminUsersView(TestController)' | |||||
135 | self.log_user() |
|
169 | self.log_user() | |
136 | user = user_util.create_user() |
|
170 | user = user_util.create_user() | |
137 | user_id = user.user_id |
|
171 | user_id = user.user_id | |
138 |
keys = user. |
|
172 | keys = user.auth_tokens | |
139 | assert 2 == len(keys) |
|
173 | assert 2 == len(keys) | |
140 |
|
174 | |||
141 | response = self.app.post( |
|
175 | response = self.app.post( | |
@@ -220,7 +254,8 b' class TestAdminUsersView(TestController)' | |||||
220 | def test_emails(self): |
|
254 | def test_emails(self): | |
221 | self.log_user() |
|
255 | self.log_user() | |
222 | user = User.get_by_username(TEST_USER_REGULAR_LOGIN) |
|
256 | user = User.get_by_username(TEST_USER_REGULAR_LOGIN) | |
223 | response = self.app.get(route_path('edit_user_emails', user_id=user.user_id)) |
|
257 | response = self.app.get( | |
|
258 | route_path('edit_user_emails', user_id=user.user_id)) | |||
224 | response.mustcontain('No additional emails specified') |
|
259 | response.mustcontain('No additional emails specified') | |
225 |
|
260 | |||
226 | def test_emails_add(self, user_util): |
|
261 | def test_emails_add(self, user_util): | |
@@ -233,7 +268,8 b' class TestAdminUsersView(TestController)' | |||||
233 | params={'new_email': 'example@rhodecode.com', |
|
268 | params={'new_email': 'example@rhodecode.com', | |
234 | 'csrf_token': self.csrf_token}) |
|
269 | 'csrf_token': self.csrf_token}) | |
235 |
|
270 | |||
236 | response = self.app.get(route_path('edit_user_emails', user_id=user_id)) |
|
271 | response = self.app.get( | |
|
272 | route_path('edit_user_emails', user_id=user_id)) | |||
237 | response.mustcontain('example@rhodecode.com') |
|
273 | response.mustcontain('example@rhodecode.com') | |
238 |
|
274 | |||
239 | def test_emails_add_existing_email(self, user_util, user_regular): |
|
275 | def test_emails_add_existing_email(self, user_util, user_regular): | |
@@ -250,7 +286,8 b' class TestAdminUsersView(TestController)' | |||||
250 | assert_session_flash( |
|
286 | assert_session_flash( | |
251 | response, 'This e-mail address is already taken') |
|
287 | response, 'This e-mail address is already taken') | |
252 |
|
288 | |||
253 | response = self.app.get(route_path('edit_user_emails', user_id=user_id)) |
|
289 | response = self.app.get( | |
|
290 | route_path('edit_user_emails', user_id=user_id)) | |||
254 | response.mustcontain(no=[existing_email]) |
|
291 | response.mustcontain(no=[existing_email]) | |
255 |
|
292 | |||
256 | def test_emails_delete(self, user_util): |
|
293 | def test_emails_delete(self, user_util): | |
@@ -263,7 +300,8 b' class TestAdminUsersView(TestController)' | |||||
263 | params={'new_email': 'example@rhodecode.com', |
|
300 | params={'new_email': 'example@rhodecode.com', | |
264 | 'csrf_token': self.csrf_token}) |
|
301 | 'csrf_token': self.csrf_token}) | |
265 |
|
302 | |||
266 | response = self.app.get(route_path('edit_user_emails', user_id=user_id)) |
|
303 | response = self.app.get( | |
|
304 | route_path('edit_user_emails', user_id=user_id)) | |||
267 | response.mustcontain('example@rhodecode.com') |
|
305 | response.mustcontain('example@rhodecode.com') | |
268 |
|
306 | |||
269 | user_email = UserEmailMap.query()\ |
|
307 | user_email = UserEmailMap.query()\ | |
@@ -277,5 +315,469 b' class TestAdminUsersView(TestController)' | |||||
277 | params={'del_email_id': del_email_id, |
|
315 | params={'del_email_id': del_email_id, | |
278 | 'csrf_token': self.csrf_token}) |
|
316 | 'csrf_token': self.csrf_token}) | |
279 |
|
317 | |||
280 | response = self.app.get(route_path('edit_user_emails', user_id=user_id)) |
|
318 | response = self.app.get( | |
281 | response.mustcontain(no=['example@rhodecode.com']) No newline at end of file |
|
319 | route_path('edit_user_emails', user_id=user_id)) | |
|
320 | response.mustcontain(no=['example@rhodecode.com']) | |||
|
321 | ||||
|
322 | ||||
|
323 | def test_create(self, request, xhr_header): | |||
|
324 | self.log_user() | |||
|
325 | username = 'newtestuser' | |||
|
326 | password = 'test12' | |||
|
327 | password_confirmation = password | |||
|
328 | name = 'name' | |||
|
329 | lastname = 'lastname' | |||
|
330 | email = 'mail@mail.com' | |||
|
331 | ||||
|
332 | self.app.get(route_path('users_new')) | |||
|
333 | ||||
|
334 | response = self.app.post(route_path('users_create'), params={ | |||
|
335 | 'username': username, | |||
|
336 | 'password': password, | |||
|
337 | 'password_confirmation': password_confirmation, | |||
|
338 | 'firstname': name, | |||
|
339 | 'active': True, | |||
|
340 | 'lastname': lastname, | |||
|
341 | 'extern_name': 'rhodecode', | |||
|
342 | 'extern_type': 'rhodecode', | |||
|
343 | 'email': email, | |||
|
344 | 'csrf_token': self.csrf_token, | |||
|
345 | }) | |||
|
346 | user_link = h.link_to( | |||
|
347 | username, | |||
|
348 | route_path( | |||
|
349 | 'user_edit', user_id=User.get_by_username(username).user_id)) | |||
|
350 | assert_session_flash(response, 'Created user %s' % (user_link,)) | |||
|
351 | ||||
|
352 | @request.addfinalizer | |||
|
353 | def cleanup(): | |||
|
354 | fixture.destroy_user(username) | |||
|
355 | Session().commit() | |||
|
356 | ||||
|
357 | new_user = User.query().filter(User.username == username).one() | |||
|
358 | ||||
|
359 | assert new_user.username == username | |||
|
360 | assert auth.check_password(password, new_user.password) | |||
|
361 | assert new_user.name == name | |||
|
362 | assert new_user.lastname == lastname | |||
|
363 | assert new_user.email == email | |||
|
364 | ||||
|
365 | response = self.app.get(route_path('users_data'), | |||
|
366 | extra_environ=xhr_header) | |||
|
367 | response.mustcontain(username) | |||
|
368 | ||||
|
369 | def test_create_err(self): | |||
|
370 | self.log_user() | |||
|
371 | username = 'new_user' | |||
|
372 | password = '' | |||
|
373 | name = 'name' | |||
|
374 | lastname = 'lastname' | |||
|
375 | email = 'errmail.com' | |||
|
376 | ||||
|
377 | self.app.get(route_path('users_new')) | |||
|
378 | ||||
|
379 | response = self.app.post(route_path('users_create'), params={ | |||
|
380 | 'username': username, | |||
|
381 | 'password': password, | |||
|
382 | 'name': name, | |||
|
383 | 'active': False, | |||
|
384 | 'lastname': lastname, | |||
|
385 | 'email': email, | |||
|
386 | 'csrf_token': self.csrf_token, | |||
|
387 | }) | |||
|
388 | ||||
|
389 | msg = validators.ValidUsername( | |||
|
390 | False, {})._messages['system_invalid_username'] | |||
|
391 | msg = h.html_escape(msg % {'username': 'new_user'}) | |||
|
392 | response.mustcontain('<span class="error-message">%s</span>' % msg) | |||
|
393 | response.mustcontain( | |||
|
394 | '<span class="error-message">Please enter a value</span>') | |||
|
395 | response.mustcontain( | |||
|
396 | '<span class="error-message">An email address must contain a' | |||
|
397 | ' single @</span>') | |||
|
398 | ||||
|
399 | def get_user(): | |||
|
400 | Session().query(User).filter(User.username == username).one() | |||
|
401 | ||||
|
402 | with pytest.raises(NoResultFound): | |||
|
403 | get_user() | |||
|
404 | ||||
|
405 | def test_new(self): | |||
|
406 | self.log_user() | |||
|
407 | self.app.get(route_path('users_new')) | |||
|
408 | ||||
|
409 | @pytest.mark.parametrize("name, attrs", [ | |||
|
410 | ('firstname', {'firstname': 'new_username'}), | |||
|
411 | ('lastname', {'lastname': 'new_username'}), | |||
|
412 | ('admin', {'admin': True}), | |||
|
413 | ('admin', {'admin': False}), | |||
|
414 | ('extern_type', {'extern_type': 'ldap'}), | |||
|
415 | ('extern_type', {'extern_type': None}), | |||
|
416 | ('extern_name', {'extern_name': 'test'}), | |||
|
417 | ('extern_name', {'extern_name': None}), | |||
|
418 | ('active', {'active': False}), | |||
|
419 | ('active', {'active': True}), | |||
|
420 | ('email', {'email': 'some@email.com'}), | |||
|
421 | ('language', {'language': 'de'}), | |||
|
422 | ('language', {'language': 'en'}), | |||
|
423 | # ('new_password', {'new_password': 'foobar123', | |||
|
424 | # 'password_confirmation': 'foobar123'}) | |||
|
425 | ]) | |||
|
426 | def test_update(self, name, attrs, user_util): | |||
|
427 | self.log_user() | |||
|
428 | usr = user_util.create_user( | |||
|
429 | password='qweqwe', | |||
|
430 | email='testme@rhodecode.org', | |||
|
431 | extern_type='rhodecode', | |||
|
432 | extern_name='xxx', | |||
|
433 | ) | |||
|
434 | user_id = usr.user_id | |||
|
435 | Session().commit() | |||
|
436 | ||||
|
437 | params = usr.get_api_data() | |||
|
438 | cur_lang = params['language'] or 'en' | |||
|
439 | params.update({ | |||
|
440 | 'password_confirmation': '', | |||
|
441 | 'new_password': '', | |||
|
442 | 'language': cur_lang, | |||
|
443 | 'csrf_token': self.csrf_token, | |||
|
444 | }) | |||
|
445 | params.update({'new_password': ''}) | |||
|
446 | params.update(attrs) | |||
|
447 | if name == 'email': | |||
|
448 | params['emails'] = [attrs['email']] | |||
|
449 | elif name == 'extern_type': | |||
|
450 | # cannot update this via form, expected value is original one | |||
|
451 | params['extern_type'] = "rhodecode" | |||
|
452 | elif name == 'extern_name': | |||
|
453 | # cannot update this via form, expected value is original one | |||
|
454 | params['extern_name'] = 'xxx' | |||
|
455 | # special case since this user is not | |||
|
456 | # logged in yet his data is not filled | |||
|
457 | # so we use creation data | |||
|
458 | ||||
|
459 | response = self.app.post( | |||
|
460 | route_path('user_update', user_id=usr.user_id), params) | |||
|
461 | assert response.status_int == 302 | |||
|
462 | assert_session_flash(response, 'User updated successfully') | |||
|
463 | ||||
|
464 | updated_user = User.get(user_id) | |||
|
465 | updated_params = updated_user.get_api_data() | |||
|
466 | updated_params.update({'password_confirmation': ''}) | |||
|
467 | updated_params.update({'new_password': ''}) | |||
|
468 | ||||
|
469 | del params['csrf_token'] | |||
|
470 | assert params == updated_params | |||
|
471 | ||||
|
472 | def test_update_and_migrate_password( | |||
|
473 | self, autologin_user, real_crypto_backend, user_util): | |||
|
474 | ||||
|
475 | user = user_util.create_user() | |||
|
476 | temp_user = user.username | |||
|
477 | user.password = auth._RhodeCodeCryptoSha256().hash_create( | |||
|
478 | b'test123') | |||
|
479 | Session().add(user) | |||
|
480 | Session().commit() | |||
|
481 | ||||
|
482 | params = user.get_api_data() | |||
|
483 | ||||
|
484 | params.update({ | |||
|
485 | 'password_confirmation': 'qweqwe123', | |||
|
486 | 'new_password': 'qweqwe123', | |||
|
487 | 'language': 'en', | |||
|
488 | 'csrf_token': autologin_user.csrf_token, | |||
|
489 | }) | |||
|
490 | ||||
|
491 | response = self.app.post( | |||
|
492 | route_path('user_update', user_id=user.user_id), params) | |||
|
493 | assert response.status_int == 302 | |||
|
494 | assert_session_flash(response, 'User updated successfully') | |||
|
495 | ||||
|
496 | # new password should be bcrypted, after log-in and transfer | |||
|
497 | user = User.get_by_username(temp_user) | |||
|
498 | assert user.password.startswith('$') | |||
|
499 | ||||
|
500 | updated_user = User.get_by_username(temp_user) | |||
|
501 | updated_params = updated_user.get_api_data() | |||
|
502 | updated_params.update({'password_confirmation': 'qweqwe123'}) | |||
|
503 | updated_params.update({'new_password': 'qweqwe123'}) | |||
|
504 | ||||
|
505 | del params['csrf_token'] | |||
|
506 | assert params == updated_params | |||
|
507 | ||||
|
508 | def test_delete(self): | |||
|
509 | self.log_user() | |||
|
510 | username = 'newtestuserdeleteme' | |||
|
511 | ||||
|
512 | fixture.create_user(name=username) | |||
|
513 | ||||
|
514 | new_user = Session().query(User)\ | |||
|
515 | .filter(User.username == username).one() | |||
|
516 | response = self.app.post( | |||
|
517 | route_path('user_delete', user_id=new_user.user_id), | |||
|
518 | params={'csrf_token': self.csrf_token}) | |||
|
519 | ||||
|
520 | assert_session_flash(response, 'Successfully deleted user') | |||
|
521 | ||||
|
522 | def test_delete_owner_of_repository(self, request, user_util): | |||
|
523 | self.log_user() | |||
|
524 | obj_name = 'test_repo' | |||
|
525 | usr = user_util.create_user() | |||
|
526 | username = usr.username | |||
|
527 | fixture.create_repo(obj_name, cur_user=usr.username) | |||
|
528 | ||||
|
529 | new_user = Session().query(User)\ | |||
|
530 | .filter(User.username == username).one() | |||
|
531 | response = self.app.post( | |||
|
532 | route_path('user_delete', user_id=new_user.user_id), | |||
|
533 | params={'csrf_token': self.csrf_token}) | |||
|
534 | ||||
|
535 | msg = 'user "%s" still owns 1 repositories and cannot be removed. ' \ | |||
|
536 | 'Switch owners or remove those repositories:%s' % (username, | |||
|
537 | obj_name) | |||
|
538 | assert_session_flash(response, msg) | |||
|
539 | fixture.destroy_repo(obj_name) | |||
|
540 | ||||
|
541 | def test_delete_owner_of_repository_detaching(self, request, user_util): | |||
|
542 | self.log_user() | |||
|
543 | obj_name = 'test_repo' | |||
|
544 | usr = user_util.create_user(auto_cleanup=False) | |||
|
545 | username = usr.username | |||
|
546 | fixture.create_repo(obj_name, cur_user=usr.username) | |||
|
547 | ||||
|
548 | new_user = Session().query(User)\ | |||
|
549 | .filter(User.username == username).one() | |||
|
550 | response = self.app.post( | |||
|
551 | route_path('user_delete', user_id=new_user.user_id), | |||
|
552 | params={'user_repos': 'detach', 'csrf_token': self.csrf_token}) | |||
|
553 | ||||
|
554 | msg = 'Detached 1 repositories' | |||
|
555 | assert_session_flash(response, msg) | |||
|
556 | fixture.destroy_repo(obj_name) | |||
|
557 | ||||
|
558 | def test_delete_owner_of_repository_deleting(self, request, user_util): | |||
|
559 | self.log_user() | |||
|
560 | obj_name = 'test_repo' | |||
|
561 | usr = user_util.create_user(auto_cleanup=False) | |||
|
562 | username = usr.username | |||
|
563 | fixture.create_repo(obj_name, cur_user=usr.username) | |||
|
564 | ||||
|
565 | new_user = Session().query(User)\ | |||
|
566 | .filter(User.username == username).one() | |||
|
567 | response = self.app.post( | |||
|
568 | route_path('user_delete', user_id=new_user.user_id), | |||
|
569 | params={'user_repos': 'delete', 'csrf_token': self.csrf_token}) | |||
|
570 | ||||
|
571 | msg = 'Deleted 1 repositories' | |||
|
572 | assert_session_flash(response, msg) | |||
|
573 | ||||
|
574 | def test_delete_owner_of_repository_group(self, request, user_util): | |||
|
575 | self.log_user() | |||
|
576 | obj_name = 'test_group' | |||
|
577 | usr = user_util.create_user() | |||
|
578 | username = usr.username | |||
|
579 | fixture.create_repo_group(obj_name, cur_user=usr.username) | |||
|
580 | ||||
|
581 | new_user = Session().query(User)\ | |||
|
582 | .filter(User.username == username).one() | |||
|
583 | response = self.app.post( | |||
|
584 | route_path('user_delete', user_id=new_user.user_id), | |||
|
585 | params={'csrf_token': self.csrf_token}) | |||
|
586 | ||||
|
587 | msg = 'user "%s" still owns 1 repository groups and cannot be removed. ' \ | |||
|
588 | 'Switch owners or remove those repository groups:%s' % (username, | |||
|
589 | obj_name) | |||
|
590 | assert_session_flash(response, msg) | |||
|
591 | fixture.destroy_repo_group(obj_name) | |||
|
592 | ||||
|
593 | def test_delete_owner_of_repository_group_detaching(self, request, user_util): | |||
|
594 | self.log_user() | |||
|
595 | obj_name = 'test_group' | |||
|
596 | usr = user_util.create_user(auto_cleanup=False) | |||
|
597 | username = usr.username | |||
|
598 | fixture.create_repo_group(obj_name, cur_user=usr.username) | |||
|
599 | ||||
|
600 | new_user = Session().query(User)\ | |||
|
601 | .filter(User.username == username).one() | |||
|
602 | response = self.app.post( | |||
|
603 | route_path('user_delete', user_id=new_user.user_id), | |||
|
604 | params={'user_repo_groups': 'delete', 'csrf_token': self.csrf_token}) | |||
|
605 | ||||
|
606 | msg = 'Deleted 1 repository groups' | |||
|
607 | assert_session_flash(response, msg) | |||
|
608 | ||||
|
609 | def test_delete_owner_of_repository_group_deleting(self, request, user_util): | |||
|
610 | self.log_user() | |||
|
611 | obj_name = 'test_group' | |||
|
612 | usr = user_util.create_user(auto_cleanup=False) | |||
|
613 | username = usr.username | |||
|
614 | fixture.create_repo_group(obj_name, cur_user=usr.username) | |||
|
615 | ||||
|
616 | new_user = Session().query(User)\ | |||
|
617 | .filter(User.username == username).one() | |||
|
618 | response = self.app.post( | |||
|
619 | route_path('user_delete', user_id=new_user.user_id), | |||
|
620 | params={'user_repo_groups': 'detach', 'csrf_token': self.csrf_token}) | |||
|
621 | ||||
|
622 | msg = 'Detached 1 repository groups' | |||
|
623 | assert_session_flash(response, msg) | |||
|
624 | fixture.destroy_repo_group(obj_name) | |||
|
625 | ||||
|
626 | def test_delete_owner_of_user_group(self, request, user_util): | |||
|
627 | self.log_user() | |||
|
628 | obj_name = 'test_user_group' | |||
|
629 | usr = user_util.create_user() | |||
|
630 | username = usr.username | |||
|
631 | fixture.create_user_group(obj_name, cur_user=usr.username) | |||
|
632 | ||||
|
633 | new_user = Session().query(User)\ | |||
|
634 | .filter(User.username == username).one() | |||
|
635 | response = self.app.post( | |||
|
636 | route_path('user_delete', user_id=new_user.user_id), | |||
|
637 | params={'csrf_token': self.csrf_token}) | |||
|
638 | ||||
|
639 | msg = 'user "%s" still owns 1 user groups and cannot be removed. ' \ | |||
|
640 | 'Switch owners or remove those user groups:%s' % (username, | |||
|
641 | obj_name) | |||
|
642 | assert_session_flash(response, msg) | |||
|
643 | fixture.destroy_user_group(obj_name) | |||
|
644 | ||||
|
645 | def test_delete_owner_of_user_group_detaching(self, request, user_util): | |||
|
646 | self.log_user() | |||
|
647 | obj_name = 'test_user_group' | |||
|
648 | usr = user_util.create_user(auto_cleanup=False) | |||
|
649 | username = usr.username | |||
|
650 | fixture.create_user_group(obj_name, cur_user=usr.username) | |||
|
651 | ||||
|
652 | new_user = Session().query(User)\ | |||
|
653 | .filter(User.username == username).one() | |||
|
654 | try: | |||
|
655 | response = self.app.post( | |||
|
656 | route_path('user_delete', user_id=new_user.user_id), | |||
|
657 | params={'user_user_groups': 'detach', | |||
|
658 | 'csrf_token': self.csrf_token}) | |||
|
659 | ||||
|
660 | msg = 'Detached 1 user groups' | |||
|
661 | assert_session_flash(response, msg) | |||
|
662 | finally: | |||
|
663 | fixture.destroy_user_group(obj_name) | |||
|
664 | ||||
|
665 | def test_delete_owner_of_user_group_deleting(self, request, user_util): | |||
|
666 | self.log_user() | |||
|
667 | obj_name = 'test_user_group' | |||
|
668 | usr = user_util.create_user(auto_cleanup=False) | |||
|
669 | username = usr.username | |||
|
670 | fixture.create_user_group(obj_name, cur_user=usr.username) | |||
|
671 | ||||
|
672 | new_user = Session().query(User)\ | |||
|
673 | .filter(User.username == username).one() | |||
|
674 | response = self.app.post( | |||
|
675 | route_path('user_delete', user_id=new_user.user_id), | |||
|
676 | params={'user_user_groups': 'delete', 'csrf_token': self.csrf_token}) | |||
|
677 | ||||
|
678 | msg = 'Deleted 1 user groups' | |||
|
679 | assert_session_flash(response, msg) | |||
|
680 | ||||
|
681 | def test_edit(self, user_util): | |||
|
682 | self.log_user() | |||
|
683 | user = user_util.create_user() | |||
|
684 | self.app.get(route_path('user_edit', user_id=user.user_id)) | |||
|
685 | ||||
|
686 | def test_edit_default_user_redirect(self): | |||
|
687 | self.log_user() | |||
|
688 | user = User.get_default_user() | |||
|
689 | self.app.get(route_path('user_edit', user_id=user.user_id), status=302) | |||
|
690 | ||||
|
691 | @pytest.mark.parametrize( | |||
|
692 | 'repo_create, repo_create_write, user_group_create, repo_group_create,' | |||
|
693 | 'fork_create, inherit_default_permissions, expect_error,' | |||
|
694 | 'expect_form_error', [ | |||
|
695 | ('hg.create.none', 'hg.create.write_on_repogroup.false', | |||
|
696 | 'hg.usergroup.create.false', 'hg.repogroup.create.false', | |||
|
697 | 'hg.fork.none', 'hg.inherit_default_perms.false', False, False), | |||
|
698 | ('hg.create.repository', 'hg.create.write_on_repogroup.false', | |||
|
699 | 'hg.usergroup.create.false', 'hg.repogroup.create.false', | |||
|
700 | 'hg.fork.none', 'hg.inherit_default_perms.false', False, False), | |||
|
701 | ('hg.create.repository', 'hg.create.write_on_repogroup.true', | |||
|
702 | 'hg.usergroup.create.true', 'hg.repogroup.create.true', | |||
|
703 | 'hg.fork.repository', 'hg.inherit_default_perms.false', False, | |||
|
704 | False), | |||
|
705 | ('hg.create.XXX', 'hg.create.write_on_repogroup.true', | |||
|
706 | 'hg.usergroup.create.true', 'hg.repogroup.create.true', | |||
|
707 | 'hg.fork.repository', 'hg.inherit_default_perms.false', False, | |||
|
708 | True), | |||
|
709 | ('', '', '', '', '', '', True, False), | |||
|
710 | ]) | |||
|
711 | def test_global_perms_on_user( | |||
|
712 | self, repo_create, repo_create_write, user_group_create, | |||
|
713 | repo_group_create, fork_create, expect_error, expect_form_error, | |||
|
714 | inherit_default_permissions, user_util): | |||
|
715 | self.log_user() | |||
|
716 | user = user_util.create_user() | |||
|
717 | uid = user.user_id | |||
|
718 | ||||
|
719 | # ENABLE REPO CREATE ON A GROUP | |||
|
720 | perm_params = { | |||
|
721 | 'inherit_default_permissions': False, | |||
|
722 | 'default_repo_create': repo_create, | |||
|
723 | 'default_repo_create_on_write': repo_create_write, | |||
|
724 | 'default_user_group_create': user_group_create, | |||
|
725 | 'default_repo_group_create': repo_group_create, | |||
|
726 | 'default_fork_create': fork_create, | |||
|
727 | 'default_inherit_default_permissions': inherit_default_permissions, | |||
|
728 | 'csrf_token': self.csrf_token, | |||
|
729 | } | |||
|
730 | response = self.app.post( | |||
|
731 | route_path('user_edit_global_perms_update', user_id=uid), | |||
|
732 | params=perm_params) | |||
|
733 | ||||
|
734 | if expect_form_error: | |||
|
735 | assert response.status_int == 200 | |||
|
736 | response.mustcontain('Value must be one of') | |||
|
737 | else: | |||
|
738 | if expect_error: | |||
|
739 | msg = 'An error occurred during permissions saving' | |||
|
740 | else: | |||
|
741 | msg = 'User global permissions updated successfully' | |||
|
742 | ug = User.get(uid) | |||
|
743 | del perm_params['inherit_default_permissions'] | |||
|
744 | del perm_params['csrf_token'] | |||
|
745 | assert perm_params == ug.get_default_perms() | |||
|
746 | assert_session_flash(response, msg) | |||
|
747 | ||||
|
748 | def test_global_permissions_initial_values(self, user_util): | |||
|
749 | self.log_user() | |||
|
750 | user = user_util.create_user() | |||
|
751 | uid = user.user_id | |||
|
752 | response = self.app.get( | |||
|
753 | route_path('user_edit_global_perms', user_id=uid)) | |||
|
754 | default_user = User.get_default_user() | |||
|
755 | default_permissions = default_user.get_default_perms() | |||
|
756 | assert_response = response.assert_response() | |||
|
757 | expected_permissions = ( | |||
|
758 | 'default_repo_create', 'default_repo_create_on_write', | |||
|
759 | 'default_fork_create', 'default_repo_group_create', | |||
|
760 | 'default_user_group_create', 'default_inherit_default_permissions') | |||
|
761 | for permission in expected_permissions: | |||
|
762 | css_selector = '[name={}][checked=checked]'.format(permission) | |||
|
763 | element = assert_response.get_element(css_selector) | |||
|
764 | assert element.value == default_permissions[permission] | |||
|
765 | ||||
|
766 | def test_perms_summary_page(self): | |||
|
767 | user = self.log_user() | |||
|
768 | response = self.app.get( | |||
|
769 | route_path('edit_user_perms_summary', user_id=user['user_id'])) | |||
|
770 | for repo in Repository.query().all(): | |||
|
771 | response.mustcontain(repo.repo_name) | |||
|
772 | ||||
|
773 | def test_perms_summary_page_json(self): | |||
|
774 | user = self.log_user() | |||
|
775 | response = self.app.get( | |||
|
776 | route_path('edit_user_perms_summary_json', user_id=user['user_id'])) | |||
|
777 | for repo in Repository.query().all(): | |||
|
778 | response.mustcontain(repo.repo_name) | |||
|
779 | ||||
|
780 | def test_audit_log_page(self): | |||
|
781 | user = self.log_user() | |||
|
782 | self.app.get( | |||
|
783 | route_path('edit_user_audit_logs', user_id=user['user_id'])) |
@@ -20,11 +20,11 b'' | |||||
20 |
|
20 | |||
21 | import logging |
|
21 | import logging | |
22 |
|
22 | |||
|
23 | from pyramid.httpexceptions import HTTPNotFound | |||
23 | from pyramid.view import view_config |
|
24 | from pyramid.view import view_config | |
24 | from sqlalchemy.orm import joinedload |
|
|||
25 |
|
25 | |||
26 | from rhodecode.apps._base import BaseAppView |
|
26 | from rhodecode.apps._base import BaseAppView | |
27 | from rhodecode.model.db import UserLog |
|
27 | from rhodecode.model.db import joinedload, UserLog | |
28 | from rhodecode.lib.user_log_filter import user_log_filter |
|
28 | from rhodecode.lib.user_log_filter import user_log_filter | |
29 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
29 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator | |
30 | from rhodecode.lib.utils2 import safe_int |
|
30 | from rhodecode.lib.utils2 import safe_int | |
@@ -71,3 +71,21 b' class AdminAuditLogsView(BaseAppView):' | |||||
71 | c.audit_logs = Page(users_log, page=p, items_per_page=10, |
|
71 | c.audit_logs = Page(users_log, page=p, items_per_page=10, | |
72 | url=url_generator) |
|
72 | url=url_generator) | |
73 | return self._get_template_context(c) |
|
73 | return self._get_template_context(c) | |
|
74 | ||||
|
75 | @LoginRequired() | |||
|
76 | @HasPermissionAllDecorator('hg.admin') | |||
|
77 | @view_config( | |||
|
78 | route_name='admin_audit_log_entry', request_method='GET', | |||
|
79 | renderer='rhodecode:templates/admin/admin_audit_log_entry.mako') | |||
|
80 | def admin_audit_log_entry(self): | |||
|
81 | c = self.load_default_context() | |||
|
82 | audit_log_id = self.request.matchdict['audit_log_id'] | |||
|
83 | ||||
|
84 | c.audit_log_entry = UserLog.query()\ | |||
|
85 | .options(joinedload(UserLog.user))\ | |||
|
86 | .options(joinedload(UserLog.repository))\ | |||
|
87 | .filter(UserLog.user_log_id == audit_log_id).scalar() | |||
|
88 | if not c.audit_log_entry: | |||
|
89 | raise HTTPNotFound() | |||
|
90 | ||||
|
91 | return self._get_template_context(c) |
@@ -20,7 +20,6 b'' | |||||
20 |
|
20 | |||
21 | import logging |
|
21 | import logging | |
22 |
|
22 | |||
23 |
|
||||
24 | from pyramid.httpexceptions import HTTPFound |
|
23 | from pyramid.httpexceptions import HTTPFound | |
25 | from pyramid.view import view_config |
|
24 | from pyramid.view import view_config | |
26 |
|
25 | |||
@@ -54,8 +53,10 b' class AdminMainView(BaseAppView):' | |||||
54 | :param pull_request_id: id of pull requests in the system |
|
53 | :param pull_request_id: id of pull requests in the system | |
55 | """ |
|
54 | """ | |
56 |
|
55 | |||
57 | pull_request_id = self.request.matchdict.get('pull_request_id') |
|
56 | pull_request = PullRequest.get_or_404( | |
58 | pull_request = PullRequest.get_or_404(pull_request_id, pyramid_exc=True) |
|
57 | self.request.matchdict['pull_request_id']) | |
|
58 | pull_request_id = pull_request.pull_request_id | |||
|
59 | ||||
59 | repo_name = pull_request.target_repo.repo_name |
|
60 | repo_name = pull_request.target_repo.repo_name | |
60 |
|
61 | |||
61 | raise HTTPFound( |
|
62 | raise HTTPFound( |
@@ -21,7 +21,6 b'' | |||||
21 | import collections |
|
21 | import collections | |
22 | import logging |
|
22 | import logging | |
23 |
|
23 | |||
24 |
|
||||
25 | from pyramid.view import view_config |
|
24 | from pyramid.view import view_config | |
26 |
|
25 | |||
27 | from rhodecode.apps._base import BaseAppView |
|
26 | from rhodecode.apps._base import BaseAppView | |
@@ -48,7 +47,7 b' class OpenSourceLicensesAdminSettingsVie' | |||||
48 | c = self.load_default_context() |
|
47 | c = self.load_default_context() | |
49 | c.active = 'open_source' |
|
48 | c.active = 'open_source' | |
50 | c.navlist = navigation_list(self.request) |
|
49 | c.navlist = navigation_list(self.request) | |
51 | c.opensource_licenses = collections.OrderedDict( |
|
50 | items = sorted(read_opensource_licenses().items(), key=lambda t: t[0]) | |
52 | sorted(read_opensource_licenses().items(), key=lambda t: t[0])) |
|
51 | c.opensource_licenses = collections.OrderedDict(items) | |
53 |
|
52 | |||
54 | return self._get_template_context(c) |
|
53 | return self._get_template_context(c) |
This diff has been collapsed as it changes many lines, (839 lines changed) Show them Hide them | |||||
@@ -21,50 +21,51 b'' | |||||
21 | import logging |
|
21 | import logging | |
22 | import datetime |
|
22 | import datetime | |
23 | import formencode |
|
23 | import formencode | |
|
24 | import formencode.htmlfill | |||
24 |
|
25 | |||
25 | from pyramid.httpexceptions import HTTPFound |
|
26 | from pyramid.httpexceptions import HTTPFound | |
26 | from pyramid.view import view_config |
|
27 | from pyramid.view import view_config | |
27 | from sqlalchemy.sql.functions import coalesce |
|
28 | from pyramid.renderers import render | |
|
29 | from pyramid.response import Response | |||
28 |
|
30 | |||
29 | from rhodecode.apps._base import BaseAppView, DataGridAppView |
|
31 | from rhodecode.apps._base import BaseAppView, DataGridAppView, UserAppView | |
|
32 | from rhodecode.apps.ssh_support import SshKeyFileChangeEvent | |||
|
33 | from rhodecode.authentication.plugins import auth_rhodecode | |||
|
34 | from rhodecode.events import trigger | |||
30 |
|
35 | |||
31 | from rhodecode.lib import audit_logger |
|
36 | from rhodecode.lib import audit_logger | |
|
37 | from rhodecode.lib.exceptions import ( | |||
|
38 | UserCreationError, UserOwnsReposException, UserOwnsRepoGroupsException, | |||
|
39 | UserOwnsUserGroupsException, DefaultUserException) | |||
32 | from rhodecode.lib.ext_json import json |
|
40 | from rhodecode.lib.ext_json import json | |
33 | from rhodecode.lib.auth import ( |
|
41 | from rhodecode.lib.auth import ( | |
34 | LoginRequired, HasPermissionAllDecorator, CSRFRequired) |
|
42 | LoginRequired, HasPermissionAllDecorator, CSRFRequired) | |
35 | from rhodecode.lib import helpers as h |
|
43 | from rhodecode.lib import helpers as h | |
36 |
from rhodecode.lib.utils import |
|
44 | from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict | |
37 | from rhodecode.lib.utils2 import safe_int, safe_unicode |
|
|||
38 | from rhodecode.model.auth_token import AuthTokenModel |
|
45 | from rhodecode.model.auth_token import AuthTokenModel | |
|
46 | from rhodecode.model.forms import ( | |||
|
47 | UserForm, UserIndividualPermissionsForm, UserPermissionsForm) | |||
|
48 | from rhodecode.model.permission import PermissionModel | |||
|
49 | from rhodecode.model.repo_group import RepoGroupModel | |||
|
50 | from rhodecode.model.ssh_key import SshKeyModel | |||
39 | from rhodecode.model.user import UserModel |
|
51 | from rhodecode.model.user import UserModel | |
40 | from rhodecode.model.user_group import UserGroupModel |
|
52 | from rhodecode.model.user_group import UserGroupModel | |
41 | from rhodecode.model.db import User, or_, UserIpMap, UserEmailMap, UserApiKeys |
|
53 | from rhodecode.model.db import ( | |
|
54 | or_, coalesce,IntegrityError, User, UserGroup, UserIpMap, UserEmailMap, | |||
|
55 | UserApiKeys, UserSshKeys, RepoGroup) | |||
42 | from rhodecode.model.meta import Session |
|
56 | from rhodecode.model.meta import Session | |
43 |
|
57 | |||
44 | log = logging.getLogger(__name__) |
|
58 | log = logging.getLogger(__name__) | |
45 |
|
59 | |||
46 |
|
60 | |||
47 | class AdminUsersView(BaseAppView, DataGridAppView): |
|
61 | class AdminUsersView(BaseAppView, DataGridAppView): | |
48 | ALLOW_SCOPED_TOKENS = False |
|
|||
49 | """ |
|
|||
50 | This view has alternative version inside EE, if modified please take a look |
|
|||
51 | in there as well. |
|
|||
52 | """ |
|
|||
53 |
|
62 | |||
54 | def load_default_context(self): |
|
63 | def load_default_context(self): | |
55 | c = self._get_local_tmpl_context() |
|
64 | c = self._get_local_tmpl_context() | |
56 | c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS |
|
|||
57 | self._register_global_c(c) |
|
65 | self._register_global_c(c) | |
58 | return c |
|
66 | return c | |
59 |
|
67 | |||
60 | def _redirect_for_default_user(self, username): |
|
68 | @LoginRequired() | |
61 | _ = self.request.translate |
|
|||
62 | if username == User.DEFAULT_USER: |
|
|||
63 | h.flash(_("You can't edit this user"), category='warning') |
|
|||
64 | # TODO(marcink): redirect to 'users' admin panel once this |
|
|||
65 | # is a pyramid view |
|
|||
66 | raise HTTPFound('/') |
|
|||
67 |
|
||||
68 | @HasPermissionAllDecorator('hg.admin') |
|
69 | @HasPermissionAllDecorator('hg.admin') | |
69 | @view_config( |
|
70 | @view_config( | |
70 | route_name='users', request_method='GET', |
|
71 | route_name='users', request_method='GET', | |
@@ -73,16 +74,23 b' class AdminUsersView(BaseAppView, DataGr' | |||||
73 | c = self.load_default_context() |
|
74 | c = self.load_default_context() | |
74 | return self._get_template_context(c) |
|
75 | return self._get_template_context(c) | |
75 |
|
76 | |||
|
77 | @LoginRequired() | |||
76 | @HasPermissionAllDecorator('hg.admin') |
|
78 | @HasPermissionAllDecorator('hg.admin') | |
77 | @view_config( |
|
79 | @view_config( | |
78 | # renderer defined below |
|
80 | # renderer defined below | |
79 | route_name='users_data', request_method='GET', |
|
81 | route_name='users_data', request_method='GET', | |
80 | renderer='json_ext', xhr=True) |
|
82 | renderer='json_ext', xhr=True) | |
81 | def users_list_data(self): |
|
83 | def users_list_data(self): | |
|
84 | column_map = { | |||
|
85 | 'first_name': 'name', | |||
|
86 | 'last_name': 'lastname', | |||
|
87 | } | |||
82 | draw, start, limit = self._extract_chunk(self.request) |
|
88 | draw, start, limit = self._extract_chunk(self.request) | |
83 |
search_q, order_by, order_dir = self._extract_ordering( |
|
89 | search_q, order_by, order_dir = self._extract_ordering( | |
|
90 | self.request, column_map=column_map) | |||
84 |
|
91 | |||
85 | _render = PartialRenderer('data_table/_dt_elements.mako') |
|
92 | _render = self.request.get_partial_renderer( | |
|
93 | 'data_table/_dt_elements.mako') | |||
86 |
|
94 | |||
87 | def user_actions(user_id, username): |
|
95 | def user_actions(user_id, username): | |
88 | return _render("user_actions", user_id, username) |
|
96 | return _render("user_actions", user_id, username) | |
@@ -126,7 +134,7 b' class AdminUsersView(BaseAppView, DataGr' | |||||
126 | users_data = [] |
|
134 | users_data = [] | |
127 | for user in users_list: |
|
135 | for user in users_list: | |
128 | users_data.append({ |
|
136 | users_data.append({ | |
129 | "username": h.gravatar_with_user(user.username), |
|
137 | "username": h.gravatar_with_user(self.request, user.username), | |
130 | "email": user.email, |
|
138 | "email": user.email, | |
131 | "first_name": user.first_name, |
|
139 | "first_name": user.first_name, | |
132 | "last_name": user.last_name, |
|
140 | "last_name": user.last_name, | |
@@ -149,6 +157,529 b' class AdminUsersView(BaseAppView, DataGr' | |||||
149 |
|
157 | |||
150 | return data |
|
158 | return data | |
151 |
|
159 | |||
|
160 | def _set_personal_repo_group_template_vars(self, c_obj): | |||
|
161 | DummyUser = AttributeDict({ | |||
|
162 | 'username': '${username}', | |||
|
163 | 'user_id': '${user_id}', | |||
|
164 | }) | |||
|
165 | c_obj.default_create_repo_group = RepoGroupModel() \ | |||
|
166 | .get_default_create_personal_repo_group() | |||
|
167 | c_obj.personal_repo_group_name = RepoGroupModel() \ | |||
|
168 | .get_personal_group_name(DummyUser) | |||
|
169 | ||||
|
170 | @LoginRequired() | |||
|
171 | @HasPermissionAllDecorator('hg.admin') | |||
|
172 | @view_config( | |||
|
173 | route_name='users_new', request_method='GET', | |||
|
174 | renderer='rhodecode:templates/admin/users/user_add.mako') | |||
|
175 | def users_new(self): | |||
|
176 | _ = self.request.translate | |||
|
177 | c = self.load_default_context() | |||
|
178 | c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name | |||
|
179 | self._set_personal_repo_group_template_vars(c) | |||
|
180 | return self._get_template_context(c) | |||
|
181 | ||||
|
182 | @LoginRequired() | |||
|
183 | @HasPermissionAllDecorator('hg.admin') | |||
|
184 | @CSRFRequired() | |||
|
185 | @view_config( | |||
|
186 | route_name='users_create', request_method='POST', | |||
|
187 | renderer='rhodecode:templates/admin/users/user_add.mako') | |||
|
188 | def users_create(self): | |||
|
189 | _ = self.request.translate | |||
|
190 | c = self.load_default_context() | |||
|
191 | c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name | |||
|
192 | user_model = UserModel() | |||
|
193 | user_form = UserForm()() | |||
|
194 | try: | |||
|
195 | form_result = user_form.to_python(dict(self.request.POST)) | |||
|
196 | user = user_model.create(form_result) | |||
|
197 | Session().flush() | |||
|
198 | creation_data = user.get_api_data() | |||
|
199 | username = form_result['username'] | |||
|
200 | ||||
|
201 | audit_logger.store_web( | |||
|
202 | 'user.create', action_data={'data': creation_data}, | |||
|
203 | user=c.rhodecode_user) | |||
|
204 | ||||
|
205 | user_link = h.link_to( | |||
|
206 | h.escape(username), | |||
|
207 | h.route_path('user_edit', user_id=user.user_id)) | |||
|
208 | h.flash(h.literal(_('Created user %(user_link)s') | |||
|
209 | % {'user_link': user_link}), category='success') | |||
|
210 | Session().commit() | |||
|
211 | except formencode.Invalid as errors: | |||
|
212 | self._set_personal_repo_group_template_vars(c) | |||
|
213 | data = render( | |||
|
214 | 'rhodecode:templates/admin/users/user_add.mako', | |||
|
215 | self._get_template_context(c), self.request) | |||
|
216 | html = formencode.htmlfill.render( | |||
|
217 | data, | |||
|
218 | defaults=errors.value, | |||
|
219 | errors=errors.error_dict or {}, | |||
|
220 | prefix_error=False, | |||
|
221 | encoding="UTF-8", | |||
|
222 | force_defaults=False | |||
|
223 | ) | |||
|
224 | return Response(html) | |||
|
225 | except UserCreationError as e: | |||
|
226 | h.flash(e, 'error') | |||
|
227 | except Exception: | |||
|
228 | log.exception("Exception creation of user") | |||
|
229 | h.flash(_('Error occurred during creation of user %s') | |||
|
230 | % self.request.POST.get('username'), category='error') | |||
|
231 | raise HTTPFound(h.route_path('users')) | |||
|
232 | ||||
|
233 | ||||
|
234 | class UsersView(UserAppView): | |||
|
235 | ALLOW_SCOPED_TOKENS = False | |||
|
236 | """ | |||
|
237 | This view has alternative version inside EE, if modified please take a look | |||
|
238 | in there as well. | |||
|
239 | """ | |||
|
240 | ||||
|
241 | def load_default_context(self): | |||
|
242 | c = self._get_local_tmpl_context() | |||
|
243 | c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS | |||
|
244 | c.allowed_languages = [ | |||
|
245 | ('en', 'English (en)'), | |||
|
246 | ('de', 'German (de)'), | |||
|
247 | ('fr', 'French (fr)'), | |||
|
248 | ('it', 'Italian (it)'), | |||
|
249 | ('ja', 'Japanese (ja)'), | |||
|
250 | ('pl', 'Polish (pl)'), | |||
|
251 | ('pt', 'Portuguese (pt)'), | |||
|
252 | ('ru', 'Russian (ru)'), | |||
|
253 | ('zh', 'Chinese (zh)'), | |||
|
254 | ] | |||
|
255 | req = self.request | |||
|
256 | ||||
|
257 | c.available_permissions = req.registry.settings['available_permissions'] | |||
|
258 | PermissionModel().set_global_permission_choices( | |||
|
259 | c, gettext_translator=req.translate) | |||
|
260 | ||||
|
261 | self._register_global_c(c) | |||
|
262 | return c | |||
|
263 | ||||
|
264 | @LoginRequired() | |||
|
265 | @HasPermissionAllDecorator('hg.admin') | |||
|
266 | @CSRFRequired() | |||
|
267 | @view_config( | |||
|
268 | route_name='user_update', request_method='POST', | |||
|
269 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
270 | def user_update(self): | |||
|
271 | _ = self.request.translate | |||
|
272 | c = self.load_default_context() | |||
|
273 | ||||
|
274 | user_id = self.db_user_id | |||
|
275 | c.user = self.db_user | |||
|
276 | ||||
|
277 | c.active = 'profile' | |||
|
278 | c.extern_type = c.user.extern_type | |||
|
279 | c.extern_name = c.user.extern_name | |||
|
280 | c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr) | |||
|
281 | available_languages = [x[0] for x in c.allowed_languages] | |||
|
282 | _form = UserForm(edit=True, available_languages=available_languages, | |||
|
283 | old_data={'user_id': user_id, | |||
|
284 | 'email': c.user.email})() | |||
|
285 | form_result = {} | |||
|
286 | old_values = c.user.get_api_data() | |||
|
287 | try: | |||
|
288 | form_result = _form.to_python(dict(self.request.POST)) | |||
|
289 | skip_attrs = ['extern_type', 'extern_name'] | |||
|
290 | # TODO: plugin should define if username can be updated | |||
|
291 | if c.extern_type != "rhodecode": | |||
|
292 | # forbid updating username for external accounts | |||
|
293 | skip_attrs.append('username') | |||
|
294 | ||||
|
295 | UserModel().update_user( | |||
|
296 | user_id, skip_attrs=skip_attrs, **form_result) | |||
|
297 | ||||
|
298 | audit_logger.store_web( | |||
|
299 | 'user.edit', action_data={'old_data': old_values}, | |||
|
300 | user=c.rhodecode_user) | |||
|
301 | ||||
|
302 | Session().commit() | |||
|
303 | h.flash(_('User updated successfully'), category='success') | |||
|
304 | except formencode.Invalid as errors: | |||
|
305 | data = render( | |||
|
306 | 'rhodecode:templates/admin/users/user_edit.mako', | |||
|
307 | self._get_template_context(c), self.request) | |||
|
308 | html = formencode.htmlfill.render( | |||
|
309 | data, | |||
|
310 | defaults=errors.value, | |||
|
311 | errors=errors.error_dict or {}, | |||
|
312 | prefix_error=False, | |||
|
313 | encoding="UTF-8", | |||
|
314 | force_defaults=False | |||
|
315 | ) | |||
|
316 | return Response(html) | |||
|
317 | except UserCreationError as e: | |||
|
318 | h.flash(e, 'error') | |||
|
319 | except Exception: | |||
|
320 | log.exception("Exception updating user") | |||
|
321 | h.flash(_('Error occurred during update of user %s') | |||
|
322 | % form_result.get('username'), category='error') | |||
|
323 | raise HTTPFound(h.route_path('user_edit', user_id=user_id)) | |||
|
324 | ||||
|
325 | @LoginRequired() | |||
|
326 | @HasPermissionAllDecorator('hg.admin') | |||
|
327 | @CSRFRequired() | |||
|
328 | @view_config( | |||
|
329 | route_name='user_delete', request_method='POST', | |||
|
330 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
331 | def user_delete(self): | |||
|
332 | _ = self.request.translate | |||
|
333 | c = self.load_default_context() | |||
|
334 | c.user = self.db_user | |||
|
335 | ||||
|
336 | _repos = c.user.repositories | |||
|
337 | _repo_groups = c.user.repository_groups | |||
|
338 | _user_groups = c.user.user_groups | |||
|
339 | ||||
|
340 | handle_repos = None | |||
|
341 | handle_repo_groups = None | |||
|
342 | handle_user_groups = None | |||
|
343 | # dummy call for flash of handle | |||
|
344 | set_handle_flash_repos = lambda: None | |||
|
345 | set_handle_flash_repo_groups = lambda: None | |||
|
346 | set_handle_flash_user_groups = lambda: None | |||
|
347 | ||||
|
348 | if _repos and self.request.POST.get('user_repos'): | |||
|
349 | do = self.request.POST['user_repos'] | |||
|
350 | if do == 'detach': | |||
|
351 | handle_repos = 'detach' | |||
|
352 | set_handle_flash_repos = lambda: h.flash( | |||
|
353 | _('Detached %s repositories') % len(_repos), | |||
|
354 | category='success') | |||
|
355 | elif do == 'delete': | |||
|
356 | handle_repos = 'delete' | |||
|
357 | set_handle_flash_repos = lambda: h.flash( | |||
|
358 | _('Deleted %s repositories') % len(_repos), | |||
|
359 | category='success') | |||
|
360 | ||||
|
361 | if _repo_groups and self.request.POST.get('user_repo_groups'): | |||
|
362 | do = self.request.POST['user_repo_groups'] | |||
|
363 | if do == 'detach': | |||
|
364 | handle_repo_groups = 'detach' | |||
|
365 | set_handle_flash_repo_groups = lambda: h.flash( | |||
|
366 | _('Detached %s repository groups') % len(_repo_groups), | |||
|
367 | category='success') | |||
|
368 | elif do == 'delete': | |||
|
369 | handle_repo_groups = 'delete' | |||
|
370 | set_handle_flash_repo_groups = lambda: h.flash( | |||
|
371 | _('Deleted %s repository groups') % len(_repo_groups), | |||
|
372 | category='success') | |||
|
373 | ||||
|
374 | if _user_groups and self.request.POST.get('user_user_groups'): | |||
|
375 | do = self.request.POST['user_user_groups'] | |||
|
376 | if do == 'detach': | |||
|
377 | handle_user_groups = 'detach' | |||
|
378 | set_handle_flash_user_groups = lambda: h.flash( | |||
|
379 | _('Detached %s user groups') % len(_user_groups), | |||
|
380 | category='success') | |||
|
381 | elif do == 'delete': | |||
|
382 | handle_user_groups = 'delete' | |||
|
383 | set_handle_flash_user_groups = lambda: h.flash( | |||
|
384 | _('Deleted %s user groups') % len(_user_groups), | |||
|
385 | category='success') | |||
|
386 | ||||
|
387 | old_values = c.user.get_api_data() | |||
|
388 | try: | |||
|
389 | UserModel().delete(c.user, handle_repos=handle_repos, | |||
|
390 | handle_repo_groups=handle_repo_groups, | |||
|
391 | handle_user_groups=handle_user_groups) | |||
|
392 | ||||
|
393 | audit_logger.store_web( | |||
|
394 | 'user.delete', action_data={'old_data': old_values}, | |||
|
395 | user=c.rhodecode_user) | |||
|
396 | ||||
|
397 | Session().commit() | |||
|
398 | set_handle_flash_repos() | |||
|
399 | set_handle_flash_repo_groups() | |||
|
400 | set_handle_flash_user_groups() | |||
|
401 | h.flash(_('Successfully deleted user'), category='success') | |||
|
402 | except (UserOwnsReposException, UserOwnsRepoGroupsException, | |||
|
403 | UserOwnsUserGroupsException, DefaultUserException) as e: | |||
|
404 | h.flash(e, category='warning') | |||
|
405 | except Exception: | |||
|
406 | log.exception("Exception during deletion of user") | |||
|
407 | h.flash(_('An error occurred during deletion of user'), | |||
|
408 | category='error') | |||
|
409 | raise HTTPFound(h.route_path('users')) | |||
|
410 | ||||
|
411 | @LoginRequired() | |||
|
412 | @HasPermissionAllDecorator('hg.admin') | |||
|
413 | @view_config( | |||
|
414 | route_name='user_edit', request_method='GET', | |||
|
415 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
416 | def user_edit(self): | |||
|
417 | _ = self.request.translate | |||
|
418 | c = self.load_default_context() | |||
|
419 | c.user = self.db_user | |||
|
420 | ||||
|
421 | c.active = 'profile' | |||
|
422 | c.extern_type = c.user.extern_type | |||
|
423 | c.extern_name = c.user.extern_name | |||
|
424 | c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr) | |||
|
425 | ||||
|
426 | defaults = c.user.get_dict() | |||
|
427 | defaults.update({'language': c.user.user_data.get('language')}) | |||
|
428 | ||||
|
429 | data = render( | |||
|
430 | 'rhodecode:templates/admin/users/user_edit.mako', | |||
|
431 | self._get_template_context(c), self.request) | |||
|
432 | html = formencode.htmlfill.render( | |||
|
433 | data, | |||
|
434 | defaults=defaults, | |||
|
435 | encoding="UTF-8", | |||
|
436 | force_defaults=False | |||
|
437 | ) | |||
|
438 | return Response(html) | |||
|
439 | ||||
|
440 | @LoginRequired() | |||
|
441 | @HasPermissionAllDecorator('hg.admin') | |||
|
442 | @view_config( | |||
|
443 | route_name='user_edit_advanced', request_method='GET', | |||
|
444 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
445 | def user_edit_advanced(self): | |||
|
446 | _ = self.request.translate | |||
|
447 | c = self.load_default_context() | |||
|
448 | ||||
|
449 | user_id = self.db_user_id | |||
|
450 | c.user = self.db_user | |||
|
451 | ||||
|
452 | c.active = 'advanced' | |||
|
453 | c.personal_repo_group = RepoGroup.get_user_personal_repo_group(user_id) | |||
|
454 | c.personal_repo_group_name = RepoGroupModel()\ | |||
|
455 | .get_personal_group_name(c.user) | |||
|
456 | ||||
|
457 | c.user_to_review_rules = sorted( | |||
|
458 | (x.user for x in c.user.user_review_rules), | |||
|
459 | key=lambda u: u.username.lower()) | |||
|
460 | ||||
|
461 | c.first_admin = User.get_first_super_admin() | |||
|
462 | defaults = c.user.get_dict() | |||
|
463 | ||||
|
464 | # Interim workaround if the user participated on any pull requests as a | |||
|
465 | # reviewer. | |||
|
466 | has_review = len(c.user.reviewer_pull_requests) | |||
|
467 | c.can_delete_user = not has_review | |||
|
468 | c.can_delete_user_message = '' | |||
|
469 | inactive_link = h.link_to( | |||
|
470 | 'inactive', h.route_path('user_edit', user_id=user_id, _anchor='active')) | |||
|
471 | if has_review == 1: | |||
|
472 | c.can_delete_user_message = h.literal(_( | |||
|
473 | 'The user participates as reviewer in {} pull request and ' | |||
|
474 | 'cannot be deleted. \nYou can set the user to ' | |||
|
475 | '"{}" instead of deleting it.').format( | |||
|
476 | has_review, inactive_link)) | |||
|
477 | elif has_review: | |||
|
478 | c.can_delete_user_message = h.literal(_( | |||
|
479 | 'The user participates as reviewer in {} pull requests and ' | |||
|
480 | 'cannot be deleted. \nYou can set the user to ' | |||
|
481 | '"{}" instead of deleting it.').format( | |||
|
482 | has_review, inactive_link)) | |||
|
483 | ||||
|
484 | data = render( | |||
|
485 | 'rhodecode:templates/admin/users/user_edit.mako', | |||
|
486 | self._get_template_context(c), self.request) | |||
|
487 | html = formencode.htmlfill.render( | |||
|
488 | data, | |||
|
489 | defaults=defaults, | |||
|
490 | encoding="UTF-8", | |||
|
491 | force_defaults=False | |||
|
492 | ) | |||
|
493 | return Response(html) | |||
|
494 | ||||
|
495 | @LoginRequired() | |||
|
496 | @HasPermissionAllDecorator('hg.admin') | |||
|
497 | @view_config( | |||
|
498 | route_name='user_edit_global_perms', request_method='GET', | |||
|
499 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
500 | def user_edit_global_perms(self): | |||
|
501 | _ = self.request.translate | |||
|
502 | c = self.load_default_context() | |||
|
503 | c.user = self.db_user | |||
|
504 | ||||
|
505 | c.active = 'global_perms' | |||
|
506 | ||||
|
507 | c.default_user = User.get_default_user() | |||
|
508 | defaults = c.user.get_dict() | |||
|
509 | defaults.update(c.default_user.get_default_perms(suffix='_inherited')) | |||
|
510 | defaults.update(c.default_user.get_default_perms()) | |||
|
511 | defaults.update(c.user.get_default_perms()) | |||
|
512 | ||||
|
513 | data = render( | |||
|
514 | 'rhodecode:templates/admin/users/user_edit.mako', | |||
|
515 | self._get_template_context(c), self.request) | |||
|
516 | html = formencode.htmlfill.render( | |||
|
517 | data, | |||
|
518 | defaults=defaults, | |||
|
519 | encoding="UTF-8", | |||
|
520 | force_defaults=False | |||
|
521 | ) | |||
|
522 | return Response(html) | |||
|
523 | ||||
|
524 | @LoginRequired() | |||
|
525 | @HasPermissionAllDecorator('hg.admin') | |||
|
526 | @CSRFRequired() | |||
|
527 | @view_config( | |||
|
528 | route_name='user_edit_global_perms_update', request_method='POST', | |||
|
529 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
530 | def user_edit_global_perms_update(self): | |||
|
531 | _ = self.request.translate | |||
|
532 | c = self.load_default_context() | |||
|
533 | ||||
|
534 | user_id = self.db_user_id | |||
|
535 | c.user = self.db_user | |||
|
536 | ||||
|
537 | c.active = 'global_perms' | |||
|
538 | try: | |||
|
539 | # first stage that verifies the checkbox | |||
|
540 | _form = UserIndividualPermissionsForm() | |||
|
541 | form_result = _form.to_python(dict(self.request.POST)) | |||
|
542 | inherit_perms = form_result['inherit_default_permissions'] | |||
|
543 | c.user.inherit_default_permissions = inherit_perms | |||
|
544 | Session().add(c.user) | |||
|
545 | ||||
|
546 | if not inherit_perms: | |||
|
547 | # only update the individual ones if we un check the flag | |||
|
548 | _form = UserPermissionsForm( | |||
|
549 | [x[0] for x in c.repo_create_choices], | |||
|
550 | [x[0] for x in c.repo_create_on_write_choices], | |||
|
551 | [x[0] for x in c.repo_group_create_choices], | |||
|
552 | [x[0] for x in c.user_group_create_choices], | |||
|
553 | [x[0] for x in c.fork_choices], | |||
|
554 | [x[0] for x in c.inherit_default_permission_choices])() | |||
|
555 | ||||
|
556 | form_result = _form.to_python(dict(self.request.POST)) | |||
|
557 | form_result.update({'perm_user_id': c.user.user_id}) | |||
|
558 | ||||
|
559 | PermissionModel().update_user_permissions(form_result) | |||
|
560 | ||||
|
561 | # TODO(marcink): implement global permissions | |||
|
562 | # audit_log.store_web('user.edit.permissions') | |||
|
563 | ||||
|
564 | Session().commit() | |||
|
565 | h.flash(_('User global permissions updated successfully'), | |||
|
566 | category='success') | |||
|
567 | ||||
|
568 | except formencode.Invalid as errors: | |||
|
569 | data = render( | |||
|
570 | 'rhodecode:templates/admin/users/user_edit.mako', | |||
|
571 | self._get_template_context(c), self.request) | |||
|
572 | html = formencode.htmlfill.render( | |||
|
573 | data, | |||
|
574 | defaults=errors.value, | |||
|
575 | errors=errors.error_dict or {}, | |||
|
576 | prefix_error=False, | |||
|
577 | encoding="UTF-8", | |||
|
578 | force_defaults=False | |||
|
579 | ) | |||
|
580 | return Response(html) | |||
|
581 | except Exception: | |||
|
582 | log.exception("Exception during permissions saving") | |||
|
583 | h.flash(_('An error occurred during permissions saving'), | |||
|
584 | category='error') | |||
|
585 | raise HTTPFound(h.route_path('user_edit_global_perms', user_id=user_id)) | |||
|
586 | ||||
|
587 | @LoginRequired() | |||
|
588 | @HasPermissionAllDecorator('hg.admin') | |||
|
589 | @CSRFRequired() | |||
|
590 | @view_config( | |||
|
591 | route_name='user_force_password_reset', request_method='POST', | |||
|
592 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
593 | def user_force_password_reset(self): | |||
|
594 | """ | |||
|
595 | toggle reset password flag for this user | |||
|
596 | """ | |||
|
597 | _ = self.request.translate | |||
|
598 | c = self.load_default_context() | |||
|
599 | ||||
|
600 | user_id = self.db_user_id | |||
|
601 | c.user = self.db_user | |||
|
602 | ||||
|
603 | try: | |||
|
604 | old_value = c.user.user_data.get('force_password_change') | |||
|
605 | c.user.update_userdata(force_password_change=not old_value) | |||
|
606 | ||||
|
607 | if old_value: | |||
|
608 | msg = _('Force password change disabled for user') | |||
|
609 | audit_logger.store_web( | |||
|
610 | 'user.edit.password_reset.disabled', | |||
|
611 | user=c.rhodecode_user) | |||
|
612 | else: | |||
|
613 | msg = _('Force password change enabled for user') | |||
|
614 | audit_logger.store_web( | |||
|
615 | 'user.edit.password_reset.enabled', | |||
|
616 | user=c.rhodecode_user) | |||
|
617 | ||||
|
618 | Session().commit() | |||
|
619 | h.flash(msg, category='success') | |||
|
620 | except Exception: | |||
|
621 | log.exception("Exception during password reset for user") | |||
|
622 | h.flash(_('An error occurred during password reset for user'), | |||
|
623 | category='error') | |||
|
624 | ||||
|
625 | raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id)) | |||
|
626 | ||||
|
627 | @LoginRequired() | |||
|
628 | @HasPermissionAllDecorator('hg.admin') | |||
|
629 | @CSRFRequired() | |||
|
630 | @view_config( | |||
|
631 | route_name='user_create_personal_repo_group', request_method='POST', | |||
|
632 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
633 | def user_create_personal_repo_group(self): | |||
|
634 | """ | |||
|
635 | Create personal repository group for this user | |||
|
636 | """ | |||
|
637 | from rhodecode.model.repo_group import RepoGroupModel | |||
|
638 | ||||
|
639 | _ = self.request.translate | |||
|
640 | c = self.load_default_context() | |||
|
641 | ||||
|
642 | user_id = self.db_user_id | |||
|
643 | c.user = self.db_user | |||
|
644 | ||||
|
645 | personal_repo_group = RepoGroup.get_user_personal_repo_group( | |||
|
646 | c.user.user_id) | |||
|
647 | if personal_repo_group: | |||
|
648 | raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id)) | |||
|
649 | ||||
|
650 | personal_repo_group_name = RepoGroupModel().get_personal_group_name( | |||
|
651 | c.user) | |||
|
652 | named_personal_group = RepoGroup.get_by_group_name( | |||
|
653 | personal_repo_group_name) | |||
|
654 | try: | |||
|
655 | ||||
|
656 | if named_personal_group and named_personal_group.user_id == c.user.user_id: | |||
|
657 | # migrate the same named group, and mark it as personal | |||
|
658 | named_personal_group.personal = True | |||
|
659 | Session().add(named_personal_group) | |||
|
660 | Session().commit() | |||
|
661 | msg = _('Linked repository group `%s` as personal' % ( | |||
|
662 | personal_repo_group_name,)) | |||
|
663 | h.flash(msg, category='success') | |||
|
664 | elif not named_personal_group: | |||
|
665 | RepoGroupModel().create_personal_repo_group(c.user) | |||
|
666 | ||||
|
667 | msg = _('Created repository group `%s`' % ( | |||
|
668 | personal_repo_group_name,)) | |||
|
669 | h.flash(msg, category='success') | |||
|
670 | else: | |||
|
671 | msg = _('Repository group `%s` is already taken' % ( | |||
|
672 | personal_repo_group_name,)) | |||
|
673 | h.flash(msg, category='warning') | |||
|
674 | except Exception: | |||
|
675 | log.exception("Exception during repository group creation") | |||
|
676 | msg = _( | |||
|
677 | 'An error occurred during repository group creation for user') | |||
|
678 | h.flash(msg, category='error') | |||
|
679 | Session().rollback() | |||
|
680 | ||||
|
681 | raise HTTPFound(h.route_path('user_edit_advanced', user_id=user_id)) | |||
|
682 | ||||
152 | @LoginRequired() |
|
683 | @LoginRequired() | |
153 | @HasPermissionAllDecorator('hg.admin') |
|
684 | @HasPermissionAllDecorator('hg.admin') | |
154 | @view_config( |
|
685 | @view_config( | |
@@ -157,27 +688,18 b' class AdminUsersView(BaseAppView, DataGr' | |||||
157 | def auth_tokens(self): |
|
688 | def auth_tokens(self): | |
158 | _ = self.request.translate |
|
689 | _ = self.request.translate | |
159 | c = self.load_default_context() |
|
690 | c = self.load_default_context() | |
160 |
|
691 | c.user = self.db_user | ||
161 | user_id = self.request.matchdict.get('user_id') |
|
|||
162 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
|||
163 | self._redirect_for_default_user(c.user.username) |
|
|||
164 |
|
692 | |||
165 | c.active = 'auth_tokens' |
|
693 | c.active = 'auth_tokens' | |
166 |
|
694 | |||
167 | c.lifetime_values = [ |
|
695 | c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_) | |
168 | (str(-1), _('forever')), |
|
|||
169 | (str(5), _('5 minutes')), |
|
|||
170 | (str(60), _('1 hour')), |
|
|||
171 | (str(60 * 24), _('1 day')), |
|
|||
172 | (str(60 * 24 * 30), _('1 month')), |
|
|||
173 | ] |
|
|||
174 | c.lifetime_options = [(c.lifetime_values, _("Lifetime"))] |
|
|||
175 | c.role_values = [ |
|
696 | c.role_values = [ | |
176 | (x, AuthTokenModel.cls._get_role_name(x)) |
|
697 | (x, AuthTokenModel.cls._get_role_name(x)) | |
177 | for x in AuthTokenModel.cls.ROLES] |
|
698 | for x in AuthTokenModel.cls.ROLES] | |
178 | c.role_options = [(c.role_values, _("Role"))] |
|
699 | c.role_options = [(c.role_values, _("Role"))] | |
179 | c.user_auth_tokens = AuthTokenModel().get_auth_tokens( |
|
700 | c.user_auth_tokens = AuthTokenModel().get_auth_tokens( | |
180 | c.user.user_id, show_expired=True) |
|
701 | c.user.user_id, show_expired=True) | |
|
702 | c.role_vcs = AuthTokenModel.cls.ROLE_VCS | |||
181 | return self._get_template_context(c) |
|
703 | return self._get_template_context(c) | |
182 |
|
704 | |||
183 | def maybe_attach_token_scope(self, token): |
|
705 | def maybe_attach_token_scope(self, token): | |
@@ -193,10 +715,8 b' class AdminUsersView(BaseAppView, DataGr' | |||||
193 | _ = self.request.translate |
|
715 | _ = self.request.translate | |
194 | c = self.load_default_context() |
|
716 | c = self.load_default_context() | |
195 |
|
717 | |||
196 |
user_id = self. |
|
718 | user_id = self.db_user_id | |
197 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
719 | c.user = self.db_user | |
198 |
|
||||
199 | self._redirect_for_default_user(c.user.username) |
|
|||
200 |
|
720 | |||
201 | user_data = c.user.get_api_data() |
|
721 | user_data = c.user.get_api_data() | |
202 | lifetime = safe_int(self.request.POST.get('lifetime'), -1) |
|
722 | lifetime = safe_int(self.request.POST.get('lifetime'), -1) | |
@@ -226,15 +746,15 b' class AdminUsersView(BaseAppView, DataGr' | |||||
226 | _ = self.request.translate |
|
746 | _ = self.request.translate | |
227 | c = self.load_default_context() |
|
747 | c = self.load_default_context() | |
228 |
|
748 | |||
229 |
user_id = self. |
|
749 | user_id = self.db_user_id | |
230 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
750 | c.user = self.db_user | |
231 | self._redirect_for_default_user(c.user.username) |
|
751 | ||
232 | user_data = c.user.get_api_data() |
|
752 | user_data = c.user.get_api_data() | |
233 |
|
753 | |||
234 | del_auth_token = self.request.POST.get('del_auth_token') |
|
754 | del_auth_token = self.request.POST.get('del_auth_token') | |
235 |
|
755 | |||
236 | if del_auth_token: |
|
756 | if del_auth_token: | |
237 |
token = UserApiKeys.get_or_404(del_auth_token |
|
757 | token = UserApiKeys.get_or_404(del_auth_token) | |
238 | token_data = token.get_api_data() |
|
758 | token_data = token.get_api_data() | |
239 |
|
759 | |||
240 | AuthTokenModel().delete(del_auth_token, c.user.user_id) |
|
760 | AuthTokenModel().delete(del_auth_token, c.user.user_id) | |
@@ -250,15 +770,127 b' class AdminUsersView(BaseAppView, DataGr' | |||||
250 | @LoginRequired() |
|
770 | @LoginRequired() | |
251 | @HasPermissionAllDecorator('hg.admin') |
|
771 | @HasPermissionAllDecorator('hg.admin') | |
252 | @view_config( |
|
772 | @view_config( | |
|
773 | route_name='edit_user_ssh_keys', request_method='GET', | |||
|
774 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
775 | def ssh_keys(self): | |||
|
776 | _ = self.request.translate | |||
|
777 | c = self.load_default_context() | |||
|
778 | c.user = self.db_user | |||
|
779 | ||||
|
780 | c.active = 'ssh_keys' | |||
|
781 | c.default_key = self.request.GET.get('default_key') | |||
|
782 | c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id) | |||
|
783 | return self._get_template_context(c) | |||
|
784 | ||||
|
785 | @LoginRequired() | |||
|
786 | @HasPermissionAllDecorator('hg.admin') | |||
|
787 | @view_config( | |||
|
788 | route_name='edit_user_ssh_keys_generate_keypair', request_method='GET', | |||
|
789 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
790 | def ssh_keys_generate_keypair(self): | |||
|
791 | _ = self.request.translate | |||
|
792 | c = self.load_default_context() | |||
|
793 | ||||
|
794 | c.user = self.db_user | |||
|
795 | ||||
|
796 | c.active = 'ssh_keys_generate' | |||
|
797 | comment = 'RhodeCode-SSH {}'.format(c.user.email or '') | |||
|
798 | c.private, c.public = SshKeyModel().generate_keypair(comment=comment) | |||
|
799 | ||||
|
800 | return self._get_template_context(c) | |||
|
801 | ||||
|
802 | @LoginRequired() | |||
|
803 | @HasPermissionAllDecorator('hg.admin') | |||
|
804 | @CSRFRequired() | |||
|
805 | @view_config( | |||
|
806 | route_name='edit_user_ssh_keys_add', request_method='POST') | |||
|
807 | def ssh_keys_add(self): | |||
|
808 | _ = self.request.translate | |||
|
809 | c = self.load_default_context() | |||
|
810 | ||||
|
811 | user_id = self.db_user_id | |||
|
812 | c.user = self.db_user | |||
|
813 | ||||
|
814 | user_data = c.user.get_api_data() | |||
|
815 | key_data = self.request.POST.get('key_data') | |||
|
816 | description = self.request.POST.get('description') | |||
|
817 | ||||
|
818 | try: | |||
|
819 | if not key_data: | |||
|
820 | raise ValueError('Please add a valid public key') | |||
|
821 | ||||
|
822 | key = SshKeyModel().parse_key(key_data.strip()) | |||
|
823 | fingerprint = key.hash_md5() | |||
|
824 | ||||
|
825 | ssh_key = SshKeyModel().create( | |||
|
826 | c.user.user_id, fingerprint, key_data, description) | |||
|
827 | ssh_key_data = ssh_key.get_api_data() | |||
|
828 | ||||
|
829 | audit_logger.store_web( | |||
|
830 | 'user.edit.ssh_key.add', action_data={ | |||
|
831 | 'data': {'ssh_key': ssh_key_data, 'user': user_data}}, | |||
|
832 | user=self._rhodecode_user, ) | |||
|
833 | Session().commit() | |||
|
834 | ||||
|
835 | # Trigger an event on change of keys. | |||
|
836 | trigger(SshKeyFileChangeEvent(), self.request.registry) | |||
|
837 | ||||
|
838 | h.flash(_("Ssh Key successfully created"), category='success') | |||
|
839 | ||||
|
840 | except IntegrityError: | |||
|
841 | log.exception("Exception during ssh key saving") | |||
|
842 | h.flash(_('An error occurred during ssh key saving: {}').format( | |||
|
843 | 'Such key already exists, please use a different one'), | |||
|
844 | category='error') | |||
|
845 | except Exception as e: | |||
|
846 | log.exception("Exception during ssh key saving") | |||
|
847 | h.flash(_('An error occurred during ssh key saving: {}').format(e), | |||
|
848 | category='error') | |||
|
849 | ||||
|
850 | return HTTPFound( | |||
|
851 | h.route_path('edit_user_ssh_keys', user_id=user_id)) | |||
|
852 | ||||
|
853 | @LoginRequired() | |||
|
854 | @HasPermissionAllDecorator('hg.admin') | |||
|
855 | @CSRFRequired() | |||
|
856 | @view_config( | |||
|
857 | route_name='edit_user_ssh_keys_delete', request_method='POST') | |||
|
858 | def ssh_keys_delete(self): | |||
|
859 | _ = self.request.translate | |||
|
860 | c = self.load_default_context() | |||
|
861 | ||||
|
862 | user_id = self.db_user_id | |||
|
863 | c.user = self.db_user | |||
|
864 | ||||
|
865 | user_data = c.user.get_api_data() | |||
|
866 | ||||
|
867 | del_ssh_key = self.request.POST.get('del_ssh_key') | |||
|
868 | ||||
|
869 | if del_ssh_key: | |||
|
870 | ssh_key = UserSshKeys.get_or_404(del_ssh_key) | |||
|
871 | ssh_key_data = ssh_key.get_api_data() | |||
|
872 | ||||
|
873 | SshKeyModel().delete(del_ssh_key, c.user.user_id) | |||
|
874 | audit_logger.store_web( | |||
|
875 | 'user.edit.ssh_key.delete', action_data={ | |||
|
876 | 'data': {'ssh_key': ssh_key_data, 'user': user_data}}, | |||
|
877 | user=self._rhodecode_user,) | |||
|
878 | Session().commit() | |||
|
879 | # Trigger an event on change of keys. | |||
|
880 | trigger(SshKeyFileChangeEvent(), self.request.registry) | |||
|
881 | h.flash(_("Ssh key successfully deleted"), category='success') | |||
|
882 | ||||
|
883 | return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id)) | |||
|
884 | ||||
|
885 | @LoginRequired() | |||
|
886 | @HasPermissionAllDecorator('hg.admin') | |||
|
887 | @view_config( | |||
253 | route_name='edit_user_emails', request_method='GET', |
|
888 | route_name='edit_user_emails', request_method='GET', | |
254 | renderer='rhodecode:templates/admin/users/user_edit.mako') |
|
889 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |
255 | def emails(self): |
|
890 | def emails(self): | |
256 | _ = self.request.translate |
|
891 | _ = self.request.translate | |
257 | c = self.load_default_context() |
|
892 | c = self.load_default_context() | |
258 |
|
893 | c.user = self.db_user | ||
259 | user_id = self.request.matchdict.get('user_id') |
|
|||
260 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
|||
261 | self._redirect_for_default_user(c.user.username) |
|
|||
262 |
|
894 | |||
263 | c.active = 'emails' |
|
895 | c.active = 'emails' | |
264 | c.user_email_map = UserEmailMap.query() \ |
|
896 | c.user_email_map = UserEmailMap.query() \ | |
@@ -275,22 +907,26 b' class AdminUsersView(BaseAppView, DataGr' | |||||
275 | _ = self.request.translate |
|
907 | _ = self.request.translate | |
276 | c = self.load_default_context() |
|
908 | c = self.load_default_context() | |
277 |
|
909 | |||
278 |
user_id = self. |
|
910 | user_id = self.db_user_id | |
279 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
911 | c.user = self.db_user | |
280 | self._redirect_for_default_user(c.user.username) |
|
|||
281 |
|
912 | |||
282 | email = self.request.POST.get('new_email') |
|
913 | email = self.request.POST.get('new_email') | |
283 | user_data = c.user.get_api_data() |
|
914 | user_data = c.user.get_api_data() | |
284 | try: |
|
915 | try: | |
285 | UserModel().add_extra_email(c.user.user_id, email) |
|
916 | UserModel().add_extra_email(c.user.user_id, email) | |
286 | audit_logger.store_web( |
|
917 | audit_logger.store_web( | |
287 |
'user.edit.email.add', |
|
918 | 'user.edit.email.add', | |
|
919 | action_data={'email': email, 'user': user_data}, | |||
288 | user=self._rhodecode_user) |
|
920 | user=self._rhodecode_user) | |
289 | Session().commit() |
|
921 | Session().commit() | |
290 | h.flash(_("Added new email address `%s` for user account") % email, |
|
922 | h.flash(_("Added new email address `%s` for user account") % email, | |
291 | category='success') |
|
923 | category='success') | |
292 | except formencode.Invalid as error: |
|
924 | except formencode.Invalid as error: | |
293 | h.flash(h.escape(error.error_dict['email']), category='error') |
|
925 | h.flash(h.escape(error.error_dict['email']), category='error') | |
|
926 | except IntegrityError: | |||
|
927 | log.warning("Email %s already exists", email) | |||
|
928 | h.flash(_('Email `{}` is already registered for another user.').format(email), | |||
|
929 | category='error') | |||
294 | except Exception: |
|
930 | except Exception: | |
295 | log.exception("Exception during email saving") |
|
931 | log.exception("Exception during email saving") | |
296 | h.flash(_('An error occurred during email saving'), |
|
932 | h.flash(_('An error occurred during email saving'), | |
@@ -306,9 +942,8 b' class AdminUsersView(BaseAppView, DataGr' | |||||
306 | _ = self.request.translate |
|
942 | _ = self.request.translate | |
307 | c = self.load_default_context() |
|
943 | c = self.load_default_context() | |
308 |
|
944 | |||
309 |
user_id = self. |
|
945 | user_id = self.db_user_id | |
310 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
946 | c.user = self.db_user | |
311 | self._redirect_for_default_user(c.user.username) |
|
|||
312 |
|
947 | |||
313 | email_id = self.request.POST.get('del_email_id') |
|
948 | email_id = self.request.POST.get('del_email_id') | |
314 | user_model = UserModel() |
|
949 | user_model = UserModel() | |
@@ -317,7 +952,8 b' class AdminUsersView(BaseAppView, DataGr' | |||||
317 | user_data = c.user.get_api_data() |
|
952 | user_data = c.user.get_api_data() | |
318 | user_model.delete_extra_email(c.user.user_id, email_id) |
|
953 | user_model.delete_extra_email(c.user.user_id, email_id) | |
319 | audit_logger.store_web( |
|
954 | audit_logger.store_web( | |
320 |
'user.edit.email.delete', |
|
955 | 'user.edit.email.delete', | |
|
956 | action_data={'email': email, 'user': user_data}, | |||
321 | user=self._rhodecode_user) |
|
957 | user=self._rhodecode_user) | |
322 | Session().commit() |
|
958 | Session().commit() | |
323 | h.flash(_("Removed email address from user account"), |
|
959 | h.flash(_("Removed email address from user account"), | |
@@ -332,10 +968,7 b' class AdminUsersView(BaseAppView, DataGr' | |||||
332 | def ips(self): |
|
968 | def ips(self): | |
333 | _ = self.request.translate |
|
969 | _ = self.request.translate | |
334 | c = self.load_default_context() |
|
970 | c = self.load_default_context() | |
335 |
|
971 | c.user = self.db_user | ||
336 | user_id = self.request.matchdict.get('user_id') |
|
|||
337 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
|||
338 | self._redirect_for_default_user(c.user.username) |
|
|||
339 |
|
972 | |||
340 | c.active = 'ips' |
|
973 | c.active = 'ips' | |
341 | c.user_ip_map = UserIpMap.query() \ |
|
974 | c.user_ip_map = UserIpMap.query() \ | |
@@ -352,14 +985,14 b' class AdminUsersView(BaseAppView, DataGr' | |||||
352 | @CSRFRequired() |
|
985 | @CSRFRequired() | |
353 | @view_config( |
|
986 | @view_config( | |
354 | route_name='edit_user_ips_add', request_method='POST') |
|
987 | route_name='edit_user_ips_add', request_method='POST') | |
|
988 | # NOTE(marcink): this view is allowed for default users, as we can | |||
|
989 | # edit their IP white list | |||
355 | def ips_add(self): |
|
990 | def ips_add(self): | |
356 | _ = self.request.translate |
|
991 | _ = self.request.translate | |
357 | c = self.load_default_context() |
|
992 | c = self.load_default_context() | |
358 |
|
993 | |||
359 |
user_id = self. |
|
994 | user_id = self.db_user_id | |
360 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
995 | c.user = self.db_user | |
361 | # NOTE(marcink): this view is allowed for default users, as we can |
|
|||
362 | # edit their IP white list |
|
|||
363 |
|
996 | |||
364 | user_model = UserModel() |
|
997 | user_model = UserModel() | |
365 | desc = self.request.POST.get('description') |
|
998 | desc = self.request.POST.get('description') | |
@@ -377,7 +1010,8 b' class AdminUsersView(BaseAppView, DataGr' | |||||
377 | try: |
|
1010 | try: | |
378 | user_model.add_extra_ip(c.user.user_id, ip, desc) |
|
1011 | user_model.add_extra_ip(c.user.user_id, ip, desc) | |
379 | audit_logger.store_web( |
|
1012 | audit_logger.store_web( | |
380 |
'user.edit.ip.add', |
|
1013 | 'user.edit.ip.add', | |
|
1014 | action_data={'ip': ip, 'user': user_data}, | |||
381 | user=self._rhodecode_user) |
|
1015 | user=self._rhodecode_user) | |
382 | Session().commit() |
|
1016 | Session().commit() | |
383 | added.append(ip) |
|
1017 | added.append(ip) | |
@@ -402,14 +1036,14 b' class AdminUsersView(BaseAppView, DataGr' | |||||
402 | @CSRFRequired() |
|
1036 | @CSRFRequired() | |
403 | @view_config( |
|
1037 | @view_config( | |
404 | route_name='edit_user_ips_delete', request_method='POST') |
|
1038 | route_name='edit_user_ips_delete', request_method='POST') | |
|
1039 | # NOTE(marcink): this view is allowed for default users, as we can | |||
|
1040 | # edit their IP white list | |||
405 | def ips_delete(self): |
|
1041 | def ips_delete(self): | |
406 | _ = self.request.translate |
|
1042 | _ = self.request.translate | |
407 | c = self.load_default_context() |
|
1043 | c = self.load_default_context() | |
408 |
|
1044 | |||
409 |
user_id = self. |
|
1045 | user_id = self.db_user_id | |
410 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
1046 | c.user = self.db_user | |
411 | # NOTE(marcink): this view is allowed for default users, as we can |
|
|||
412 | # edit their IP white list |
|
|||
413 |
|
1047 | |||
414 | ip_id = self.request.POST.get('del_ip_id') |
|
1048 | ip_id = self.request.POST.get('del_ip_id') | |
415 | user_model = UserModel() |
|
1049 | user_model = UserModel() | |
@@ -434,11 +1068,9 b' class AdminUsersView(BaseAppView, DataGr' | |||||
434 | renderer='rhodecode:templates/admin/users/user_edit.mako') |
|
1068 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |
435 | def groups_management(self): |
|
1069 | def groups_management(self): | |
436 | c = self.load_default_context() |
|
1070 | c = self.load_default_context() | |
|
1071 | c.user = self.db_user | |||
|
1072 | c.data = c.user.group_member | |||
437 |
|
1073 | |||
438 | user_id = self.request.matchdict.get('user_id') |
|
|||
439 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
|||
440 | c.data = c.user.group_member |
|
|||
441 | self._redirect_for_default_user(c.user.username) |
|
|||
442 | groups = [UserGroupModel.get_user_groups_as_dict(group.users_group) |
|
1074 | groups = [UserGroupModel.get_user_groups_as_dict(group.users_group) | |
443 | for group in c.user.group_member] |
|
1075 | for group in c.user.group_member] | |
444 | c.groups = json.dumps(groups) |
|
1076 | c.groups = json.dumps(groups) | |
@@ -455,17 +1087,35 b' class AdminUsersView(BaseAppView, DataGr' | |||||
455 | _ = self.request.translate |
|
1087 | _ = self.request.translate | |
456 | c = self.load_default_context() |
|
1088 | c = self.load_default_context() | |
457 |
|
1089 | |||
458 |
user_id = self. |
|
1090 | user_id = self.db_user_id | |
459 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
1091 | c.user = self.db_user | |
460 | self._redirect_for_default_user(c.user.username) |
|
1092 | ||
|
1093 | user_groups = set(self.request.POST.getall('users_group_id')) | |||
|
1094 | user_groups_objects = [] | |||
|
1095 | ||||
|
1096 | for ugid in user_groups: | |||
|
1097 | user_groups_objects.append( | |||
|
1098 | UserGroupModel().get_group(safe_int(ugid))) | |||
|
1099 | user_group_model = UserGroupModel() | |||
|
1100 | added_to_groups, removed_from_groups = \ | |||
|
1101 | user_group_model.change_groups(c.user, user_groups_objects) | |||
461 |
|
1102 | |||
462 | users_groups = set(self.request.POST.getall('users_group_id')) |
|
1103 | user_data = c.user.get_api_data() | |
463 | users_groups_model = [] |
|
1104 | for user_group_id in added_to_groups: | |
|
1105 | user_group = UserGroup.get(user_group_id) | |||
|
1106 | old_values = user_group.get_api_data() | |||
|
1107 | audit_logger.store_web( | |||
|
1108 | 'user_group.edit.member.add', | |||
|
1109 | action_data={'user': user_data, 'old_data': old_values}, | |||
|
1110 | user=self._rhodecode_user) | |||
464 |
|
1111 | |||
465 |
for ugid in |
|
1112 | for user_group_id in removed_from_groups: | |
466 |
user |
|
1113 | user_group = UserGroup.get(user_group_id) | |
467 | user_group_model = UserGroupModel() |
|
1114 | old_values = user_group.get_api_data() | |
468 | user_group_model.change_groups(c.user, users_groups_model) |
|
1115 | audit_logger.store_web( | |
|
1116 | 'user_group.edit.member.delete', | |||
|
1117 | action_data={'user': user_data, 'old_data': old_values}, | |||
|
1118 | user=self._rhodecode_user) | |||
469 |
|
1119 | |||
470 | Session().commit() |
|
1120 | Session().commit() | |
471 | c.active = 'user_groups_management' |
|
1121 | c.active = 'user_groups_management' | |
@@ -482,10 +1132,8 b' class AdminUsersView(BaseAppView, DataGr' | |||||
482 | def user_audit_logs(self): |
|
1132 | def user_audit_logs(self): | |
483 | _ = self.request.translate |
|
1133 | _ = self.request.translate | |
484 | c = self.load_default_context() |
|
1134 | c = self.load_default_context() | |
|
1135 | c.user = self.db_user | |||
485 |
|
1136 | |||
486 | user_id = self.request.matchdict.get('user_id') |
|
|||
487 | c.user = User.get_or_404(user_id, pyramid_exc=True) |
|
|||
488 | self._redirect_for_default_user(c.user.username) |
|
|||
489 | c.active = 'audit' |
|
1137 | c.active = 'audit' | |
490 |
|
1138 | |||
491 | p = safe_int(self.request.GET.get('page', 1), 1) |
|
1139 | p = safe_int(self.request.GET.get('page', 1), 1) | |
@@ -503,3 +1151,28 b' class AdminUsersView(BaseAppView, DataGr' | |||||
503 | c.filter_term = filter_term |
|
1151 | c.filter_term = filter_term | |
504 | return self._get_template_context(c) |
|
1152 | return self._get_template_context(c) | |
505 |
|
1153 | |||
|
1154 | @LoginRequired() | |||
|
1155 | @HasPermissionAllDecorator('hg.admin') | |||
|
1156 | @view_config( | |||
|
1157 | route_name='edit_user_perms_summary', request_method='GET', | |||
|
1158 | renderer='rhodecode:templates/admin/users/user_edit.mako') | |||
|
1159 | def user_perms_summary(self): | |||
|
1160 | _ = self.request.translate | |||
|
1161 | c = self.load_default_context() | |||
|
1162 | c.user = self.db_user | |||
|
1163 | ||||
|
1164 | c.active = 'perms_summary' | |||
|
1165 | c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr) | |||
|
1166 | ||||
|
1167 | return self._get_template_context(c) | |||
|
1168 | ||||
|
1169 | @LoginRequired() | |||
|
1170 | @HasPermissionAllDecorator('hg.admin') | |||
|
1171 | @view_config( | |||
|
1172 | route_name='edit_user_perms_summary_json', request_method='GET', | |||
|
1173 | renderer='json_ext') | |||
|
1174 | def user_perms_summary_json(self): | |||
|
1175 | self.load_default_context() | |||
|
1176 | perm_user = self.db_user.AuthUser(ip_addr=self.request.remote_addr) | |||
|
1177 | ||||
|
1178 | return perm_user.permissions |
@@ -87,4 +87,4 b' def includeme(config):' | |||||
87 | pattern=settings.get('channelstream.proxy_path') or '/_channelstream') |
|
87 | pattern=settings.get('channelstream.proxy_path') or '/_channelstream') | |
88 |
|
88 | |||
89 | # Scan module for configuration decorators. |
|
89 | # Scan module for configuration decorators. | |
90 | config.scan() |
|
90 | config.scan('.views', ignore='.tests') |
@@ -18,20 +18,11 b'' | |||||
18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
21 | """ |
|
|||
22 | Channel Stream controller for rhodecode |
|
|||
23 |
|
||||
24 | :created_on: Oct 10, 2015 |
|
|||
25 | :author: marcinl |
|
|||
26 | :copyright: (c) 2013-2015 RhodeCode GmbH. |
|
|||
27 | :license: Commercial License, see LICENSE for more details. |
|
|||
28 | """ |
|
|||
29 |
|
||||
30 | import logging |
|
21 | import logging | |
31 | import uuid |
|
22 | import uuid | |
32 |
|
23 | |||
33 | from pyramid.view import view_config |
|
24 | from pyramid.view import view_config | |
34 |
from |
|
25 | from pyramid.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPBadGateway | |
35 |
|
26 | |||
36 | from rhodecode.lib.channelstream import ( |
|
27 | from rhodecode.lib.channelstream import ( | |
37 | channelstream_request, |
|
28 | channelstream_request, |
@@ -27,7 +27,31 b' from rhodecode.model.gist import GistMod' | |||||
27 | from rhodecode.model.meta import Session |
|
27 | from rhodecode.model.meta import Session | |
28 | from rhodecode.tests import ( |
|
28 | from rhodecode.tests import ( | |
29 | TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, |
|
29 | TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, | |
30 |
TestController, assert_session_flash |
|
30 | TestController, assert_session_flash) | |
|
31 | ||||
|
32 | ||||
|
33 | def route_path(name, params=None, **kwargs): | |||
|
34 | import urllib | |||
|
35 | from rhodecode.apps._base import ADMIN_PREFIX | |||
|
36 | ||||
|
37 | base_url = { | |||
|
38 | 'gists_show': ADMIN_PREFIX + '/gists', | |||
|
39 | 'gists_new': ADMIN_PREFIX + '/gists/new', | |||
|
40 | 'gists_create': ADMIN_PREFIX + '/gists/create', | |||
|
41 | 'gist_show': ADMIN_PREFIX + '/gists/{gist_id}', | |||
|
42 | 'gist_delete': ADMIN_PREFIX + '/gists/{gist_id}/delete', | |||
|
43 | 'gist_edit': ADMIN_PREFIX + '/gists/{gist_id}/edit', | |||
|
44 | 'gist_edit_check_revision': ADMIN_PREFIX + '/gists/{gist_id}/edit/check_revision', | |||
|
45 | 'gist_update': ADMIN_PREFIX + '/gists/{gist_id}/update', | |||
|
46 | 'gist_show_rev': ADMIN_PREFIX + '/gists/{gist_id}/{revision}', | |||
|
47 | 'gist_show_formatted': ADMIN_PREFIX + '/gists/{gist_id}/{revision}/{format}', | |||
|
48 | 'gist_show_formatted_path': ADMIN_PREFIX + '/gists/{gist_id}/{revision}/{format}/{f_path}', | |||
|
49 | ||||
|
50 | }[name].format(**kwargs) | |||
|
51 | ||||
|
52 | if params: | |||
|
53 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |||
|
54 | return base_url | |||
31 |
|
55 | |||
32 |
|
56 | |||
33 | class GistUtility(object): |
|
57 | class GistUtility(object): | |
@@ -70,7 +94,7 b' class TestGistsController(TestController' | |||||
70 |
|
94 | |||
71 | def test_index_empty(self, create_gist): |
|
95 | def test_index_empty(self, create_gist): | |
72 | self.log_user() |
|
96 | self.log_user() | |
73 |
response = self.app.get( |
|
97 | response = self.app.get(route_path('gists_show')) | |
74 | response.mustcontain('data: [],') |
|
98 | response.mustcontain('data: [],') | |
75 |
|
99 | |||
76 | def test_index(self, create_gist): |
|
100 | def test_index(self, create_gist): | |
@@ -79,7 +103,7 b' class TestGistsController(TestController' | |||||
79 | g2 = create_gist('gist2', lifetime=1400) |
|
103 | g2 = create_gist('gist2', lifetime=1400) | |
80 | g3 = create_gist('gist3', description='gist3-desc') |
|
104 | g3 = create_gist('gist3', description='gist3-desc') | |
81 | g4 = create_gist('gist4', gist_type='private').gist_access_id |
|
105 | g4 = create_gist('gist4', gist_type='private').gist_access_id | |
82 |
response = self.app.get( |
|
106 | response = self.app.get(route_path('gists_show')) | |
83 |
|
107 | |||
84 | response.mustcontain('gist: %s' % g1.gist_access_id) |
|
108 | response.mustcontain('gist: %s' % g1.gist_access_id) | |
85 | response.mustcontain('gist: %s' % g2.gist_access_id) |
|
109 | response.mustcontain('gist: %s' % g2.gist_access_id) | |
@@ -95,7 +119,7 b' class TestGistsController(TestController' | |||||
95 | def test_index_private_gists(self, create_gist): |
|
119 | def test_index_private_gists(self, create_gist): | |
96 | self.log_user() |
|
120 | self.log_user() | |
97 | gist = create_gist('gist5', gist_type='private') |
|
121 | gist = create_gist('gist5', gist_type='private') | |
98 |
response = self.app.get( |
|
122 | response = self.app.get(route_path('gists_show', params=dict(private=1))) | |
99 |
|
123 | |||
100 | # and privates |
|
124 | # and privates | |
101 | response.mustcontain('gist: %s' % gist.gist_access_id) |
|
125 | response.mustcontain('gist: %s' % gist.gist_access_id) | |
@@ -107,7 +131,7 b' class TestGistsController(TestController' | |||||
107 | create_gist('gist3', description='gist3-desc') |
|
131 | create_gist('gist3', description='gist3-desc') | |
108 | create_gist('gist4', gist_type='private') |
|
132 | create_gist('gist4', gist_type='private') | |
109 |
|
133 | |||
110 |
response = self.app.get( |
|
134 | response = self.app.get(route_path('gists_show', params=dict(all=1))) | |
111 |
|
135 | |||
112 | assert len(GistModel.get_all()) == 4 |
|
136 | assert len(GistModel.get_all()) == 4 | |
113 | # and privates |
|
137 | # and privates | |
@@ -120,7 +144,7 b' class TestGistsController(TestController' | |||||
120 | create_gist('gist3', gist_type='private') |
|
144 | create_gist('gist3', gist_type='private') | |
121 | create_gist('gist4', gist_type='private') |
|
145 | create_gist('gist4', gist_type='private') | |
122 |
|
146 | |||
123 |
response = self.app.get( |
|
147 | response = self.app.get(route_path('gists_show', params=dict(all=1))) | |
124 |
|
148 | |||
125 | assert len(GistModel.get_all()) == 3 |
|
149 | assert len(GistModel.get_all()) == 3 | |
126 | # since we don't have access to private in this view, we |
|
150 | # since we don't have access to private in this view, we | |
@@ -131,7 +155,7 b' class TestGistsController(TestController' | |||||
131 | def test_create(self): |
|
155 | def test_create(self): | |
132 | self.log_user() |
|
156 | self.log_user() | |
133 | response = self.app.post( |
|
157 | response = self.app.post( | |
134 |
|
|
158 | route_path('gists_create'), | |
135 | params={'lifetime': -1, |
|
159 | params={'lifetime': -1, | |
136 | 'content': 'gist test', |
|
160 | 'content': 'gist test', | |
137 | 'filename': 'foo', |
|
161 | 'filename': 'foo', | |
@@ -146,7 +170,7 b' class TestGistsController(TestController' | |||||
146 | def test_create_with_path_with_dirs(self): |
|
170 | def test_create_with_path_with_dirs(self): | |
147 | self.log_user() |
|
171 | self.log_user() | |
148 | response = self.app.post( |
|
172 | response = self.app.post( | |
149 |
|
|
173 | route_path('gists_create'), | |
150 | params={'lifetime': -1, |
|
174 | params={'lifetime': -1, | |
151 | 'content': 'gist test', |
|
175 | 'content': 'gist test', | |
152 | 'filename': '/home/foo', |
|
176 | 'filename': '/home/foo', | |
@@ -163,12 +187,13 b' class TestGistsController(TestController' | |||||
163 | Session().add(gist) |
|
187 | Session().add(gist) | |
164 | Session().commit() |
|
188 | Session().commit() | |
165 |
|
189 | |||
166 |
self.app.get( |
|
190 | self.app.get(route_path('gist_show', gist_id=gist.gist_access_id), | |
|
191 | status=404) | |||
167 |
|
192 | |||
168 | def test_create_private(self): |
|
193 | def test_create_private(self): | |
169 | self.log_user() |
|
194 | self.log_user() | |
170 | response = self.app.post( |
|
195 | response = self.app.post( | |
171 |
|
|
196 | route_path('gists_create'), | |
172 | params={'lifetime': -1, |
|
197 | params={'lifetime': -1, | |
173 | 'content': 'private gist test', |
|
198 | 'content': 'private gist test', | |
174 | 'filename': 'private-foo', |
|
199 | 'filename': 'private-foo', | |
@@ -187,7 +212,7 b' class TestGistsController(TestController' | |||||
187 | def test_create_private_acl_private(self): |
|
212 | def test_create_private_acl_private(self): | |
188 | self.log_user() |
|
213 | self.log_user() | |
189 | response = self.app.post( |
|
214 | response = self.app.post( | |
190 |
|
|
215 | route_path('gists_create'), | |
191 | params={'lifetime': -1, |
|
216 | params={'lifetime': -1, | |
192 | 'content': 'private gist test', |
|
217 | 'content': 'private gist test', | |
193 | 'filename': 'private-foo', |
|
218 | 'filename': 'private-foo', | |
@@ -206,7 +231,7 b' class TestGistsController(TestController' | |||||
206 | def test_create_with_description(self): |
|
231 | def test_create_with_description(self): | |
207 | self.log_user() |
|
232 | self.log_user() | |
208 | response = self.app.post( |
|
233 | response = self.app.post( | |
209 |
|
|
234 | route_path('gists_create'), | |
210 | params={'lifetime': -1, |
|
235 | params={'lifetime': -1, | |
211 | 'content': 'gist test', |
|
236 | 'content': 'gist test', | |
212 | 'filename': 'foo-desc', |
|
237 | 'filename': 'foo-desc', | |
@@ -231,7 +256,8 b' class TestGistsController(TestController' | |||||
231 | 'gist_acl_level': Gist.ACL_LEVEL_PUBLIC, |
|
256 | 'gist_acl_level': Gist.ACL_LEVEL_PUBLIC, | |
232 | 'csrf_token': self.csrf_token |
|
257 | 'csrf_token': self.csrf_token | |
233 | } |
|
258 | } | |
234 |
response = self.app.post( |
|
259 | response = self.app.post( | |
|
260 | route_path('gists_create'), params=params, status=302) | |||
235 | self.logout_user() |
|
261 | self.logout_user() | |
236 | response = response.follow() |
|
262 | response = response.follow() | |
237 | response.mustcontain('added file: foo-desc') |
|
263 | response.mustcontain('added file: foo-desc') | |
@@ -240,35 +266,36 b' class TestGistsController(TestController' | |||||
240 |
|
266 | |||
241 | def test_new(self): |
|
267 | def test_new(self): | |
242 | self.log_user() |
|
268 | self.log_user() | |
243 |
self.app.get( |
|
269 | self.app.get(route_path('gists_new')) | |
244 |
|
270 | |||
245 | def test_delete(self, create_gist): |
|
271 | def test_delete(self, create_gist): | |
246 | self.log_user() |
|
272 | self.log_user() | |
247 | gist = create_gist('delete-me') |
|
273 | gist = create_gist('delete-me') | |
248 | response = self.app.post( |
|
274 | response = self.app.post( | |
249 |
|
|
275 | route_path('gist_delete', gist_id=gist.gist_id), | |
250 |
params={ |
|
276 | params={'csrf_token': self.csrf_token}) | |
251 | assert_session_flash(response, 'Deleted gist %s' % gist.gist_id) |
|
277 | assert_session_flash(response, 'Deleted gist %s' % gist.gist_id) | |
252 |
|
278 | |||
253 | def test_delete_normal_user_his_gist(self, create_gist): |
|
279 | def test_delete_normal_user_his_gist(self, create_gist): | |
254 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
280 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
255 | gist = create_gist('delete-me', owner=TEST_USER_REGULAR_LOGIN) |
|
281 | gist = create_gist('delete-me', owner=TEST_USER_REGULAR_LOGIN) | |
|
282 | ||||
256 | response = self.app.post( |
|
283 | response = self.app.post( | |
257 |
|
|
284 | route_path('gist_delete', gist_id=gist.gist_id), | |
258 |
params={ |
|
285 | params={'csrf_token': self.csrf_token}) | |
259 | assert_session_flash(response, 'Deleted gist %s' % gist.gist_id) |
|
286 | assert_session_flash(response, 'Deleted gist %s' % gist.gist_id) | |
260 |
|
287 | |||
261 | def test_delete_normal_user_not_his_own_gist(self, create_gist): |
|
288 | def test_delete_normal_user_not_his_own_gist(self, create_gist): | |
262 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
289 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
263 | gist = create_gist('delete-me') |
|
290 | gist = create_gist('delete-me-2') | |
|
291 | ||||
264 | self.app.post( |
|
292 | self.app.post( | |
265 |
|
|
293 | route_path('gist_delete', gist_id=gist.gist_id), | |
266 |
params={ |
|
294 | params={'csrf_token': self.csrf_token}, status=404) | |
267 | status=403) |
|
|||
268 |
|
295 | |||
269 | def test_show(self, create_gist): |
|
296 | def test_show(self, create_gist): | |
270 | gist = create_gist('gist-show-me') |
|
297 | gist = create_gist('gist-show-me') | |
271 |
response = self.app.get( |
|
298 | response = self.app.get(route_path('gist_show', gist_id=gist.gist_access_id)) | |
272 |
|
299 | |||
273 | response.mustcontain('added file: gist-show-me<') |
|
300 | response.mustcontain('added file: gist-show-me<') | |
274 |
|
301 | |||
@@ -283,16 +310,19 b' class TestGistsController(TestController' | |||||
283 | with mock.patch( |
|
310 | with mock.patch( | |
284 | 'rhodecode.lib.vcs.settings.ALIASES', ['git']): |
|
311 | 'rhodecode.lib.vcs.settings.ALIASES', ['git']): | |
285 | gist = create_gist('gist-show-me-again') |
|
312 | gist = create_gist('gist-show-me-again') | |
286 | self.app.get(url('gist', gist_id=gist.gist_access_id), status=200) |
|
313 | self.app.get( | |
|
314 | route_path('gist_show', gist_id=gist.gist_access_id), status=200) | |||
287 |
|
315 | |||
288 | def test_show_acl_private(self, create_gist): |
|
316 | def test_show_acl_private(self, create_gist): | |
289 | gist = create_gist('gist-show-me-only-when-im-logged-in', |
|
317 | gist = create_gist('gist-show-me-only-when-im-logged-in', | |
290 | acl_level=Gist.ACL_LEVEL_PRIVATE) |
|
318 | acl_level=Gist.ACL_LEVEL_PRIVATE) | |
291 | self.app.get(url('gist', gist_id=gist.gist_access_id), status=404) |
|
319 | self.app.get( | |
|
320 | route_path('gist_show', gist_id=gist.gist_access_id), status=404) | |||
292 |
|
321 | |||
293 | # now we log-in we should see thi gist |
|
322 | # now we log-in we should see thi gist | |
294 | self.log_user() |
|
323 | self.log_user() | |
295 |
response = self.app.get( |
|
324 | response = self.app.get( | |
|
325 | route_path('gist_show', gist_id=gist.gist_access_id)) | |||
296 | response.mustcontain('added file: gist-show-me-only-when-im-logged-in') |
|
326 | response.mustcontain('added file: gist-show-me-only-when-im-logged-in') | |
297 |
|
327 | |||
298 | assert_response = response.assert_response() |
|
328 | assert_response = response.assert_response() | |
@@ -303,36 +333,42 b' class TestGistsController(TestController' | |||||
303 |
|
333 | |||
304 | def test_show_as_raw(self, create_gist): |
|
334 | def test_show_as_raw(self, create_gist): | |
305 | gist = create_gist('gist-show-me', content='GIST CONTENT') |
|
335 | gist = create_gist('gist-show-me', content='GIST CONTENT') | |
306 |
response = self.app.get( |
|
336 | response = self.app.get( | |
307 | gist_id=gist.gist_access_id, format='raw')) |
|
337 | route_path('gist_show_formatted', | |
|
338 | gist_id=gist.gist_access_id, revision='tip', | |||
|
339 | format='raw')) | |||
308 | assert response.body == 'GIST CONTENT' |
|
340 | assert response.body == 'GIST CONTENT' | |
309 |
|
341 | |||
310 | def test_show_as_raw_individual_file(self, create_gist): |
|
342 | def test_show_as_raw_individual_file(self, create_gist): | |
311 | gist = create_gist('gist-show-me-raw', content='GIST BODY') |
|
343 | gist = create_gist('gist-show-me-raw', content='GIST BODY') | |
312 |
response = self.app.get( |
|
344 | response = self.app.get( | |
313 | gist_id=gist.gist_access_id, format='raw', |
|
345 | route_path('gist_show_formatted_path', | |
314 | revision='tip', f_path='gist-show-me-raw')) |
|
346 | gist_id=gist.gist_access_id, format='raw', | |
|
347 | revision='tip', f_path='gist-show-me-raw')) | |||
315 | assert response.body == 'GIST BODY' |
|
348 | assert response.body == 'GIST BODY' | |
316 |
|
349 | |||
317 | def test_edit_page(self, create_gist): |
|
350 | def test_edit_page(self, create_gist): | |
318 | self.log_user() |
|
351 | self.log_user() | |
319 | gist = create_gist('gist-for-edit', content='GIST EDIT BODY') |
|
352 | gist = create_gist('gist-for-edit', content='GIST EDIT BODY') | |
320 |
response = self.app.get( |
|
353 | response = self.app.get(route_path('gist_edit', gist_id=gist.gist_access_id)) | |
321 | response.mustcontain('GIST EDIT BODY') |
|
354 | response.mustcontain('GIST EDIT BODY') | |
322 |
|
355 | |||
323 | def test_edit_page_non_logged_user(self, create_gist): |
|
356 | def test_edit_page_non_logged_user(self, create_gist): | |
324 | gist = create_gist('gist-for-edit', content='GIST EDIT BODY') |
|
357 | gist = create_gist('gist-for-edit', content='GIST EDIT BODY') | |
325 |
self.app.get( |
|
358 | self.app.get(route_path('gist_edit', gist_id=gist.gist_access_id), | |
|
359 | status=302) | |||
326 |
|
360 | |||
327 | def test_edit_normal_user_his_gist(self, create_gist): |
|
361 | def test_edit_normal_user_his_gist(self, create_gist): | |
328 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
362 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
329 | gist = create_gist('gist-for-edit', owner=TEST_USER_REGULAR_LOGIN) |
|
363 | gist = create_gist('gist-for-edit', owner=TEST_USER_REGULAR_LOGIN) | |
330 |
self.app.get( |
|
364 | self.app.get(route_path('gist_edit', gist_id=gist.gist_access_id, | |
|
365 | status=200)) | |||
331 |
|
366 | |||
332 | def test_edit_normal_user_not_his_own_gist(self, create_gist): |
|
367 | def test_edit_normal_user_not_his_own_gist(self, create_gist): | |
333 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) |
|
368 | self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS) | |
334 | gist = create_gist('delete-me') |
|
369 | gist = create_gist('delete-me') | |
335 |
self.app.get( |
|
370 | self.app.get(route_path('gist_edit', gist_id=gist.gist_access_id), | |
|
371 | status=404) | |||
336 |
|
372 | |||
337 | def test_user_first_name_is_escaped(self, user_util, create_gist): |
|
373 | def test_user_first_name_is_escaped(self, user_util, create_gist): | |
338 | xss_atack_string = '"><script>alert(\'First Name\')</script>' |
|
374 | xss_atack_string = '"><script>alert(\'First Name\')</script>' | |
@@ -341,7 +377,7 b' class TestGistsController(TestController' | |||||
341 | user = user_util.create_user( |
|
377 | user = user_util.create_user( | |
342 | firstname=xss_atack_string, password=password) |
|
378 | firstname=xss_atack_string, password=password) | |
343 | create_gist('gist', gist_type='public', owner=user.username) |
|
379 | create_gist('gist', gist_type='public', owner=user.username) | |
344 |
response = self.app.get( |
|
380 | response = self.app.get(route_path('gists_show')) | |
345 | response.mustcontain(xss_escaped_string) |
|
381 | response.mustcontain(xss_escaped_string) | |
346 |
|
382 | |||
347 | def test_user_last_name_is_escaped(self, user_util, create_gist): |
|
383 | def test_user_last_name_is_escaped(self, user_util, create_gist): | |
@@ -351,5 +387,5 b' class TestGistsController(TestController' | |||||
351 | user = user_util.create_user( |
|
387 | user = user_util.create_user( | |
352 | lastname=xss_atack_string, password=password) |
|
388 | lastname=xss_atack_string, password=password) | |
353 | create_gist('gist', gist_type='public', owner=user.username) |
|
389 | create_gist('gist', gist_type='public', owner=user.username) | |
354 |
response = self.app.get( |
|
390 | response = self.app.get(route_path('gists_show')) | |
355 | response.mustcontain(xss_escaped_string) |
|
391 | response.mustcontain(xss_escaped_string) |
@@ -46,4 +46,4 b' def includeme(config):' | |||||
46 | routing_links.connect_redirection_links(config) |
|
46 | routing_links.connect_redirection_links(config) | |
47 |
|
47 | |||
48 | # Scan module for configuration decorators. |
|
48 | # Scan module for configuration decorators. | |
49 | config.scan() |
|
49 | config.scan('.views', ignore='.tests') |
@@ -54,14 +54,16 b' class TestHomeController(TestController)' | |||||
54 | response.mustcontain('"name_raw": "%s"' % repo.repo_name) |
|
54 | response.mustcontain('"name_raw": "%s"' % repo.repo_name) | |
55 |
|
55 | |||
56 | def test_index_contains_statics_with_ver(self): |
|
56 | def test_index_contains_statics_with_ver(self): | |
57 | from pylons import tmpl_context as c |
|
57 | from rhodecode.lib.base import calculate_version_hash | |
58 |
|
58 | |||
59 | self.log_user() |
|
59 | self.log_user() | |
60 | response = self.app.get(route_path('home')) |
|
60 | response = self.app.get(route_path('home')) | |
61 |
|
61 | |||
62 |
rhodecode_version_hash = c |
|
62 | rhodecode_version_hash = calculate_version_hash( | |
|
63 | {'beaker.session.secret':'test-rc-uytcxaz'}) | |||
63 | response.mustcontain('style.css?ver={0}'.format(rhodecode_version_hash)) |
|
64 | response.mustcontain('style.css?ver={0}'.format(rhodecode_version_hash)) | |
64 |
response.mustcontain('rhodecode-components.js?ver={0}'.format( |
|
65 | response.mustcontain('rhodecode-components.js?ver={0}'.format( | |
|
66 | rhodecode_version_hash)) | |||
65 |
|
67 | |||
66 | def test_index_contains_backend_specific_details(self, backend): |
|
68 | def test_index_contains_backend_specific_details(self, backend): | |
67 | self.log_user() |
|
69 | self.log_user() | |
@@ -132,3 +134,9 b' class TestHomeController(TestController)' | |||||
132 | response.mustcontain(version_string) |
|
134 | response.mustcontain(version_string) | |
133 | if state is False: |
|
135 | if state is False: | |
134 | response.mustcontain(no=[version_string]) |
|
136 | response.mustcontain(no=[version_string]) | |
|
137 | ||||
|
138 | def test_logout_form_contains_csrf(self, autologin_user, csrf_token): | |||
|
139 | response = self.app.get(route_path('home')) | |||
|
140 | assert_response = response.assert_response() | |||
|
141 | element = assert_response.get_element('.logout #csrf_token') | |||
|
142 | assert element.value == csrf_token |
@@ -25,15 +25,16 b' from pyramid.view import view_config' | |||||
25 |
|
25 | |||
26 | from rhodecode.apps._base import BaseAppView |
|
26 | from rhodecode.apps._base import BaseAppView | |
27 | from rhodecode.lib import helpers as h |
|
27 | from rhodecode.lib import helpers as h | |
28 |
from rhodecode.lib.auth import |
|
28 | from rhodecode.lib.auth import ( | |
29 | HasRepoGroupPermissionAnyDecorator |
|
29 | LoginRequired, NotAnonymous, HasRepoGroupPermissionAnyDecorator) | |
30 | from rhodecode.lib.index import searcher_from_config |
|
30 | from rhodecode.lib.index import searcher_from_config | |
31 | from rhodecode.lib.utils2 import safe_unicode, str2bool |
|
31 | from rhodecode.lib.utils2 import safe_unicode, str2bool | |
32 | from rhodecode.lib.ext_json import json |
|
32 | from rhodecode.lib.ext_json import json | |
33 |
from rhodecode.model.db import |
|
33 | from rhodecode.model.db import ( | |
|
34 | func, or_, in_filter_generator, Repository, RepoGroup) | |||
34 | from rhodecode.model.repo import RepoModel |
|
35 | from rhodecode.model.repo import RepoModel | |
35 | from rhodecode.model.repo_group import RepoGroupModel |
|
36 | from rhodecode.model.repo_group import RepoGroupModel | |
36 |
from rhodecode.model.scm import |
|
37 | from rhodecode.model.scm import RepoGroupList, RepoList | |
37 | from rhodecode.model.user import UserModel |
|
38 | from rhodecode.model.user import UserModel | |
38 | from rhodecode.model.user_group import UserGroupModel |
|
39 | from rhodecode.model.user_group import UserGroupModel | |
39 |
|
40 | |||
@@ -101,9 +102,17 b' class HomeView(BaseAppView):' | |||||
101 | return {'suggestions': _user_groups} |
|
102 | return {'suggestions': _user_groups} | |
102 |
|
103 | |||
103 | def _get_repo_list(self, name_contains=None, repo_type=None, limit=20): |
|
104 | def _get_repo_list(self, name_contains=None, repo_type=None, limit=20): | |
|
105 | allowed_ids = self._rhodecode_user.repo_acl_ids( | |||
|
106 | ['repository.read', 'repository.write', 'repository.admin'], | |||
|
107 | cache=False, name_filter=name_contains) or [-1] | |||
|
108 | ||||
104 | query = Repository.query()\ |
|
109 | query = Repository.query()\ | |
105 | .order_by(func.length(Repository.repo_name))\ |
|
110 | .order_by(func.length(Repository.repo_name))\ | |
106 | .order_by(Repository.repo_name) |
|
111 | .order_by(Repository.repo_name)\ | |
|
112 | .filter(or_( | |||
|
113 | # generate multiple IN to fix limitation problems | |||
|
114 | *in_filter_generator(Repository.repo_id, allowed_ids) | |||
|
115 | )) | |||
107 |
|
116 | |||
108 | if repo_type: |
|
117 | if repo_type: | |
109 | query = query.filter(Repository.repo_type == repo_type) |
|
118 | query = query.filter(Repository.repo_type == repo_type) | |
@@ -114,23 +123,31 b' class HomeView(BaseAppView):' | |||||
114 | Repository.repo_name.ilike(ilike_expression)) |
|
123 | Repository.repo_name.ilike(ilike_expression)) | |
115 | query = query.limit(limit) |
|
124 | query = query.limit(limit) | |
116 |
|
125 | |||
117 |
a |
|
126 | acl_repo_iter = query | |
118 | # permission checks are inside this function |
|
127 | ||
119 | repo_iter = ScmModel().get_repos(all_repos) |
|
|||
120 | return [ |
|
128 | return [ | |
121 | { |
|
129 | { | |
122 |
'id': obj |
|
130 | 'id': obj.repo_name, | |
123 |
'text': obj |
|
131 | 'text': obj.repo_name, | |
124 | 'type': 'repo', |
|
132 | 'type': 'repo', | |
125 | 'obj': obj['dbrepo'], |
|
133 | 'obj': {'repo_type': obj.repo_type, 'private': obj.private, | |
126 | 'url': h.route_path('repo_summary', repo_name=obj['name']) |
|
134 | 'repo_id': obj.repo_id}, | |
|
135 | 'url': h.route_path('repo_summary', repo_name=obj.repo_name) | |||
127 | } |
|
136 | } | |
128 | for obj in repo_iter] |
|
137 | for obj in acl_repo_iter] | |
129 |
|
138 | |||
130 | def _get_repo_group_list(self, name_contains=None, limit=20): |
|
139 | def _get_repo_group_list(self, name_contains=None, limit=20): | |
|
140 | allowed_ids = self._rhodecode_user.repo_group_acl_ids( | |||
|
141 | ['group.read', 'group.write', 'group.admin'], | |||
|
142 | cache=False, name_filter=name_contains) or [-1] | |||
|
143 | ||||
131 | query = RepoGroup.query()\ |
|
144 | query = RepoGroup.query()\ | |
132 | .order_by(func.length(RepoGroup.group_name))\ |
|
145 | .order_by(func.length(RepoGroup.group_name))\ | |
133 | .order_by(RepoGroup.group_name) |
|
146 | .order_by(RepoGroup.group_name) \ | |
|
147 | .filter(or_( | |||
|
148 | # generate multiple IN to fix limitation problems | |||
|
149 | *in_filter_generator(RepoGroup.group_id, allowed_ids) | |||
|
150 | )) | |||
134 |
|
151 | |||
135 | if name_contains: |
|
152 | if name_contains: | |
136 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) |
|
153 | ilike_expression = u'%{}%'.format(safe_unicode(name_contains)) | |
@@ -138,23 +155,24 b' class HomeView(BaseAppView):' | |||||
138 | RepoGroup.group_name.ilike(ilike_expression)) |
|
155 | RepoGroup.group_name.ilike(ilike_expression)) | |
139 | query = query.limit(limit) |
|
156 | query = query.limit(limit) | |
140 |
|
157 | |||
141 |
a |
|
158 | acl_repo_iter = query | |
142 | repo_groups_iter = ScmModel().get_repo_groups(all_groups) |
|
159 | ||
143 | return [ |
|
160 | return [ | |
144 | { |
|
161 | { | |
145 | 'id': obj.group_name, |
|
162 | 'id': obj.group_name, | |
146 | 'text': obj.group_name, |
|
163 | 'text': obj.group_name, | |
147 | 'type': 'group', |
|
164 | 'type': 'group', | |
148 | 'obj': {}, |
|
165 | 'obj': {}, | |
149 | 'url': h.route_path('repo_group_home', repo_group_name=obj.group_name) |
|
166 | 'url': h.route_path( | |
|
167 | 'repo_group_home', repo_group_name=obj.group_name) | |||
150 | } |
|
168 | } | |
151 |
for obj in repo |
|
169 | for obj in acl_repo_iter] | |
152 |
|
170 | |||
153 |
def _get_hash_commit_list(self, auth_user, |
|
171 | def _get_hash_commit_list(self, auth_user, query=None): | |
154 |
if not |
|
172 | if not query or len(query) < 3: | |
155 | return [] |
|
173 | return [] | |
156 |
|
174 | |||
157 |
commit_hashes = re.compile('([0-9a-f]{2,40})').findall( |
|
175 | commit_hashes = re.compile('(?:commit:)([0-9a-f]{2,40})').findall(query) | |
158 |
|
176 | |||
159 | if len(commit_hashes) != 1: |
|
177 | if len(commit_hashes) != 1: | |
160 | return [] |
|
178 | return [] | |
@@ -172,9 +190,9 b' class HomeView(BaseAppView):' | |||||
172 | 'text': entry['commit_id'], |
|
190 | 'text': entry['commit_id'], | |
173 | 'type': 'commit', |
|
191 | 'type': 'commit', | |
174 | 'obj': {'repo': entry['repository']}, |
|
192 | 'obj': {'repo': entry['repository']}, | |
175 |
'url': h. |
|
193 | 'url': h.route_path( | |
176 |
|
|
194 | 'repo_commit', | |
177 |
|
|
195 | repo_name=entry['repository'], commit_id=entry['commit_id']) | |
178 | } |
|
196 | } | |
179 | for entry in result['results']] |
|
197 | for entry in result['results']] | |
180 |
|
198 |
@@ -19,24 +19,62 b'' | |||||
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
21 | import datetime |
|
21 | import datetime | |
22 | from rhodecode.tests import TestController, url |
|
22 | ||
|
23 | import pytest | |||
|
24 | ||||
|
25 | from rhodecode.apps._base import ADMIN_PREFIX | |||
|
26 | from rhodecode.tests import TestController | |||
23 | from rhodecode.model.db import UserFollowing, Repository |
|
27 | from rhodecode.model.db import UserFollowing, Repository | |
24 |
|
28 | |||
25 |
|
29 | |||
26 | class TestJournalController(TestController): |
|
30 | def route_path(name, params=None, **kwargs): | |
|
31 | import urllib | |||
27 |
|
32 | |||
28 | def test_index(self): |
|
33 | base_url = { | |
|
34 | 'journal': ADMIN_PREFIX + '/journal', | |||
|
35 | 'journal_rss': ADMIN_PREFIX + '/journal/rss', | |||
|
36 | 'journal_atom': ADMIN_PREFIX + '/journal/atom', | |||
|
37 | 'journal_public': ADMIN_PREFIX + '/public_journal', | |||
|
38 | 'journal_public_atom': ADMIN_PREFIX + '/public_journal/atom', | |||
|
39 | 'journal_public_atom_old': ADMIN_PREFIX + '/public_journal_atom', | |||
|
40 | 'journal_public_rss': ADMIN_PREFIX + '/public_journal/rss', | |||
|
41 | 'journal_public_rss_old': ADMIN_PREFIX + '/public_journal_rss', | |||
|
42 | 'toggle_following': ADMIN_PREFIX + '/toggle_following', | |||
|
43 | }[name].format(**kwargs) | |||
|
44 | ||||
|
45 | if params: | |||
|
46 | base_url = '{}?{}'.format(base_url, urllib.urlencode(params)) | |||
|
47 | return base_url | |||
|
48 | ||||
|
49 | ||||
|
50 | class TestJournalViews(TestController): | |||
|
51 | ||||
|
52 | def test_journal(self): | |||
29 | self.log_user() |
|
53 | self.log_user() | |
30 |
response = self.app.get( |
|
54 | response = self.app.get(route_path('journal')) | |
31 | response.mustcontain( |
|
55 | # response.mustcontain( | |
32 | """<div class="journal_day">%s</div>""" % datetime.date.today()) |
|
56 | # """<div class="journal_day">%s</div>""" % datetime.date.today()) | |
|
57 | ||||
|
58 | @pytest.mark.parametrize("feed_type, content_type", [ | |||
|
59 | ('rss', "application/rss+xml"), | |||
|
60 | ('atom', "application/atom+xml") | |||
|
61 | ]) | |||
|
62 | def test_journal_feed(self, feed_type, content_type): | |||
|
63 | self.log_user() | |||
|
64 | response = self.app.get( | |||
|
65 | route_path( | |||
|
66 | 'journal_{}'.format(feed_type)), | |||
|
67 | status=200) | |||
|
68 | ||||
|
69 | assert response.content_type == content_type | |||
33 |
|
70 | |||
34 | def test_toggle_following_repository(self, backend): |
|
71 | def test_toggle_following_repository(self, backend): | |
35 | user = self.log_user() |
|
72 | user = self.log_user() | |
36 | repo = Repository.get_by_repo_name(backend.repo_name) |
|
73 | repo = Repository.get_by_repo_name(backend.repo_name) | |
37 | repo_id = repo.repo_id |
|
74 | repo_id = repo.repo_id | |
38 | self.app.post(url('toggle_following'), {'follows_repo_id': repo_id, |
|
75 | self.app.post( | |
39 | 'csrf_token': self.csrf_token}) |
|
76 | route_path('toggle_following'), {'follows_repo_id': repo_id, | |
|
77 | 'csrf_token': self.csrf_token}) | |||
40 |
|
78 | |||
41 | followings = UserFollowing.query()\ |
|
79 | followings = UserFollowing.query()\ | |
42 | .filter(UserFollowing.user_id == user['user_id'])\ |
|
80 | .filter(UserFollowing.user_id == user['user_id'])\ | |
@@ -44,8 +82,9 b' class TestJournalController(TestControll' | |||||
44 |
|
82 | |||
45 | assert len(followings) == 0 |
|
83 | assert len(followings) == 0 | |
46 |
|
84 | |||
47 | self.app.post(url('toggle_following'), {'follows_repo_id': repo_id, |
|
85 | self.app.post( | |
48 | 'csrf_token': self.csrf_token}) |
|
86 | route_path('toggle_following'), {'follows_repo_id': repo_id, | |
|
87 | 'csrf_token': self.csrf_token}) | |||
49 |
|
88 | |||
50 | followings = UserFollowing.query()\ |
|
89 | followings = UserFollowing.query()\ | |
51 | .filter(UserFollowing.user_id == user['user_id'])\ |
|
90 | .filter(UserFollowing.user_id == user['user_id'])\ | |
@@ -53,12 +92,15 b' class TestJournalController(TestControll' | |||||
53 |
|
92 | |||
54 | assert len(followings) == 1 |
|
93 | assert len(followings) == 1 | |
55 |
|
94 | |||
56 | def test_public_journal_atom(self): |
|
95 | @pytest.mark.parametrize("feed_type, content_type", [ | |
|
96 | ('rss', "application/rss+xml"), | |||
|
97 | ('atom', "application/atom+xml") | |||
|
98 | ]) | |||
|
99 | def test_public_journal_feed(self, feed_type, content_type): | |||
57 | self.log_user() |
|
100 | self.log_user() | |
58 |
response = self.app.get( |
|
101 | response = self.app.get( | |
59 | action='public_journal_atom'),) |
|
102 | route_path( | |
|
103 | 'journal_public_{}'.format(feed_type)), | |||
|
104 | status=200) | |||
60 |
|
105 | |||
61 | def test_public_journal_rss(self): |
|
106 | assert response.content_type == content_type | |
62 | self.log_user() |
|
|||
63 | response = self.app.get(url(controller='journal', |
|
|||
64 | action='public_journal_rss'),) |
|
@@ -41,4 +41,4 b' def includeme(config):' | |||||
41 | pattern=ADMIN_PREFIX + '/password_reset_confirmation') |
|
41 | pattern=ADMIN_PREFIX + '/password_reset_confirmation') | |
42 |
|
42 | |||
43 | # Scan module for configuration decorators. |
|
43 | # Scan module for configuration decorators. | |
44 | config.scan() |
|
44 | config.scan('.views', ignore='.tests') |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_login.py to rhodecode/apps/login/tests/test_login.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_login.py to rhodecode/apps/login/tests/test_login.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_password_reset.py to rhodecode/apps/login/tests/test_password_reset.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_password_reset.py to rhodecode/apps/login/tests/test_password_reset.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_admin_notifications.py to rhodecode/apps/my_account/tests/test_my_account_notifications.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_admin_notifications.py to rhodecode/apps/my_account/tests/test_my_account_notifications.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/apps/my_account/views.py to rhodecode/apps/my_account/views/my_account.py |
|
NO CONTENT: file renamed from rhodecode/apps/my_account/views.py to rhodecode/apps/my_account/views/my_account.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_changelog.py to rhodecode/apps/repository/tests/test_repo_changelog.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_changelog.py to rhodecode/apps/repository/tests/test_repo_changelog.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_commit_comments.py to rhodecode/apps/repository/tests/test_repo_commit_comments.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_commit_comments.py to rhodecode/apps/repository/tests/test_repo_commit_comments.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_changeset.py to rhodecode/apps/repository/tests/test_repo_commits.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_changeset.py to rhodecode/apps/repository/tests/test_repo_commits.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_compare.py to rhodecode/apps/repository/tests/test_repo_compare.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_compare.py to rhodecode/apps/repository/tests/test_repo_compare.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_compare_local.py to rhodecode/apps/repository/tests/test_repo_compare_local.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_compare_local.py to rhodecode/apps/repository/tests/test_repo_compare_local.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_compare_on_single_file.py to rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_compare_on_single_file.py to rhodecode/apps/repository/tests/test_repo_compare_on_single_file.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_feed.py to rhodecode/apps/repository/tests/test_repo_feed.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_feed.py to rhodecode/apps/repository/tests/test_repo_feed.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_files.py to rhodecode/apps/repository/tests/test_repo_files.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_files.py to rhodecode/apps/repository/tests/test_repo_files.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_admin_repos_issuetracker.py to rhodecode/apps/repository/tests/test_repo_issue_tracker.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_admin_repos_issuetracker.py to rhodecode/apps/repository/tests/test_repo_issue_tracker.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_pullrequests.py to rhodecode/apps/repository/tests/test_repo_pullrequests.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_pullrequests.py to rhodecode/apps/repository/tests/test_repo_pullrequests.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_admin_user_groups.py to rhodecode/apps/user_group/tests/test_user_groups.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_admin_user_groups.py to rhodecode/apps/user_group/tests/test_user_groups.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/functional/test_integrations.py to rhodecode/integrations/tests/test_integrations.py |
|
NO CONTENT: file renamed from rhodecode/tests/functional/test_integrations.py to rhodecode/integrations/tests/test_integrations.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden |
|
NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden |
1 | NO CONTENT: modified file chmod 100644 => 100755 |
|
NO CONTENT: modified file chmod 100644 => 100755 | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden |
|
NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden |
1 | NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden |
|
NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden |
1 | NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden |
|
NO CONTENT: modified file chmod 100644 => 100755, binary diff hidden |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/public/js/excanvas.min.js to rhodecode/public/js/src/excanvas.min.js |
|
NO CONTENT: file renamed from rhodecode/public/js/excanvas.min.js to rhodecode/public/js/src/excanvas.min.js |
1 | NO CONTENT: file renamed from rhodecode/public/js/jquery.commits-graph.js to rhodecode/public/js/src/plugins/jquery.commits-graph.js |
|
NO CONTENT: file renamed from rhodecode/public/js/jquery.commits-graph.js to rhodecode/public/js/src/plugins/jquery.commits-graph.js |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/templates/admin/notifications/show_notification.mako to rhodecode/templates/admin/notifications/notifications_show.mako |
|
NO CONTENT: file renamed from rhodecode/templates/admin/notifications/show_notification.mako to rhodecode/templates/admin/notifications/notifications_show.mako | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/templates/admin/notifications/notifications.mako to rhodecode/templates/admin/notifications/notifications_show_all.mako |
|
NO CONTENT: file renamed from rhodecode/templates/admin/notifications/notifications.mako to rhodecode/templates/admin/notifications/notifications_show_all.mako | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/templates/admin/repo_groups/repo_group_edit_perms.mako to rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako |
|
NO CONTENT: file renamed from rhodecode/templates/admin/repo_groups/repo_group_edit_perms.mako to rhodecode/templates/admin/repo_groups/repo_group_edit_permissions.mako | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/templates/summary/base.mako to rhodecode/templates/summary/summary_base.mako |
|
NO CONTENT: file renamed from rhodecode/templates/summary/base.mako to rhodecode/templates/summary/summary_base.mako | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file renamed from rhodecode/tests/other/test_libs.py to rhodecode/tests/lib/test_libs.py |
|
NO CONTENT: file renamed from rhodecode/tests/other/test_libs.py to rhodecode/tests/lib/test_libs.py | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed | ||
The requested commit or file is too big and content was truncated. Show full diff |
General Comments 0
You need to be logged in to leave comments.
Login now