##// END OF EJS Templates
pylons: remove pylons as dependency...
marcink -
r2351:59272121 default
parent child Browse files
Show More
@@ -61,23 +61,6 b' self: super: {'
61 61 ];
62 62 });
63 63
64 celery = super.celery.override (attrs: {
65 # The current version of kombu needs some patching to work with the
66 # other libs. Should be removed once we update celery and kombu.
67 patches = [
68 ./patch-celery-dateutil.diff
69 ];
70 });
71
72 kombu = super.kombu.override (attrs: {
73 # The current version of kombu needs some patching to work with the
74 # other libs. Should be removed once we update celery and kombu.
75 patches = [
76 ./patch-kombu-py-2-7-11.diff
77 ./patch-kombu-msgpack.diff
78 ];
79 });
80
81 64 lxml = super.lxml.override (attrs: {
82 65 # johbo: On 16.09 we need this to compile on darwin, otherwise compilation
83 66 # fails on Darwin.
@@ -133,10 +116,6 b' self: super: {'
133 116 };
134 117 });
135 118
136 Pylons = super.Pylons.override (attrs: {
137 name = "Pylons-1.0.2.rhodecode-patch1";
138 });
139
140 119 pyramid = super.pyramid.override (attrs: {
141 120 postFixup = ''
142 121 wrapPythonPrograms
@@ -184,30 +184,17 b''
184 184 license = [ pkgs.lib.licenses.bsdOriginal ];
185 185 };
186 186 };
187 Pylons = super.buildPythonPackage {
188 name = "Pylons-1.0.2.dev20171106";
187 Routes = super.buildPythonPackage {
188 name = "Routes-2.4.1";
189 189 buildInputs = with self; [];
190 190 doCheck = false;
191 propagatedBuildInputs = with self; [Routes WebHelpers Beaker Paste PasteDeploy PasteScript FormEncode simplejson decorator nose Mako WebError WebTest Tempita MarkupSafe WebOb];
191 propagatedBuildInputs = with self; [six repoze.lru];
192 192 src = fetchurl {
193 url = "https://code.rhodecode.com/upstream/pylons/archive/707354ee4261b9c10450404fc9852ccea4fd667d.tar.gz?md5=f26633726fa2cd3a340316ee6a5d218f";
194 md5 = "f26633726fa2cd3a340316ee6a5d218f";
193 url = "https://pypi.python.org/packages/33/38/ea827837e68d9c7dde4cff7ec122a93c319f0effc08ce92a17095576603f/Routes-2.4.1.tar.gz";
194 md5 = "c058dff6832941dec47e0d0052548ad8";
195 195 };
196 196 meta = {
197 license = [ pkgs.lib.licenses.bsdOriginal ];
198 };
199 };
200 Routes = super.buildPythonPackage {
201 name = "Routes-1.13";
202 buildInputs = with self; [];
203 doCheck = false;
204 propagatedBuildInputs = with self; [repoze.lru];
205 src = fetchurl {
206 url = "https://pypi.python.org/packages/88/d3/259c3b3cde8837eb9441ab5f574a660e8a4acea8f54a078441d4d2acac1c/Routes-1.13.tar.gz";
207 md5 = "d527b0ab7dd9172b1275a41f97448783";
208 };
209 meta = {
210 license = [ pkgs.lib.licenses.bsdOriginal ];
197 license = [ pkgs.lib.licenses.mit ];
211 198 };
212 199 };
213 200 SQLAlchemy = super.buildPythonPackage {
@@ -340,6 +327,19 b''
340 327 license = [ pkgs.lib.licenses.mit ];
341 328 };
342 329 };
330 amqp = super.buildPythonPackage {
331 name = "amqp-2.2.2";
332 buildInputs = with self; [];
333 doCheck = false;
334 propagatedBuildInputs = with self; [vine];
335 src = fetchurl {
336 url = "https://pypi.python.org/packages/e0/70/9ab9ccd8247fb7d2adb717e9f6a0ed358c9e1ab2c349048b0352f9e80ee2/amqp-2.2.2.tar.gz";
337 md5 = "0971a3fd2d635ded45c349cfc17106bd";
338 };
339 meta = {
340 license = [ pkgs.lib.licenses.bsdOriginal ];
341 };
342 };
343 343 amqplib = super.buildPythonPackage {
344 344 name = "amqplib-1.0.2";
345 345 buildInputs = with self; [];
@@ -353,19 +353,6 b''
353 353 license = [ { fullName = "LGPL"; } { fullName = "GNU Library or Lesser General Public License (LGPL)"; } ];
354 354 };
355 355 };
356 anyjson = super.buildPythonPackage {
357 name = "anyjson-0.3.3";
358 buildInputs = with self; [];
359 doCheck = false;
360 propagatedBuildInputs = with self; [];
361 src = fetchurl {
362 url = "https://pypi.python.org/packages/c3/4d/d4089e1a3dd25b46bebdb55a992b0797cff657b4477bc32ce28038fdecbc/anyjson-0.3.3.tar.gz";
363 md5 = "2ea28d6ec311aeeebaf993cb3008b27c";
364 };
365 meta = {
366 license = [ pkgs.lib.licenses.bsdOriginal ];
367 };
368 };
369 356 appenlight-client = super.buildPythonPackage {
370 357 name = "appenlight-client-0.6.22";
371 358 buildInputs = with self; [];
@@ -418,6 +405,19 b''
418 405 license = [ pkgs.lib.licenses.mit ];
419 406 };
420 407 };
408 billiard = super.buildPythonPackage {
409 name = "billiard-3.5.0.3";
410 buildInputs = with self; [];
411 doCheck = false;
412 propagatedBuildInputs = with self; [];
413 src = fetchurl {
414 url = "https://pypi.python.org/packages/39/ac/f5571210cca2e4f4532e38aaff242f26c8654c5e2436bee966c230647ccc/billiard-3.5.0.3.tar.gz";
415 md5 = "113ba481e48400adbf6fbbf59a2f8554";
416 };
417 meta = {
418 license = [ pkgs.lib.licenses.bsdOriginal ];
419 };
420 };
421 421 bleach = super.buildPythonPackage {
422 422 name = "bleach-1.5.0";
423 423 buildInputs = with self; [];
@@ -458,13 +458,13 b''
458 458 };
459 459 };
460 460 celery = super.buildPythonPackage {
461 name = "celery-2.2.10";
461 name = "celery-4.1.0";
462 462 buildInputs = with self; [];
463 463 doCheck = false;
464 propagatedBuildInputs = with self; [python-dateutil anyjson kombu pyparsing];
464 propagatedBuildInputs = with self; [pytz billiard kombu];
465 465 src = fetchurl {
466 url = "https://pypi.python.org/packages/b1/64/860fd50e45844c83442e7953effcddeff66b2851d90b2d784f7201c111b8/celery-2.2.10.tar.gz";
467 md5 = "898bc87e54f278055b561316ba73e222";
466 url = "https://pypi.python.org/packages/07/65/88a2a45fc80f487872c93121a701a53bbbc3d3d832016876fac84fc8d46a/celery-4.1.0.tar.gz";
467 md5 = "db91e1d26936381127f01e150fe3054a";
468 468 };
469 469 meta = {
470 470 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1004,13 +1004,13 b''
1004 1004 };
1005 1005 };
1006 1006 kombu = super.buildPythonPackage {
1007 name = "kombu-1.5.1";
1007 name = "kombu-4.1.0";
1008 1008 buildInputs = with self; [];
1009 1009 doCheck = false;
1010 propagatedBuildInputs = with self; [anyjson amqplib];
1010 propagatedBuildInputs = with self; [amqp];
1011 1011 src = fetchurl {
1012 url = "https://pypi.python.org/packages/19/53/74bf2a624644b45f0850a638752514fc10a8e1cbd738f10804951a6df3f5/kombu-1.5.1.tar.gz";
1013 md5 = "50662f3c7e9395b3d0721fb75d100b63";
1012 url = "https://pypi.python.org/packages/03/5e/1a47d1e543d4943d65330af4e4406049f443878818fb65bfdc651bb93a96/kombu-4.1.0.tar.gz";
1013 md5 = "2fb2be9fec0e6514231bba23a3779439";
1014 1014 };
1015 1015 meta = {
1016 1016 license = [ pkgs.lib.licenses.bsdOriginal ];
@@ -1094,19 +1094,6 b''
1094 1094 license = [ pkgs.lib.licenses.bsdOriginal ];
1095 1095 };
1096 1096 };
1097 nose = super.buildPythonPackage {
1098 name = "nose-1.3.6";
1099 buildInputs = with self; [];
1100 doCheck = false;
1101 propagatedBuildInputs = with self; [];
1102 src = fetchurl {
1103 url = "https://pypi.python.org/packages/70/c7/469e68148d17a0d3db5ed49150242fd70a74a8147b8f3f8b87776e028d99/nose-1.3.6.tar.gz";
1104 md5 = "0ca546d81ca8309080fc80cb389e7a16";
1105 };
1106 meta = {
1107 license = [ { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "GNU LGPL"; } ];
1108 };
1109 };
1110 1097 objgraph = super.buildPythonPackage {
1111 1098 name = "objgraph-3.1.1";
1112 1099 buildInputs = with self; [];
@@ -1173,13 +1160,13 b''
1173 1160 };
1174 1161 };
1175 1162 pexpect = super.buildPythonPackage {
1176 name = "pexpect-4.2.1";
1163 name = "pexpect-4.3.0";
1177 1164 buildInputs = with self; [];
1178 1165 doCheck = false;
1179 1166 propagatedBuildInputs = with self; [ptyprocess];
1180 1167 src = fetchurl {
1181 url = "https://pypi.python.org/packages/e8/13/d0b0599099d6cd23663043a2a0bb7c61e58c6ba359b2656e6fb000ef5b98/pexpect-4.2.1.tar.gz";
1182 md5 = "3694410001a99dff83f0b500a1ca1c95";
1168 url = "https://pypi.python.org/packages/f8/44/5466c30e49762bb92e442bbdf4472d6904608d211258eb3198a11f0309a4/pexpect-4.3.0.tar.gz";
1169 md5 = "047a486dcd26134b74f2e67046bb61a0";
1183 1170 };
1184 1171 meta = {
1185 1172 license = [ pkgs.lib.licenses.isc { fullName = "ISC License (ISCL)"; } ];
@@ -1550,16 +1537,16 b''
1550 1537 };
1551 1538 };
1552 1539 python-dateutil = super.buildPythonPackage {
1553 name = "python-dateutil-2.1";
1540 name = "python-dateutil-2.6.1";
1554 1541 buildInputs = with self; [];
1555 1542 doCheck = false;
1556 1543 propagatedBuildInputs = with self; [six];
1557 1544 src = fetchurl {
1558 url = "https://pypi.python.org/packages/65/52/9c18dac21f174ad31b65e22d24297864a954e6fe65876eba3f5773d2da43/python-dateutil-2.1.tar.gz";
1559 md5 = "1534bb15cf311f07afaa3aacba1c028b";
1545 url = "https://pypi.python.org/packages/54/bb/f1db86504f7a49e1d9b9301531181b00a1c7325dc85a29160ee3eaa73a54/python-dateutil-2.6.1.tar.gz";
1546 md5 = "db38f6b4511cefd76014745bb0cc45a4";
1560 1547 };
1561 1548 meta = {
1562 license = [ { fullName = "Simplified BSD"; } ];
1549 license = [ pkgs.lib.licenses.bsdOriginal { fullName = "Simplified BSD"; } ];
1563 1550 };
1564 1551 };
1565 1552 python-editor = super.buildPythonPackage {
@@ -1615,13 +1602,13 b''
1615 1602 };
1616 1603 };
1617 1604 pytz = super.buildPythonPackage {
1618 name = "pytz-2015.4";
1605 name = "pytz-2017.3";
1619 1606 buildInputs = with self; [];
1620 1607 doCheck = false;
1621 1608 propagatedBuildInputs = with self; [];
1622 1609 src = fetchurl {
1623 url = "https://pypi.python.org/packages/7e/1a/f43b5c92df7b156822030fed151327ea096bcf417e45acc23bd1df43472f/pytz-2015.4.zip";
1624 md5 = "233f2a2b370d03f9b5911700cc9ebf3c";
1610 url = "https://pypi.python.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip";
1611 md5 = "7006b56c0d68a162d9fe57d4249c3171";
1625 1612 };
1626 1613 meta = {
1627 1614 license = [ pkgs.lib.licenses.mit ];
@@ -1696,7 +1683,7 b''
1696 1683 name = "rhodecode-enterprise-ce-4.11.0";
1697 1684 buildInputs = with self; [pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage configobj];
1698 1685 doCheck = true;
1699 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];
1686 propagatedBuildInputs = with self; [setuptools-scm amqplib amqp authomatic Babel Beaker celery Chameleon channelstream click colander configobj cssselect decorator deform docutils dogpile.cache dogpile.core ecdsa FormEncode future futures gnureadline infrae.cache iso8601 itsdangerous Jinja2 billiard kombu lxml Mako Markdown MarkupSafe msgpack-python MySQL-python objgraph packaging Paste PasteDeploy PasteScript pathlib2 peppercorn psutil psycopg2 py-bcrypt pycrypto pycurl pyflakes pygments-markdown-lexer Pygments pyparsing pyramid-beaker pyramid-debugtoolbar pyramid-jinja2 pyramid-mako pyramid pysqlite python-dateutil python-ldap python-memcached python-pam pytz pyzmq py-gfm recaptcha-client redis repoze.lru requests Routes setproctitle simplejson six SQLAlchemy sshpubkeys subprocess32 Tempita translationstring trollius urllib3 URLObject venusian WebError WebHelpers2 WebHelpers WebOb Whoosh wsgiref zope.cachedescriptors zope.deprecation zope.event zope.interface nbconvert bleach nbformat jupyter-client alembic invoke bumpversion transifex-client gevent greenlet gunicorn waitress uWSGI ipdb ipython CProfileV bottle rhodecode-tools appenlight-client pytest py pytest-cov pytest-sugar pytest-runner pytest-catchlog pytest-profiling gprof2dot pytest-timeout mock WebTest cov-core coverage];
1700 1687 src = ./.;
1701 1688 meta = {
1702 1689 license = [ { fullName = "Affero GNU General Public License v3 or later (AGPLv3+)"; } { fullName = "AGPLv3, and Commercial License"; } ];
@@ -1755,13 +1742,13 b''
1755 1742 };
1756 1743 };
1757 1744 setuptools-scm = super.buildPythonPackage {
1758 name = "setuptools-scm-1.15.0";
1745 name = "setuptools-scm-1.15.6";
1759 1746 buildInputs = with self; [];
1760 1747 doCheck = false;
1761 1748 propagatedBuildInputs = with self; [];
1762 1749 src = fetchurl {
1763 url = "https://pypi.python.org/packages/80/b7/31b6ae5fcb188e37f7e31abe75f9be90490a5456a72860fa6e643f8a3cbc/setuptools_scm-1.15.0.tar.gz";
1764 md5 = "b6916c78ed6253d6602444fad4279c5b";
1750 url = "https://pypi.python.org/packages/03/6d/aafdd01edd227ee879b691455bf19895091872af7e48192bea1758c82032/setuptools_scm-1.15.6.tar.gz";
1751 md5 = "f17493d53f0d842bb0152f214775640b";
1765 1752 };
1766 1753 meta = {
1767 1754 license = [ pkgs.lib.licenses.mit ];
@@ -1949,6 +1936,19 b''
1949 1936 license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
1950 1937 };
1951 1938 };
1939 vine = super.buildPythonPackage {
1940 name = "vine-1.1.4";
1941 buildInputs = with self; [];
1942 doCheck = false;
1943 propagatedBuildInputs = with self; [];
1944 src = fetchurl {
1945 url = "https://pypi.python.org/packages/32/23/36284986e011f3c130d802c3c66abd8f1aef371eae110ddf80c5ae22e1ff/vine-1.1.4.tar.gz";
1946 md5 = "9fdb971e7fd15b181b84f3bfcf20d11c";
1947 };
1948 meta = {
1949 license = [ pkgs.lib.licenses.bsdOriginal ];
1950 };
1951 };
1952 1952 waitress = super.buildPythonPackage {
1953 1953 name = "waitress-1.1.0";
1954 1954 buildInputs = with self; [];
@@ -1,13 +1,13 b''
1 1 ## core
2 2 setuptools==30.1.0
3 setuptools-scm==1.15.0
3 setuptools-scm==1.15.6
4 4
5 5 amqplib==1.0.2
6 anyjson==0.3.3
6 amqp==2.2.2
7 7 authomatic==0.1.0.post1
8 8 Babel==1.3
9 9 Beaker==1.9.0
10 celery==2.2.10
10 celery==4.1.0
11 11 Chameleon==2.24
12 12 channelstream==0.5.2
13 13 click==6.6
@@ -28,7 +28,8 b' infrae.cache==1.0.1'
28 28 iso8601==0.1.12
29 29 itsdangerous==0.24
30 30 Jinja2==2.9.6
31 kombu==1.5.1
31 billiard==3.5.0.3
32 kombu==4.1.0
32 33 lxml==3.7.3
33 34 Mako==1.0.7
34 35 Markdown==2.6.9
@@ -57,18 +58,18 b' pyramid-jinja2==2.7'
57 58 pyramid-mako==1.0.2
58 59 pyramid==1.9.1
59 60 pysqlite==2.8.3
60 python-dateutil==2.1
61 python-dateutil
61 62 python-ldap==2.4.45
62 63 python-memcached==1.58
63 64 python-pam==1.8.2
64 pytz==2015.4
65 pytz==2017.3
65 66 pyzmq==14.6.0
66 67 py-gfm==0.1.3
67 68 recaptcha-client==1.0.6
68 69 redis==2.10.6
69 70 repoze.lru==0.7
70 71 requests==2.9.1
71 Routes==1.13
72 Routes==2.4.1
72 73 setproctitle==1.1.10
73 74 simplejson==3.11.1
74 75 six==1.11.0
@@ -92,10 +93,6 b' zope.deprecation==4.1.2'
92 93 zope.event==4.0.3
93 94 zope.interface==4.1.3
94 95
95 ## customized/patched libs
96 # our patched version of Pylons==1.0.2
97 https://code.rhodecode.com/upstream/pylons/archive/707354ee4261b9c10450404fc9852ccea4fd667d.tar.gz?md5=f26633726fa2cd3a340316ee6a5d218f#egg=Pylons==1.0.2.rhodecode-patch-1
98
99 96
100 97 # IPYTHON RENDERING
101 98 # entrypoints backport, pypi version doesn't support egg installs
@@ -27,7 +27,7 b' from rhodecode.tests import TEST_USER_AD'
27 27
28 28
29 29 @pytest.fixture(scope="class")
30 def testuser_api(request, pylonsapp):
30 def testuser_api(request, baseapp):
31 31 cls = request.cls
32 32
33 33 # ADMIN USER
@@ -159,32 +159,14 b' class BaseAppView(object):'
159 159
160 160 return c
161 161
162 def _register_global_c(self, tmpl_args):
163 """
164 Registers attributes to pylons global `c`
165 """
166
167 # TODO(marcink): remove once pyramid migration is finished
168 from pylons import tmpl_context as c
169 try:
170 for k, v in tmpl_args.items():
171 setattr(c, k, v)
172 except TypeError:
173 log.exception('Failed to register pylons C')
174 pass
175
176 def _get_template_context(self, tmpl_args):
177 self._register_global_c(tmpl_args)
162 def _get_template_context(self, tmpl_args, **kwargs):
178 163
179 164 local_tmpl_args = {
180 165 'defaults': {},
181 166 'errors': {},
182 # register a fake 'c' to be used in templates instead of global
183 # pylons c, after migration to pyramid we should rename it to 'c'
184 # make sure we replace usage of _c in templates too
185 '_c': tmpl_args
167 'c': tmpl_args
186 168 }
187 local_tmpl_args.update(tmpl_args)
169 local_tmpl_args.update(kwargs)
188 170 return local_tmpl_args
189 171
190 172 def load_default_context(self):
@@ -194,7 +176,7 b' class BaseAppView(object):'
194 176 def load_default_context(self):
195 177 c = self._get_local_tmpl_context()
196 178 c.custom_var = 'foobar'
197 self._register_global_c(c)
179
198 180 return c
199 181 """
200 182 raise NotImplementedError('Needs implementation in view class')
@@ -213,7 +195,7 b' class RepoAppView(BaseAppView):'
213 195 'Requirements are missing for repository %s: %s',
214 196 self.db_repo_name, error.message)
215 197
216 def _get_local_tmpl_context(self, include_app_defaults=False):
198 def _get_local_tmpl_context(self, include_app_defaults=True):
217 199 _ = self.request.translate
218 200 c = super(RepoAppView, self)._get_local_tmpl_context(
219 201 include_app_defaults=include_app_defaults)
@@ -336,7 +318,7 b' class BaseReferencesView(RepoAppView):'
336 318 def load_default_context(self):
337 319 c = self._get_local_tmpl_context()
338 320
339 self._register_global_c(c)
321
340 322 return c
341 323
342 324 def load_refs_context(self, ref_items, partials_template):
@@ -25,7 +25,6 b' import collections'
25 25 from zope.interface import implementer
26 26
27 27 from rhodecode.apps.admin.interfaces import IAdminNavigationRegistry
28 from rhodecode.lib.utils import get_registry
29 28 from rhodecode.lib.utils2 import str2bool
30 29 from rhodecode.translation import _
31 30
@@ -116,7 +115,7 b' def navigation_registry(request, registr'
116 115 """
117 116 Helper that returns the admin navigation registry.
118 117 """
119 pyramid_registry = registry or get_registry(request)
118 pyramid_registry = registry or request.registry
120 119 nav_registry = pyramid_registry.queryUtility(IAdminNavigationRegistry)
121 120 return nav_registry
122 121
@@ -46,10 +46,11 b' def route_path(name, params=None, **kwar'
46 46 return base_url
47 47
48 48
49 class TestAdminController(TestController):
49 @pytest.mark.usefixtures('app')
50 class TestAdminController(object):
50 51
51 52 @pytest.fixture(scope='class', autouse=True)
52 def prepare(self, request, pylonsapp):
53 def prepare(self, request, baseapp):
53 54 UserLog.query().delete()
54 55 Session().commit()
55 56
@@ -84,104 +85,87 b' class TestAdminController(TestController'
84 85 UserLog.query().delete()
85 86 Session().commit()
86 87
87 def test_index(self):
88 self.log_user()
88 def test_index(self, autologin_user):
89 89 response = self.app.get(route_path('admin_audit_logs'))
90 90 response.mustcontain('Admin audit logs')
91 91
92 def test_filter_all_entries(self):
93 self.log_user()
92 def test_filter_all_entries(self, autologin_user):
94 93 response = self.app.get(route_path('admin_audit_logs'))
95 94 all_count = UserLog.query().count()
96 95 response.mustcontain('%s entries' % all_count)
97 96
98 def test_filter_journal_filter_exact_match_on_repository(self):
99 self.log_user()
97 def test_filter_journal_filter_exact_match_on_repository(self, autologin_user):
100 98 response = self.app.get(route_path('admin_audit_logs',
101 99 params=dict(filter='repository:rhodecode')))
102 100 response.mustcontain('3 entries')
103 101
104 def test_filter_journal_filter_exact_match_on_repository_CamelCase(self):
105 self.log_user()
102 def test_filter_journal_filter_exact_match_on_repository_CamelCase(self, autologin_user):
106 103 response = self.app.get(route_path('admin_audit_logs',
107 104 params=dict(filter='repository:RhodeCode')))
108 105 response.mustcontain('3 entries')
109 106
110 def test_filter_journal_filter_wildcard_on_repository(self):
111 self.log_user()
107 def test_filter_journal_filter_wildcard_on_repository(self, autologin_user):
112 108 response = self.app.get(route_path('admin_audit_logs',
113 109 params=dict(filter='repository:*test*')))
114 110 response.mustcontain('862 entries')
115 111
116 def test_filter_journal_filter_prefix_on_repository(self):
117 self.log_user()
112 def test_filter_journal_filter_prefix_on_repository(self, autologin_user):
118 113 response = self.app.get(route_path('admin_audit_logs',
119 114 params=dict(filter='repository:test*')))
120 115 response.mustcontain('257 entries')
121 116
122 def test_filter_journal_filter_prefix_on_repository_CamelCase(self):
123 self.log_user()
117 def test_filter_journal_filter_prefix_on_repository_CamelCase(self, autologin_user):
124 118 response = self.app.get(route_path('admin_audit_logs',
125 119 params=dict(filter='repository:Test*')))
126 120 response.mustcontain('257 entries')
127 121
128 def test_filter_journal_filter_prefix_on_repository_and_user(self):
129 self.log_user()
122 def test_filter_journal_filter_prefix_on_repository_and_user(self, autologin_user):
130 123 response = self.app.get(route_path('admin_audit_logs',
131 124 params=dict(filter='repository:test* AND username:demo')))
132 125 response.mustcontain('130 entries')
133 126
134 def test_filter_journal_filter_prefix_on_repository_or_target_repo(self):
135 self.log_user()
127 def test_filter_journal_filter_prefix_on_repository_or_target_repo(self, autologin_user):
136 128 response = self.app.get(route_path('admin_audit_logs',
137 129 params=dict(filter='repository:test* OR repository:rhodecode')))
138 130 response.mustcontain('260 entries') # 257 + 3
139 131
140 def test_filter_journal_filter_exact_match_on_username(self):
141 self.log_user()
132 def test_filter_journal_filter_exact_match_on_username(self, autologin_user):
142 133 response = self.app.get(route_path('admin_audit_logs',
143 134 params=dict(filter='username:demo')))
144 135 response.mustcontain('1087 entries')
145 136
146 def test_filter_journal_filter_exact_match_on_username_camelCase(self):
147 self.log_user()
137 def test_filter_journal_filter_exact_match_on_username_camelCase(self, autologin_user):
148 138 response = self.app.get(route_path('admin_audit_logs',
149 139 params=dict(filter='username:DemO')))
150 140 response.mustcontain('1087 entries')
151 141
152 def test_filter_journal_filter_wildcard_on_username(self):
153 self.log_user()
142 def test_filter_journal_filter_wildcard_on_username(self, autologin_user):
154 143 response = self.app.get(route_path('admin_audit_logs',
155 144 params=dict(filter='username:*test*')))
156 145 entries_count = UserLog.query().filter(UserLog.username.ilike('%test%')).count()
157 146 response.mustcontain('{} entries'.format(entries_count))
158 147
159 def test_filter_journal_filter_prefix_on_username(self):
160 self.log_user()
148 def test_filter_journal_filter_prefix_on_username(self, autologin_user):
161 149 response = self.app.get(route_path('admin_audit_logs',
162 150 params=dict(filter='username:demo*')))
163 151 response.mustcontain('1101 entries')
164 152
165 def test_filter_journal_filter_prefix_on_user_or_other_user(self):
166 self.log_user()
153 def test_filter_journal_filter_prefix_on_user_or_other_user(self, autologin_user):
167 154 response = self.app.get(route_path('admin_audit_logs',
168 155 params=dict(filter='username:demo OR username:volcan')))
169 156 response.mustcontain('1095 entries') # 1087 + 8
170 157
171 def test_filter_journal_filter_wildcard_on_action(self):
172 self.log_user()
158 def test_filter_journal_filter_wildcard_on_action(self, autologin_user):
173 159 response = self.app.get(route_path('admin_audit_logs',
174 160 params=dict(filter='action:*pull_request*')))
175 161 response.mustcontain('187 entries')
176 162
177 def test_filter_journal_filter_on_date(self):
178 self.log_user()
163 def test_filter_journal_filter_on_date(self, autologin_user):
179 164 response = self.app.get(route_path('admin_audit_logs',
180 165 params=dict(filter='date:20121010')))
181 166 response.mustcontain('47 entries')
182 167
183 def test_filter_journal_filter_on_date_2(self):
184 self.log_user()
168 def test_filter_journal_filter_on_date_2(self, autologin_user):
185 169 response = self.app.get(route_path('admin_audit_logs',
186 170 params=dict(filter='date:20121020')))
187 171 response.mustcontain('17 entries')
@@ -429,7 +429,7 b' class TestAdminSettingsVcs(object):'
429 429 # TODO: johbo: What we really want is to checkpoint before a test run and
430 430 # reset the session afterwards.
431 431 @pytest.fixture(scope='class', autouse=True)
432 def cleanup_settings(self, request, pylonsapp):
432 def cleanup_settings(self, request, baseapp):
433 433 ui_id = RhodeCodeUi.ui_id
434 434 original_ids = list(
435 435 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
@@ -23,7 +23,6 b' from sqlalchemy.orm.exc import NoResultF'
23 23
24 24 from rhodecode.lib import auth
25 25 from rhodecode.lib import helpers as h
26 from rhodecode.model import validators
27 26 from rhodecode.model.db import User, UserApiKeys, UserEmailMap, Repository
28 27 from rhodecode.model.meta import Session
29 28 from rhodecode.model.user import UserModel
@@ -386,8 +385,7 b' class TestAdminUsersView(TestController)'
386 385 'csrf_token': self.csrf_token,
387 386 })
388 387
389 msg = validators.ValidUsername(
390 False, {})._messages['system_invalid_username']
388 msg = '???'
391 389 msg = h.html_escape(msg % {'username': 'new_user'})
392 390 response.mustcontain('<span class="error-message">%s</span>' % msg)
393 391 response.mustcontain(
@@ -36,7 +36,6 b' log = logging.getLogger(__name__)'
36 36 class AdminAuditLogsView(BaseAppView):
37 37 def load_default_context(self):
38 38 c = self._get_local_tmpl_context()
39 self._register_global_c(c)
40 39 return c
41 40
42 41 @LoginRequired()
@@ -44,7 +44,7 b' class AdminDefaultSettingsView(BaseAppVi'
44 44 def load_default_context(self):
45 45 c = self._get_local_tmpl_context()
46 46
47 self._register_global_c(c)
47
48 48 return c
49 49
50 50 @LoginRequired()
@@ -79,7 +79,7 b' class AdminDefaultSettingsView(BaseAppVi'
79 79 _ = self.request.translate
80 80 c = self.load_default_context()
81 81 c.active = 'repositories'
82 form = DefaultsForm()()
82 form = DefaultsForm(self.request.translate)()
83 83
84 84 try:
85 85 form_result = form.to_python(dict(self.request.POST))
@@ -35,7 +35,7 b' class OpenSourceLicensesAdminSettingsVie'
35 35
36 36 def load_default_context(self):
37 37 c = self._get_local_tmpl_context()
38 self._register_global_c(c)
38
39 39 return c
40 40
41 41 @LoginRequired()
@@ -54,7 +54,7 b' class AdminPermissionsView(BaseAppView, '
54 54 def load_default_context(self):
55 55 c = self._get_local_tmpl_context()
56 56
57 self._register_global_c(c)
57
58 58 PermissionModel().set_global_permission_choices(
59 59 c, gettext_translator=self.request.translate)
60 60 return c
@@ -100,6 +100,7 b' class AdminPermissionsView(BaseAppView, '
100 100 c.active = 'application'
101 101
102 102 _form = ApplicationPermissionsForm(
103 self.request.translate,
103 104 [x[0] for x in c.register_choices],
104 105 [x[0] for x in c.password_reset_choices],
105 106 [x[0] for x in c.extern_activate_choices])()
@@ -180,6 +181,7 b' class AdminPermissionsView(BaseAppView, '
180 181 c.active = 'objects'
181 182
182 183 _form = ObjectPermissionsForm(
184 self.request.translate,
183 185 [x[0] for x in c.repo_perms_choices],
184 186 [x[0] for x in c.group_perms_choices],
185 187 [x[0] for x in c.user_group_perms_choices])()
@@ -251,6 +253,7 b' class AdminPermissionsView(BaseAppView, '
251 253 c.active = 'global'
252 254
253 255 _form = UserPermissionsForm(
256 self.request.translate,
254 257 [x[0] for x in c.repo_create_choices],
255 258 [x[0] for x in c.repo_create_on_write_choices],
256 259 [x[0] for x in c.repo_group_create_choices],
@@ -395,6 +398,7 b' class AdminPermissionsView(BaseAppView, '
395 398 renderer='json_ext', xhr=True)
396 399 def ssh_keys_data(self):
397 400 _ = self.request.translate
401 self.load_default_context()
398 402 column_map = {
399 403 'fingerprint': 'ssh_key_fingerprint',
400 404 'username': User.username
@@ -35,7 +35,7 b' log = logging.getLogger(__name__)'
35 35 class AdminProcessManagementView(BaseAppView):
36 36 def load_default_context(self):
37 37 c = self._get_local_tmpl_context()
38 self._register_global_c(c)
38
39 39 return c
40 40
41 41 @LoginRequired()
@@ -47,7 +47,7 b' class AdminRepoGroupsView(BaseAppView, D'
47 47
48 48 def load_default_context(self):
49 49 c = self._get_local_tmpl_context()
50 self._register_global_c(c)
50
51 51 return c
52 52
53 53 def _load_form_data(self, c):
@@ -150,8 +150,9 b' class AdminRepoGroupsView(BaseAppView, D'
150 150 # permissions for can create group based on parent_id are checked
151 151 # here in the Form
152 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)()
153 repo_group_form = RepoGroupForm(
154 self.request.translate, available_groups=available_groups,
155 can_create_in_root=can_create)()
155 156
156 157 repo_group_name = self.request.POST.get('group_name')
157 158 try:
@@ -49,7 +49,7 b' class AdminReposView(BaseAppView, DataGr'
49 49
50 50 def load_default_context(self):
51 51 c = self._get_local_tmpl_context()
52 self._register_global_c(c)
52
53 53 return c
54 54
55 55 def _load_form_data(self, c):
@@ -148,9 +148,10 b' class AdminReposView(BaseAppView, DataGr'
148 148
149 149 try:
150 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))
151 form = RepoForm(
152 self.request.translate, repo_groups=c.repo_groups_choices,
153 landing_revs=c.landing_revs_choices)()
154 form_results = form.to_python(dict(self.request.POST))
154 155
155 156 # create is done sometimes async on celery, db transaction
156 157 # management is handled there.
@@ -39,7 +39,7 b' class AdminSessionSettingsView(BaseAppVi'
39 39 def load_default_context(self):
40 40 c = self._get_local_tmpl_context()
41 41
42 self._register_global_c(c)
42
43 43 return c
44 44
45 45 @LoginRequired()
@@ -67,7 +67,7 b' class AdminSettingsView(BaseAppView):'
67 67 c.labs_active = str2bool(
68 68 rhodecode.CONFIG.get('labs_settings_active', 'true'))
69 69 c.navlist = navigation_list(self.request)
70 self._register_global_c(c)
70
71 71 return c
72 72
73 73 @classmethod
@@ -153,7 +153,7 b' class AdminSettingsView(BaseAppView):'
153 153 settings = self.request.registry.settings
154 154 c.svn_proxy_generate_config = settings[generate_config]
155 155
156 application_form = ApplicationUiSettingsForm()()
156 application_form = ApplicationUiSettingsForm(self.request.translate)()
157 157
158 158 try:
159 159 form_result = application_form.to_python(dict(self.request.POST))
@@ -310,7 +310,7 b' class AdminSettingsView(BaseAppView):'
310 310 c.active = 'global'
311 311 c.personal_repo_group_default_pattern = RepoGroupModel()\
312 312 .get_personal_group_name_pattern()
313 application_form = ApplicationSettingsForm()()
313 application_form = ApplicationSettingsForm(self.request.translate)()
314 314 try:
315 315 form_result = application_form.to_python(dict(self.request.POST))
316 316 except formencode.Invalid as errors:
@@ -382,7 +382,7 b' class AdminSettingsView(BaseAppView):'
382 382 _ = self.request.translate
383 383 c = self.load_default_context()
384 384 c.active = 'visual'
385 application_form = ApplicationVisualisationForm()()
385 application_form = ApplicationVisualisationForm(self.request.translate)()
386 386 try:
387 387 form_result = application_form.to_python(dict(self.request.POST))
388 388 except formencode.Invalid as errors:
@@ -482,7 +482,7 b' class AdminSettingsView(BaseAppView):'
482 482 settings_model = IssueTrackerSettingsModel()
483 483
484 484 try:
485 form = IssueTrackerPatternsForm()().to_python(self.request.POST)
485 form = IssueTrackerPatternsForm(self.request.translate)().to_python(self.request.POST)
486 486 except formencode.Invalid as errors:
487 487 log.exception('Failed to add new pattern')
488 488 error = errors
@@ -698,7 +698,7 b' class AdminSettingsView(BaseAppView):'
698 698 c = self.load_default_context()
699 699 c.active = 'labs'
700 700
701 application_form = LabsSettingsForm()()
701 application_form = LabsSettingsForm(self.request.translate)()
702 702 try:
703 703 form_result = application_form.to_python(dict(self.request.POST))
704 704 except formencode.Invalid as errors:
@@ -40,7 +40,7 b' log = logging.getLogger(__name__)'
40 40 class AdminSystemInfoSettingsView(BaseAppView):
41 41 def load_default_context(self):
42 42 c = self._get_local_tmpl_context()
43 self._register_global_c(c)
43
44 44 return c
45 45
46 46 @staticmethod
@@ -53,7 +53,7 b' class AdminUserGroupsView(BaseAppView, D'
53 53 PermissionModel().set_global_permission_choices(
54 54 c, gettext_translator=self.request.translate)
55 55
56 self._register_global_c(c)
56
57 57 return c
58 58
59 59 # permission check in data loading of
@@ -196,7 +196,7 b' class AdminUserGroupsView(BaseAppView, D'
196 196 def user_groups_create(self):
197 197 _ = self.request.translate
198 198 c = self.load_default_context()
199 users_group_form = UserGroupForm()()
199 users_group_form = UserGroupForm(self.request.translate)()
200 200
201 201 user_group_name = self.request.POST.get('users_group_name')
202 202 try:
@@ -44,7 +44,8 b' from rhodecode.lib import helpers as h'
44 44 from rhodecode.lib.utils2 import safe_int, safe_unicode, AttributeDict
45 45 from rhodecode.model.auth_token import AuthTokenModel
46 46 from rhodecode.model.forms import (
47 UserForm, UserIndividualPermissionsForm, UserPermissionsForm)
47 UserForm, UserIndividualPermissionsForm, UserPermissionsForm,
48 UserExtraEmailForm, UserExtraIpForm)
48 49 from rhodecode.model.permission import PermissionModel
49 50 from rhodecode.model.repo_group import RepoGroupModel
50 51 from rhodecode.model.ssh_key import SshKeyModel
@@ -62,7 +63,6 b' class AdminUsersView(BaseAppView, DataGr'
62 63
63 64 def load_default_context(self):
64 65 c = self._get_local_tmpl_context()
65 self._register_global_c(c)
66 66 return c
67 67
68 68 @LoginRequired()
@@ -191,7 +191,7 b' class AdminUsersView(BaseAppView, DataGr'
191 191 c = self.load_default_context()
192 192 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
193 193 user_model = UserModel()
194 user_form = UserForm()()
194 user_form = UserForm(self.request.translate)()
195 195 try:
196 196 form_result = user_form.to_python(dict(self.request.POST))
197 197 user = user_model.create(form_result)
@@ -259,7 +259,7 b' class UsersView(UserAppView):'
259 259 PermissionModel().set_global_permission_choices(
260 260 c, gettext_translator=req.translate)
261 261
262 self._register_global_c(c)
262
263 263 return c
264 264
265 265 @LoginRequired()
@@ -280,7 +280,8 b' class UsersView(UserAppView):'
280 280 c.extern_name = c.user.extern_name
281 281 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
282 282 available_languages = [x[0] for x in c.allowed_languages]
283 _form = UserForm(edit=True, available_languages=available_languages,
283 _form = UserForm(self.request.translate, edit=True,
284 available_languages=available_languages,
284 285 old_data={'user_id': user_id,
285 286 'email': c.user.email})()
286 287 form_result = {}
@@ -538,7 +539,7 b' class UsersView(UserAppView):'
538 539 c.active = 'global_perms'
539 540 try:
540 541 # first stage that verifies the checkbox
541 _form = UserIndividualPermissionsForm()
542 _form = UserIndividualPermissionsForm(self.request.translate)
542 543 form_result = _form.to_python(dict(self.request.POST))
543 544 inherit_perms = form_result['inherit_default_permissions']
544 545 c.user.inherit_default_permissions = inherit_perms
@@ -547,6 +548,7 b' class UsersView(UserAppView):'
547 548 if not inherit_perms:
548 549 # only update the individual ones if we un check the flag
549 550 _form = UserPermissionsForm(
551 self.request.translate,
550 552 [x[0] for x in c.repo_create_choices],
551 553 [x[0] for x in c.repo_create_on_write_choices],
552 554 [x[0] for x in c.repo_group_create_choices],
@@ -914,6 +916,11 b' class UsersView(UserAppView):'
914 916 email = self.request.POST.get('new_email')
915 917 user_data = c.user.get_api_data()
916 918 try:
919
920 form = UserExtraEmailForm(self.request.translate)()
921 data = form.to_python({'email': email})
922 email = data['email']
923
917 924 UserModel().add_extra_email(c.user.user_id, email)
918 925 audit_logger.store_web(
919 926 'user.edit.email.add',
@@ -1009,6 +1016,10 b' class UsersView(UserAppView):'
1009 1016 user_data = c.user.get_api_data()
1010 1017 for ip in ip_list:
1011 1018 try:
1019 form = UserExtraIpForm(self.request.translate)()
1020 data = form.to_python({'ip': ip})
1021 ip = data['ip']
1022
1012 1023 user_model.add_extra_ip(c.user.user_id, ip, desc)
1013 1024 audit_logger.store_web(
1014 1025 'user.edit.ip.add',
@@ -24,6 +24,7 b' import uuid'
24 24 from pyramid.view import view_config
25 25 from pyramid.httpexceptions import HTTPBadRequest, HTTPForbidden, HTTPBadGateway
26 26
27 from rhodecode.apps._base import BaseAppView
27 28 from rhodecode.lib.channelstream import (
28 29 channelstream_request,
29 30 ChannelstreamConnectionException,
@@ -34,28 +35,28 b' from rhodecode.lib.channelstream import '
34 35 parse_channels_info,
35 36 update_history_from_logs,
36 37 STATE_PUBLIC_KEYS)
38
37 39 from rhodecode.lib.auth import NotAnonymous
38 40
39 41 log = logging.getLogger(__name__)
40 42
41 43
42 class ChannelstreamView(object):
43 def __init__(self, context, request):
44 self.context = context
45 self.request = request
44 class ChannelstreamView(BaseAppView):
46 45
47 # Some of the decorators rely on this attribute to be present
48 # on the class of the decorated method.
49 self._rhodecode_user = request.user
50 registry = request.registry
51 self.channelstream_config = registry.rhodecode_plugins['channelstream']
46 def load_default_context(self):
47 c = self._get_local_tmpl_context()
48 self.channelstream_config = \
49 self.request.registry.rhodecode_plugins['channelstream']
52 50 if not self.channelstream_config.get('enabled'):
53 51 log.error('Channelstream plugin is disabled')
54 52 raise HTTPBadRequest()
55 53
54 return c
55
56 56 @NotAnonymous()
57 @view_config(route_name='channelstream_connect', renderer='json')
57 @view_config(route_name='channelstream_connect', renderer='json_ext')
58 58 def connect(self):
59 self.load_default_context()
59 60 """ handle authorization of users trying to connect """
60 61 try:
61 62 json_body = self.request.json_body
@@ -122,9 +123,10 b' class ChannelstreamView(object):'
122 123 return connect_result
123 124
124 125 @NotAnonymous()
125 @view_config(route_name='channelstream_subscribe', renderer='json')
126 @view_config(route_name='channelstream_subscribe', renderer='json_ext')
126 127 def subscribe(self):
127 128 """ can be used to subscribe specific connection to other channels """
129 self.load_default_context()
128 130 try:
129 131 json_body = self.request.json_body
130 132 except Exception:
@@ -31,7 +31,7 b' log = logging.getLogger(__name__)'
31 31 class DebugStyleView(BaseAppView):
32 32 def load_default_context(self):
33 33 c = self._get_local_tmpl_context()
34 self._register_global_c(c)
34
35 35 return c
36 36
37 37 @view_config(
@@ -67,7 +67,7 b' class GistView(BaseAppView):'
67 67 (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users"))
68 68 ]
69 69
70 self._register_global_c(c)
70
71 71 return c
72 72
73 73 @LoginRequired()
@@ -66,7 +66,7 b' class TestGotoSwitcherData(TestControlle'
66 66 ]
67 67
68 68 @pytest.fixture(autouse=True, scope='class')
69 def prepare(self, request, pylonsapp):
69 def prepare(self, request, baseapp):
70 70 for repo_and_group in self.required_repos_with_groups:
71 71 # create structure of groups and return the last group
72 72
@@ -46,7 +46,7 b' class HomeView(BaseAppView):'
46 46 def load_default_context(self):
47 47 c = self._get_local_tmpl_context()
48 48 c.user = c.auth_user.get_instance()
49 self._register_global_c(c)
49
50 50 return c
51 51
52 52 @LoginRequired()
@@ -47,7 +47,7 b' class JournalView(BaseAppView):'
47 47
48 48 def load_default_context(self):
49 49 c = self._get_local_tmpl_context(include_app_defaults=True)
50 self._register_global_c(c)
50
51 51 self._load_defaults(c.rhodecode_name)
52 52
53 53 # TODO(marcink): what is this, why we need a global register ?
@@ -146,7 +146,8 b' class JournalView(BaseAppView):'
146 146 user = AttributeDict({'short_contact': entry.username,
147 147 'email': '',
148 148 'full_contact': ''})
149 action, action_extra, ico = h.action_parser(entry, feed=True)
149 action, action_extra, ico = h.action_parser(
150 self.request, entry, feed=True)
150 151 title = "%s - %s %s" % (user.short_contact, action(),
151 152 entry.repository.repo_name)
152 153 desc = action_extra()
@@ -191,7 +192,8 b' class JournalView(BaseAppView):'
191 192 user = AttributeDict({'short_contact': entry.username,
192 193 'email': '',
193 194 'full_contact': ''})
194 action, action_extra, ico = h.action_parser(entry, feed=True)
195 action, action_extra, ico = h.action_parser(
196 self.request, entry, feed=True)
195 197 title = "%s - %s %s" % (user.short_contact, action(),
196 198 entry.repository.repo_name)
197 199 desc = action_extra()
@@ -30,7 +30,6 b' from rhodecode.tests.fixture import Fixt'
30 30 from rhodecode.lib.auth import check_password
31 31 from rhodecode.lib import helpers as h
32 32 from rhodecode.model.auth_token import AuthTokenModel
33 from rhodecode.model import validators
34 33 from rhodecode.model.db import User, Notification, UserApiKeys
35 34 from rhodecode.model.meta import Session
36 35
@@ -234,7 +233,7 b' class TestLoginController(object):'
234 233 )
235 234
236 235 assertr = response.assert_response()
237 msg = validators.ValidUsername()._messages['username_exists']
236 msg = '???'
238 237 msg = msg % {'username': uname}
239 238 assertr.element_contains('#username+.error-message', msg)
240 239
@@ -252,7 +251,7 b' class TestLoginController(object):'
252 251 )
253 252
254 253 assertr = response.assert_response()
255 msg = validators.UniqSystemEmail()()._messages['email_taken']
254 msg = '???'
256 255 assertr.element_contains('#email+.error-message', msg)
257 256
258 257 def test_register_err_same_email_case_sensitive(self):
@@ -268,7 +267,7 b' class TestLoginController(object):'
268 267 }
269 268 )
270 269 assertr = response.assert_response()
271 msg = validators.UniqSystemEmail()()._messages['email_taken']
270 msg = '???'
272 271 assertr.element_contains('#email+.error-message', msg)
273 272
274 273 def test_register_err_wrong_data(self):
@@ -322,7 +321,7 b' class TestLoginController(object):'
322 321 )
323 322
324 323 assertr = response.assert_response()
325 msg = validators.ValidUsername()._messages['username_exists']
324 msg = '???'
326 325 msg = msg % {'username': usr}
327 326 assertr.element_contains('#username+.error-message', msg)
328 327
@@ -339,7 +338,7 b' class TestLoginController(object):'
339 338 }
340 339 )
341 340
342 msg = validators.ValidPassword()._messages['invalid_password']
341 msg = '???'
343 342 response.mustcontain(msg)
344 343
345 344 def test_register_password_mismatch(self):
@@ -354,7 +353,7 b' class TestLoginController(object):'
354 353 'lastname': 'test'
355 354 }
356 355 )
357 msg = validators.ValidPasswordsMatch()._messages['password_mismatch']
356 msg = '???'
358 357 response.mustcontain(msg)
359 358
360 359 def test_register_ok(self):
@@ -113,7 +113,7 b' class LoginView(BaseAppView):'
113 113 def load_default_context(self):
114 114 c = self._get_local_tmpl_context()
115 115 c.came_from = get_came_from(self.request)
116 self._register_global_c(c)
116
117 117 return c
118 118
119 119 def _get_captcha_data(self):
@@ -157,7 +157,7 b' class LoginView(BaseAppView):'
157 157 def login_post(self):
158 158 c = self.load_default_context()
159 159
160 login_form = LoginForm()()
160 login_form = LoginForm(self.request.translate)()
161 161
162 162 try:
163 163 self.session.invalidate()
@@ -182,11 +182,10 b' class LoginView(BaseAppView):'
182 182 defaults = errors.value
183 183 # remove password from filling in form again
184 184 defaults.pop('password', None)
185 render_ctx = self._get_template_context(c)
186 render_ctx.update({
185 render_ctx = {
187 186 'errors': errors.error_dict,
188 187 'defaults': defaults,
189 })
188 }
190 189
191 190 audit_user = audit_logger.UserWrap(
192 191 username=self.request.POST.get('username'),
@@ -195,7 +194,7 b' class LoginView(BaseAppView):'
195 194 audit_logger.store_web(
196 195 'user.login.failure', action_data=action_data,
197 196 user=audit_user, commit=True)
198 return render_ctx
197 return self._get_template_context(c, **render_ctx)
199 198
200 199 except UserCreationError as e:
201 200 # headers auth or other auth functions that create users on
@@ -255,7 +254,7 b' class LoginView(BaseAppView):'
255 254 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
256 255 .AuthUser().permissions['global']
257 256
258 register_form = RegisterForm()()
257 register_form = RegisterForm(self.request.translate)()
259 258 try:
260 259
261 260 form_result = register_form.to_python(self.request.POST)
@@ -324,7 +323,7 b' class LoginView(BaseAppView):'
324 323 queue='error')
325 324 return HTTPFound(self.request.route_path('reset_password'))
326 325
327 password_reset_form = PasswordResetForm()()
326 password_reset_form = PasswordResetForm(self.request.translate)()
328 327 try:
329 328 form_result = password_reset_form.to_python(
330 329 self.request.POST)
@@ -198,8 +198,6 b' class TestMyAccountEdit(TestController):'
198 198 params=params)
199 199
200 200 response.mustcontain('An email address must contain a single @')
201 from rhodecode.model import validators
202 msg = validators.ValidUsername(
203 edit=False, old_data={})._messages['username_exists']
201 msg = '???'
204 202 msg = h.html_escape(msg % {'username': 'test_admin'})
205 203 response.mustcontain(u"%s" % msg)
@@ -42,7 +42,7 b' from rhodecode.model.comment import Comm'
42 42 from rhodecode.model.db import (
43 43 Repository, UserEmailMap, UserApiKeys, UserFollowing, joinedload,
44 44 PullRequest)
45 from rhodecode.model.forms import UserForm
45 from rhodecode.model.forms import UserForm, UserExtraEmailForm
46 46 from rhodecode.model.meta import Session
47 47 from rhodecode.model.pull_request import PullRequestModel
48 48 from rhodecode.model.scm import RepoList
@@ -64,7 +64,7 b' class MyAccountView(BaseAppView, DataGri'
64 64 c = self._get_local_tmpl_context()
65 65 c.user = c.auth_user.get_instance()
66 66 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
67 self._register_global_c(c)
67
68 68 return c
69 69
70 70 @LoginRequired()
@@ -245,6 +245,10 b' class MyAccountView(BaseAppView, DataGri'
245 245 email = self.request.POST.get('new_email')
246 246
247 247 try:
248 form = UserExtraEmailForm(self.request.translate)()
249 data = form.to_python({'email': email})
250 email = data['email']
251
248 252 UserModel().add_extra_email(c.user.user_id, email)
249 253 audit_logger.store_web(
250 254 'user.edit.email.add', action_data={
@@ -442,7 +446,7 b' class MyAccountView(BaseAppView, DataGri'
442 446 c.extern_type = c.user.extern_type
443 447 c.extern_name = c.user.extern_name
444 448
445 _form = UserForm(edit=True,
449 _form = UserForm(self.request.translate, edit=True,
446 450 old_data={'user_id': self._rhodecode_user.user_id,
447 451 'email': self._rhodecode_user.email})()
448 452 form_result = {}
@@ -43,7 +43,7 b' class MyAccountNotificationsView(BaseApp'
43 43 def load_default_context(self):
44 44 c = self._get_local_tmpl_context()
45 45 c.user = c.auth_user.get_instance()
46 self._register_global_c(c)
46
47 47 return c
48 48
49 49 def _has_permissions(self, notification):
@@ -44,7 +44,7 b' class MyAccountSshKeysView(BaseAppView, '
44 44
45 45 c.ssh_enabled = self.request.registry.settings.get(
46 46 'ssh.generate_authorized_keyfile')
47 self._register_global_c(c)
47
48 48 return c
49 49
50 50 @LoginRequired()
@@ -36,7 +36,7 b' def admin_routes(config):'
36 36 def includeme(config):
37 37
38 38 config.include(admin_routes, route_prefix=ADMIN_PREFIX + '/ops')
39 # make OLD entries from pylons work
39 # make OLD entries from <4.10.0 work
40 40 config.add_route(
41 41 name='ops_ping_legacy', pattern=ADMIN_PREFIX + '/ping')
42 42 config.add_route(
@@ -35,7 +35,7 b' class OpsView(BaseAppView):'
35 35 def load_default_context(self):
36 36 c = self._get_local_tmpl_context()
37 37 c.user = c.auth_user.get_instance()
38 self._register_global_c(c)
38
39 39 return c
40 40
41 41 @view_config(
@@ -37,7 +37,7 b' log = logging.getLogger(__name__)'
37 37 class RepoGroupSettingsView(RepoGroupAppView):
38 38 def load_default_context(self):
39 39 c = self._get_local_tmpl_context()
40 self._register_global_c(c)
40
41 41 return c
42 42
43 43 @LoginRequired()
@@ -38,7 +38,7 b' log = logging.getLogger(__name__)'
38 38 class RepoGroupPermissionsView(RepoGroupAppView):
39 39 def load_default_context(self):
40 40 c = self._get_local_tmpl_context()
41 self._register_global_c(c)
41
42 42 return c
43 43
44 44 @LoginRequired()
@@ -65,7 +65,7 b' class RepoGroupPermissionsView(RepoGroup'
65 65 c.repo_group = self.db_repo_group
66 66
67 67 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
68 form = RepoGroupPermsForm(valid_recursive_choices)()\
68 form = RepoGroupPermsForm(self.request.translate, valid_recursive_choices)()\
69 69 .to_python(self.request.POST)
70 70
71 71 if not c.rhodecode_user.is_admin:
@@ -73,7 +73,7 b' class RepoGroupSettingsView(RepoGroupApp'
73 73 c.repo_groups_choices.append(parent_group.group_id)
74 74 c.repo_groups.append(RepoGroup._generate_choice(parent_group))
75 75
76 self._register_global_c(c)
76
77 77 return c
78 78
79 79 def _can_create_repo_group(self, parent_group_id=None):
@@ -47,7 +47,7 b' def route_path(name, params=None, **kwar'
47 47 class TestRepoCommitCommentsView(TestController):
48 48
49 49 @pytest.fixture(autouse=True)
50 def prepare(self, request, pylonsapp):
50 def prepare(self, request, baseapp):
51 51 for x in ChangesetComment.query().all():
52 52 Session().delete(x)
53 53 Session().commit()
@@ -34,7 +34,7 b' class AuditLogsView(RepoAppView):'
34 34 def load_default_context(self):
35 35 c = self._get_local_tmpl_context()
36 36
37 self._register_global_c(c)
37
38 38 return c
39 39
40 40 @LoginRequired()
@@ -37,7 +37,7 b' class RepoCachesView(RepoAppView):'
37 37 def load_default_context(self):
38 38 c = self._get_local_tmpl_context()
39 39
40 self._register_global_c(c)
40
41 41 return c
42 42
43 43 @LoginRequired()
@@ -159,7 +159,7 b' class RepoChangelogView(RepoAppView):'
159 159 c = self._get_local_tmpl_context(include_app_defaults=True)
160 160
161 161 c.rhodecode_repo = self.rhodecode_vcs_repo
162 self._register_global_c(c)
162
163 163 return c
164 164
165 165 def _get_preload_attrs(self):
@@ -34,7 +34,7 b' log = logging.getLogger(__name__)'
34 34 class RepoChecksView(BaseAppView):
35 35 def load_default_context(self):
36 36 c = self._get_local_tmpl_context()
37 self._register_global_c(c)
37
38 38 return c
39 39
40 40 @NotAnonymous()
@@ -150,7 +150,6 b' class RepoCommitsView(RepoAppView):'
150 150 c = self._get_local_tmpl_context(include_app_defaults=True)
151 151 c.rhodecode_repo = self.rhodecode_vcs_repo
152 152
153 self._register_global_c(c)
154 153 return c
155 154
156 155 def _commit(self, commit_id_range, method):
@@ -47,7 +47,7 b' class RepoCompareView(RepoAppView):'
47 47
48 48 c.rhodecode_repo = self.rhodecode_vcs_repo
49 49
50 self._register_global_c(c)
50
51 51 return c
52 52
53 53 def _get_commit_or_redirect(
@@ -42,7 +42,7 b' class RepoFeedView(RepoAppView):'
42 42 def load_default_context(self):
43 43 c = self._get_local_tmpl_context()
44 44
45 self._register_global_c(c)
45
46 46 self._load_defaults()
47 47 return c
48 48
@@ -83,7 +83,7 b' class RepoFilesView(RepoAppView):'
83 83
84 84 c.rhodecode_repo = self.rhodecode_vcs_repo
85 85
86 self._register_global_c(c)
86
87 87 return c
88 88
89 89 def _ensure_not_locked(self):
@@ -57,7 +57,7 b' class RepoForksView(RepoAppView, DataGri'
57 57 c.landing_revs_choices = choices
58 58 c.personal_repo_group = c.rhodecode_user.personal_repo_group
59 59
60 self._register_global_c(c)
60
61 61 return c
62 62
63 63 @LoginRequired()
@@ -209,7 +209,7 b' class RepoForksView(RepoAppView, DataGri'
209 209 _ = self.request.translate
210 210 c = self.load_default_context()
211 211
212 _form = RepoForkForm(old_data={'repo_type': self.db_repo.repo_type},
212 _form = RepoForkForm(self.request.translate, old_data={'repo_type': self.db_repo.repo_type},
213 213 repo_groups=c.repo_groups_choices,
214 214 landing_revs=c.landing_revs_choices)()
215 215 post_data = dict(self.request.POST)
@@ -33,7 +33,7 b' class RepoMaintenanceView(RepoAppView):'
33 33 def load_default_context(self):
34 34 c = self._get_local_tmpl_context()
35 35
36 self._register_global_c(c)
36
37 37 return c
38 38
39 39 @LoginRequired()
@@ -40,7 +40,7 b' class RepoSettingsPermissionsView(RepoAp'
40 40 def load_default_context(self):
41 41 c = self._get_local_tmpl_context()
42 42
43 self._register_global_c(c)
43
44 44 return c
45 45
46 46 @LoginRequired()
@@ -68,7 +68,7 b' class RepoSettingsPermissionsView(RepoAp'
68 68 # default user permissions, prevents submission of FAKE post data
69 69 # into the form for private repos
70 70 data['repo_private'] = self.db_repo.private
71 form = RepoPermsForm()().to_python(data)
71 form = RepoPermsForm(self.request.translate)().to_python(data)
72 72 changes = RepoModel().update_permissions(
73 73 self.db_repo_name, form['perm_additions'], form['perm_updates'],
74 74 form['perm_deletions'])
@@ -60,7 +60,7 b' class RepoPullRequestsView(RepoAppView, '
60 60 c = self._get_local_tmpl_context(include_app_defaults=True)
61 61 c.REVIEW_STATUS_APPROVED = ChangesetStatus.STATUS_APPROVED
62 62 c.REVIEW_STATUS_REJECTED = ChangesetStatus.STATUS_REJECTED
63 self._register_global_c(c)
63
64 64 return c
65 65
66 66 def _get_pull_requests_list(
@@ -749,7 +749,9 b' class RepoPullRequestsView(RepoAppView, '
749 749 controls = peppercorn.parse(self.request.POST.items())
750 750
751 751 try:
752 _form = PullRequestForm(self.db_repo.repo_id)().to_python(controls)
752 form = PullRequestForm(
753 self.request.translate, self.db_repo.repo_id)()
754 _form = form.to_python(controls)
753 755 except formencode.Invalid as errors:
754 756 if errors.error_dict.get('revisions'):
755 757 msg = 'Revisions: %s' % errors.error_dict['revisions']
@@ -32,8 +32,6 b' log = logging.getLogger(__name__)'
32 32 class RepoReviewRulesView(RepoAppView):
33 33 def load_default_context(self):
34 34 c = self._get_local_tmpl_context()
35
36 self._register_global_c(c)
37 35 return c
38 36
39 37 @LoginRequired()
@@ -54,6 +52,7 b' class RepoReviewRulesView(RepoAppView):'
54 52 route_name='repo_default_reviewers_data', request_method='GET',
55 53 renderer='json_ext')
56 54 def repo_default_reviewers_data(self):
55 self.load_default_context()
57 56 review_data = get_default_reviewers_data(
58 57 self.db_repo.user, None, None, None, None)
59 58 return review_data
@@ -71,7 +71,7 b' class RepoSettingsView(RepoAppView):'
71 71 c.repo_fields = RepositoryField.query()\
72 72 .filter(RepositoryField.repository == self.db_repo).all()
73 73
74 self._register_global_c(c)
74
75 75 return c
76 76
77 77 def _get_schema(self, c, old_values=None):
@@ -44,7 +44,7 b' class RepoSettingsView(RepoAppView):'
44 44 def load_default_context(self):
45 45 c = self._get_local_tmpl_context()
46 46
47 self._register_global_c(c)
47
48 48 return c
49 49
50 50 @LoginRequired()
@@ -43,7 +43,7 b' class RepoSettingsFieldsView(RepoAppView'
43 43 def load_default_context(self):
44 44 c = self._get_local_tmpl_context()
45 45
46 self._register_global_c(c)
46
47 47 return c
48 48
49 49 @LoginRequired()
@@ -70,7 +70,8 b' class RepoSettingsFieldsView(RepoAppView'
70 70 _ = self.request.translate
71 71
72 72 try:
73 form_result = RepoFieldForm()().to_python(dict(self.request.POST))
73 form = RepoFieldForm(self.request.translate)()
74 form_result = form.to_python(dict(self.request.POST))
74 75 RepoModel().add_repo_field(
75 76 self.db_repo_name,
76 77 form_result['new_field_key'],
@@ -40,7 +40,7 b' class RepoSettingsIssueTrackersView(Repo'
40 40 def load_default_context(self):
41 41 c = self._get_local_tmpl_context()
42 42
43 self._register_global_c(c)
43
44 44 return c
45 45
46 46 @LoginRequired()
@@ -118,7 +118,7 b' class RepoSettingsIssueTrackersView(Repo'
118 118 Session().commit()
119 119
120 120 try:
121 form = IssueTrackerPatternsForm()().to_python(self.request.POST)
121 form = IssueTrackerPatternsForm(self.request.translate)().to_python(self.request.POST)
122 122 except formencode.Invalid as errors:
123 123 log.exception('Failed to add new pattern')
124 124 error = errors
@@ -36,7 +36,7 b' class RepoSettingsRemoteView(RepoAppView'
36 36 def load_default_context(self):
37 37 c = self._get_local_tmpl_context()
38 38
39 self._register_global_c(c)
39
40 40 return c
41 41
42 42 @LoginRequired()
@@ -43,7 +43,7 b' class RepoSettingsVcsView(RepoAppView):'
43 43 def load_default_context(self):
44 44 c = self._get_local_tmpl_context()
45 45
46 self._register_global_c(c)
46
47 47 return c
48 48
49 49 def _vcs_form_defaults(self, repo_name):
@@ -117,7 +117,7 b' class RepoSettingsVcsView(RepoAppView):'
117 117 defaults = self._vcs_form_defaults(self.db_repo_name)
118 118 c.inherit_global_settings = defaults['inherit_global_settings']
119 119
120 application_form = RepoVcsSettingsForm(self.db_repo_name)()
120 application_form = RepoVcsSettingsForm(self.request.translate, self.db_repo_name)()
121 121 try:
122 122 form_result = application_form.to_python(dict(self.request.POST))
123 123 except formencode.Invalid as errors:
@@ -35,7 +35,7 b' class StripView(RepoAppView):'
35 35 def load_default_context(self):
36 36 c = self._get_local_tmpl_context()
37 37
38 self._register_global_c(c)
38
39 39 return c
40 40
41 41 @LoginRequired()
@@ -53,7 +53,7 b' class RepoSummaryView(RepoAppView):'
53 53 if not c.repository_requirements_missing:
54 54 c.rhodecode_repo = self.rhodecode_vcs_repo
55 55
56 self._register_global_c(c)
56
57 57 return c
58 58
59 59 def _get_readme_data(self, db_repo, default_renderer):
@@ -103,7 +103,7 b' def search(request, tmpl_context, repo_n'
103 103 class SearchView(BaseAppView):
104 104 def load_default_context(self):
105 105 c = self._get_local_tmpl_context()
106 self._register_global_c(c)
106
107 107 return c
108 108
109 109 @LoginRequired()
@@ -119,7 +119,7 b' class SearchView(BaseAppView):'
119 119 class SearchRepoView(RepoAppView):
120 120 def load_default_context(self):
121 121 c = self._get_local_tmpl_context()
122 self._register_global_c(c)
122
123 123 return c
124 124
125 125 @LoginRequired()
@@ -56,7 +56,7 b' class UserGroupsView(UserGroupAppView):'
56 56 PermissionModel().set_global_permission_choices(
57 57 c, gettext_translator=self.request.translate)
58 58
59 self._register_global_c(c)
59
60 60 return c
61 61
62 62 def _get_perms_summary(self, user_group_id):
@@ -94,6 +94,7 b' class UserGroupsView(UserGroupAppView):'
94 94 """
95 95 Return members of given user group
96 96 """
97 self.load_default_context()
97 98 user_group = self.db_user_group
98 99 group_members_obj = sorted((x.user for x in user_group.members),
99 100 key=lambda u: u.username.lower())
@@ -173,7 +174,8 b' class UserGroupsView(UserGroupAppView):'
173 174 c.active = 'settings'
174 175
175 176 users_group_form = UserGroupForm(
176 edit=True, old_data=c.user_group.get_dict(), allow_disabled=True)()
177 self.request.translate, edit=True,
178 old_data=c.user_group.get_dict(), allow_disabled=True)()
177 179
178 180 old_values = c.user_group.get_api_data()
179 181 user_group_name = self.request.POST.get('users_group_name')
@@ -346,7 +348,7 b' class UserGroupsView(UserGroupAppView):'
346 348 user_group_id = user_group.users_group_id
347 349 c = self.load_default_context()
348 350 c.user_group = user_group
349 form = UserGroupPermsForm()().to_python(self.request.POST)
351 form = UserGroupPermsForm(self.request.translate)().to_python(self.request.POST)
350 352
351 353 if not self._rhodecode_user.is_admin:
352 354 if self._revoke_perms_on_yourself(form):
@@ -435,6 +437,7 b' class UserGroupsView(UserGroupAppView):'
435 437 if not inherit_perms:
436 438 # only update the individual ones if we un check the flag
437 439 _form = UserPermissionsForm(
440 self.request.translate,
438 441 [x[0] for x in c.repo_create_choices],
439 442 [x[0] for x in c.repo_create_on_write_choices],
440 443 [x[0] for x in c.repo_group_create_choices],
@@ -252,29 +252,6 b' class RhodeCodeAuthPluginBase(object):'
252 252 del settings_copy[k]
253 253 return settings_copy
254 254
255 @property
256 def validators(self):
257 """
258 Exposes RhodeCode validators modules
259 """
260 # this is a hack to overcome issues with pylons threadlocals and
261 # translator object _() not being registered properly.
262 class LazyCaller(object):
263 def __init__(self, name):
264 self.validator_name = name
265
266 def __call__(self, *args, **kwargs):
267 from rhodecode.model import validators as v
268 obj = getattr(v, self.validator_name)
269 # log.debug('Initializing lazy formencode object: %s', obj)
270 return LazyFormencode(obj, *args, **kwargs)
271
272 class ProxyGet(object):
273 def __getattribute__(self, name):
274 return LazyCaller(name)
275
276 return ProxyGet()
277
278 255 @hybrid_property
279 256 def name(self):
280 257 """
@@ -26,25 +26,24 b' from pyramid.httpexceptions import HTTPF'
26 26 from pyramid.renderers import render
27 27 from pyramid.response import Response
28 28
29 from rhodecode.apps._base import BaseAppView
29 30 from rhodecode.authentication.base import (
30 31 get_auth_cache_manager, get_perms_cache_manager, get_authn_registry)
31 from rhodecode.lib import auth
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
32 from rhodecode.lib.auth import (
33 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
33 34 from rhodecode.model.forms import AuthSettingsForm
34 35 from rhodecode.model.meta import Session
35 36 from rhodecode.model.settings import SettingsModel
36 from rhodecode.translation import _
37 37
38 38 log = logging.getLogger(__name__)
39 39
40 40
41 class AuthnPluginViewBase(object):
41 class AuthnPluginViewBase(BaseAppView):
42 42
43 def __init__(self, context, request):
44 self.request = request
45 self.context = context
46 self.plugin = context.plugin
47 self._rhodecode_user = request.user
43 def load_default_context(self):
44 c = self._get_local_tmpl_context()
45 self.plugin = self.context.plugin
46 return c
48 47
49 48 @LoginRequired()
50 49 @HasPermissionAllDecorator('hg.admin')
@@ -52,6 +51,7 b' class AuthnPluginViewBase(object):'
52 51 """
53 52 View that displays the plugin settings as a form.
54 53 """
54 c = self.load_default_context()
55 55 defaults = defaults or {}
56 56 errors = errors or {}
57 57 schema = self.plugin.get_settings_schema()
@@ -70,15 +70,17 b' class AuthnPluginViewBase(object):'
70 70 'resource': self.context,
71 71 }
72 72
73 return template_context
73 return self._get_template_context(c, **template_context)
74 74
75 75 @LoginRequired()
76 76 @HasPermissionAllDecorator('hg.admin')
77 @auth.CSRFRequired()
77 @CSRFRequired()
78 78 def settings_post(self):
79 79 """
80 80 View that validates and stores the plugin settings.
81 81 """
82 _ = self.request.translate
83 self.load_default_context()
82 84 schema = self.plugin.get_settings_schema()
83 85 data = self.request.params
84 86
@@ -107,23 +109,16 b' class AuthnPluginViewBase(object):'
107 109 return HTTPFound(redirect_to)
108 110
109 111
110 # TODO: Ongoing migration in these views.
111 # - Maybe we should also use a colander schema for these views.
112 class AuthSettingsView(object):
113 def __init__(self, context, request):
114 self.context = context
115 self.request = request
116
117 # TODO: Move this into a utility function. It is needed in all view
118 # classes during migration. Maybe a mixin?
119
120 # Some of the decorators rely on this attribute to be present on the
121 # class of the decorated method.
122 self._rhodecode_user = request.user
112 class AuthSettingsView(BaseAppView):
113 def load_default_context(self):
114 c = self._get_local_tmpl_context()
115 return c
123 116
124 117 @LoginRequired()
125 118 @HasPermissionAllDecorator('hg.admin')
126 119 def index(self, defaults=None, errors=None, prefix_error=False):
120 c = self.load_default_context()
121
127 122 defaults = defaults or {}
128 123 authn_registry = get_authn_registry(self.request.registry)
129 124 enabled_plugins = SettingsModel().get_auth_plugins()
@@ -135,8 +130,8 b' class AuthSettingsView(object):'
135 130 'enabled_plugins': enabled_plugins,
136 131 }
137 132 html = render('rhodecode:templates/admin/auth/auth_settings.mako',
138 template_context,
139 request=self.request)
133 self._get_template_context(c, **template_context),
134 self.request)
140 135
141 136 # Create form default values and fill the form.
142 137 form_defaults = {
@@ -155,11 +150,12 b' class AuthSettingsView(object):'
155 150
156 151 @LoginRequired()
157 152 @HasPermissionAllDecorator('hg.admin')
158 @auth.CSRFRequired()
153 @CSRFRequired()
159 154 def auth_settings(self):
155 _ = self.request.translate
160 156 try:
161 form = AuthSettingsForm()()
162 form_result = form.to_python(self.request.params)
157 form = AuthSettingsForm(self.request.translate)()
158 form_result = form.to_python(self.request.POST)
163 159 plugins = ','.join(form_result['auth_plugins'])
164 160 setting = SettingsModel().create_or_update_setting(
165 161 'auth_plugins', plugins)
@@ -18,127 +18,49 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 """
22 Pylons environment configuration
23 """
24 21
25 22 import os
26 23 import logging
27 24 import rhodecode
28 25
29 from mako.lookup import TemplateLookup
30 from pyramid.settings import asbool
31
32 26 # ------------------------------------------------------------------------------
33 27 # CELERY magic until refactor - issue #4163 - import order matters here:
34 from rhodecode.lib import celerypylons # this must be first, celerypylons
28 #from rhodecode.lib import celerypylons # this must be first, celerypylons
35 29 # sets config settings upon import
36 30
37 31 import rhodecode.integrations # any modules using celery task
38 32 # decorators should be added afterwards:
39 33 # ------------------------------------------------------------------------------
40 34
41 from rhodecode.lib import app_globals
42 35 from rhodecode.config import utils
43 from rhodecode.config.routing import make_map
44 36
45 from rhodecode.lib import helpers
46 from rhodecode.lib.utils import (
47 make_db_config, set_rhodecode_config, load_rcextensions)
48 from rhodecode.lib.utils2 import str2bool, aslist
37 from rhodecode.lib.utils import load_rcextensions
38 from rhodecode.lib.utils2 import str2bool
49 39 from rhodecode.lib.vcs import connect_vcs, start_vcs_server
50 40
51 41 log = logging.getLogger(__name__)
52 42
53 43
54 def load_environment(global_conf, app_conf, initial=False,
55 test_env=None, test_index=None):
56 """
57 Configure the Pylons environment via the ``pylons.config``
58 object
59 """
60 from pylons.configuration import PylonsConfig
61 from pylons.error import handle_mako_error
62
63 config = PylonsConfig()
64
65
66 # Pylons paths
67 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
68 paths = {
69 'root': root,
70 'controllers': os.path.join(root, 'controllers'),
71 'static_files': os.path.join(root, 'public'),
72 'templates': [os.path.join(root, 'templates')],
73 }
74
75 # Initialize config with the basic options
76 config.init_app(global_conf, app_conf, package='rhodecode', paths=paths)
77
78 # store some globals into rhodecode
79 rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery'))
80 rhodecode.CELERY_EAGER = str2bool(
81 config['app_conf'].get('celery.always.eager'))
82
83 config['routes.map'] = make_map(config)
84
85 config['pylons.app_globals'] = app_globals.Globals(config)
86 config['pylons.h'] = helpers
87 rhodecode.CONFIG = config
88
89 load_rcextensions(root_path=config['here'])
90
91 # Setup cache object as early as possible
92 import pylons
93 pylons.cache._push_object(config['pylons.app_globals'].cache)
94
95 # Create the Mako TemplateLookup, with the default auto-escaping
96 config['pylons.app_globals'].mako_lookup = TemplateLookup(
97 directories=paths['templates'],
98 error_handler=handle_mako_error,
99 module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
100 input_encoding='utf-8', default_filters=['escape'],
101 imports=['from webhelpers.html import escape'])
102
103 # sets the c attribute access when don't existing attribute are accessed
104 config['pylons.strict_tmpl_context'] = True
105
106 # configure channelstream
107 config['channelstream_config'] = {
108 'enabled': asbool(config.get('channelstream.enabled', False)),
109 'server': config.get('channelstream.server'),
110 'secret': config.get('channelstream.secret')
111 }
112
113 db_cfg = make_db_config(clear_session=True)
114
115 repos_path = list(db_cfg.items('paths'))[0][1]
116 config['base_path'] = repos_path
117
118 # store db config also in main global CONFIG
119 set_rhodecode_config(config)
120
121 # configure instance id
122 utils.set_instance_id(config)
123
124 # CONFIGURATION OPTIONS HERE (note: all config options will override
125 # any Pylons config options)
126
127 # store config reference into our module to skip import magic of pylons
128 rhodecode.CONFIG.update(config)
129
130 return config
131
132
133 44 def load_pyramid_environment(global_config, settings):
134 45 # Some parts of the code expect a merge of global and app settings.
135 46 settings_merged = global_config.copy()
136 47 settings_merged.update(settings)
137 48
138 # Store the settings to make them available to other modules.
139 rhodecode.PYRAMID_SETTINGS = settings_merged
140 # NOTE(marcink): needs to be enabled after full port to pyramid
141 # rhodecode.CONFIG = config
49 # TODO(marcink): probably not required anymore
50 # configure channelstream,
51 settings_merged['channelstream_config'] = {
52 'enabled': str2bool(settings_merged.get('channelstream.enabled', False)),
53 'server': settings_merged.get('channelstream.server'),
54 'secret': settings_merged.get('channelstream.secret')
55 }
56
57
58 # TODO(marcink): celery
59 # # store some globals into rhodecode
60 # rhodecode.CELERY_ENABLED = str2bool(config['app_conf'].get('use_celery'))
61 # rhodecode.CELERY_EAGER = str2bool(
62 # config['app_conf'].get('celery.always.eager'))
63
142 64
143 65 # If this is a test run we prepare the test environment like
144 66 # creating a test database, test search index and test repositories.
@@ -152,6 +74,11 b' def load_pyramid_environment(global_conf'
152 74 # Initialize the database connection.
153 75 utils.initialize_database(settings_merged)
154 76
77 # TODO(marcink): base_path handling ?
78 # repos_path = list(db_cfg.items('paths'))[0][1]
79
80 load_rcextensions(root_path=settings_merged['here'])
81
155 82 # Limit backends to `vcs.backends` from configuration
156 83 for alias in rhodecode.BACKENDS.keys():
157 84 if alias not in settings['vcs.backends']:
@@ -173,5 +100,10 b' def load_pyramid_environment(global_conf'
173 100
174 101 utils.configure_vcs(settings)
175 102
103 # Store the settings to make them available to other modules.
104
105 rhodecode.PYRAMID_SETTINGS = settings_merged
106 rhodecode.CONFIG = settings_merged
107
176 108 if vcs_server_enabled:
177 109 connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))
@@ -43,10 +43,7 b''
43 43 },
44 44 "python2.7-Pygments-2.2.0": {
45 45 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
46 },
47 "python2.7-Pylons-1.0.2.rhodecode-patch1": {
48 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
49 },
46 },
50 47 "python2.7-Routes-1.13": {
51 48 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
52 49 },
@@ -80,10 +77,7 b''
80 77 },
81 78 "python2.7-amqplib-1.0.2": {
82 79 "GNU Lesser General Public License v3.0 only": "http://spdx.org/licenses/LGPL-3.0"
83 },
84 "python2.7-anyjson-0.3.3": {
85 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
86 },
80 },
87 81 "python2.7-appenlight-client-0.6.14": {
88 82 "BSD 4-clause \"Original\" or \"Old\" License": "http://spdx.org/licenses/BSD-4-Clause"
89 83 },
@@ -327,7 +321,7 b''
327 321 "Python Software Foundation License version 2": "http://spdx.org/licenses/Python-2.0",
328 322 "Zope Public License 2.0": "http://spdx.org/licenses/ZPL-2.0"
329 323 },
330 "python2.7-setuptools-scm-1.15.0": {
324 "python2.7-setuptools-scm-1.15.6": {
331 325 "MIT License": "http://spdx.org/licenses/MIT"
332 326 },
333 327 "python2.7-simplegeneric-0.8.1": {
@@ -22,33 +22,26 b' import logging'
22 22 import traceback
23 23 import collections
24 24
25 from paste.registry import RegistryManager
26 25 from paste.gzipper import make_gzip_middleware
26 from pyramid.wsgi import wsgiapp
27 27 from pyramid.authorization import ACLAuthorizationPolicy
28 28 from pyramid.config import Configurator
29 29 from pyramid.settings import asbool, aslist
30 from pyramid.wsgi import wsgiapp
31 30 from pyramid.httpexceptions import (
32 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound)
31 HTTPException, HTTPError, HTTPInternalServerError, HTTPFound, HTTPNotFound)
33 32 from pyramid.events import ApplicationCreated
34 33 from pyramid.renderers import render_to_response
35 from routes.middleware import RoutesMiddleware
36 import rhodecode
37 34
38 35 from rhodecode.model import meta
39 36 from rhodecode.config import patches
40 37 from rhodecode.config import utils as config_utils
41 from rhodecode.config.routing import STATIC_FILE_PREFIX
42 from rhodecode.config.environment import (
43 load_environment, load_pyramid_environment)
38 from rhodecode.config.environment import load_pyramid_environment
44 39
40 from rhodecode.lib.middleware.vcs import VCSMiddleware
45 41 from rhodecode.lib.vcs import VCSCommunicationError
46 42 from rhodecode.lib.exceptions import VCSServerUnavailable
47 43 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
48 from rhodecode.lib.middleware.error_handling import (
49 PylonsErrorHandlingMiddleware)
50 44 from rhodecode.lib.middleware.https_fixup import HttpsFixup
51 from rhodecode.lib.middleware.vcs import VCSMiddleware
52 45 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
53 46 from rhodecode.lib.utils2 import aslist as rhodecode_aslist, AttributeDict
54 47 from rhodecode.subscribers import (
@@ -59,76 +52,17 b' from rhodecode.subscribers import ('
59 52 log = logging.getLogger(__name__)
60 53
61 54
62 # this is used to avoid avoid the route lookup overhead in routesmiddleware
63 # for certain routes which won't go to pylons to - eg. static files, debugger
64 # it is only needed for the pylons migration and can be removed once complete
65 class SkippableRoutesMiddleware(RoutesMiddleware):
66 """ Routes middleware that allows you to skip prefixes """
67
68 def __init__(self, *args, **kw):
69 self.skip_prefixes = kw.pop('skip_prefixes', [])
70 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
71
72 def __call__(self, environ, start_response):
73 for prefix in self.skip_prefixes:
74 if environ['PATH_INFO'].startswith(prefix):
75 # added to avoid the case when a missing /_static route falls
76 # through to pylons and causes an exception as pylons is
77 # expecting wsgiorg.routingargs to be set in the environ
78 # by RoutesMiddleware.
79 if 'wsgiorg.routing_args' not in environ:
80 environ['wsgiorg.routing_args'] = (None, {})
81 return self.app(environ, start_response)
82
83 return super(SkippableRoutesMiddleware, self).__call__(
84 environ, start_response)
85
86
87 def make_app(global_conf, static_files=True, **app_conf):
88 """Create a Pylons WSGI application and return it
89
90 ``global_conf``
91 The inherited configuration for this application. Normally from
92 the [DEFAULT] section of the Paste ini file.
93
94 ``app_conf``
95 The application's local configuration. Normally specified in
96 the [app:<name>] section of the Paste ini file (where <name>
97 defaults to main).
98
99 """
100 from pylons.wsgiapp import PylonsApp
101
102 # Apply compatibility patches
103 patches.kombu_1_5_1_python_2_7_11()
104 patches.inspect_getargspec()
105
106 # Configure the Pylons environment
107 config = load_environment(global_conf, app_conf)
108
109 # The Pylons WSGI app
110 app = PylonsApp(config=config)
111
112 # Establish the Registry for this application
113 app = RegistryManager(app)
114
115 app.config = config
116
117 return app
55 def is_http_error(response):
56 # error which should have traceback
57 return response.status_code > 499
118 58
119 59
120 60 def make_pyramid_app(global_config, **settings):
121 61 """
122 Constructs the WSGI application based on Pyramid and wraps the Pylons based
123 application.
62 Constructs the WSGI application based on Pyramid.
124 63
125 64 Specials:
126 65
127 * We migrate from Pylons to Pyramid. While doing this, we keep both
128 frameworks functional. This involves moving some WSGI middlewares around
129 and providing access to some data internals, so that the old code is
130 still functional.
131
132 66 * The application can also be integrated like a plugin via the call to
133 67 `includeme`. This is accompanied with the other utility functions which
134 68 are called. Changing this should be done with great care to not break
@@ -138,9 +72,11 b' def make_pyramid_app(global_config, **se'
138 72 sanitize_settings_and_apply_defaults(settings)
139 73
140 74 config = Configurator(settings=settings)
141 load_pyramid_environment(global_config, settings)
142 75
143 add_pylons_compat_data(config.registry, global_config, settings.copy())
76 # Apply compatibility patches
77 patches.inspect_getargspec()
78
79 load_pyramid_environment(global_config, settings)
144 80
145 81 # Static file view comes first
146 82 includeme_first(config)
@@ -157,54 +93,24 b' def make_pyramid_app(global_config, **se'
157 93 return pyramid_app
158 94
159 95
160 def make_not_found_view(config):
96 def not_found_view(request):
161 97 """
162 98 This creates the view which should be registered as not-found-view to
163 pyramid. Basically it contains of the old pylons app, converted to a view.
164 Additionally it is wrapped by some other middlewares.
99 pyramid.
165 100 """
166 settings = config.registry.settings
167 vcs_server_enabled = settings['vcs.server.enable']
168 101
169 # Make pylons app from unprepared settings.
170 pylons_app = make_app(
171 config.registry._pylons_compat_global_config,
172 **config.registry._pylons_compat_settings)
173 config.registry._pylons_compat_config = pylons_app.config
174
175 # Appenlight monitoring.
176 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
177 pylons_app, settings)
102 if not getattr(request, 'vcs_call', None):
103 # handle like regular case with our error_handler
104 return error_handler(HTTPNotFound(), request)
178 105
179 # The pylons app is executed inside of the pyramid 404 exception handler.
180 # Exceptions which are raised inside of it are not handled by pyramid
181 # again. Therefore we add a middleware that invokes the error handler in
182 # case of an exception or error response. This way we return proper error
183 # HTML pages in case of an error.
184 reraise = (settings.get('debugtoolbar.enabled', False) or
185 rhodecode.disable_error_handler)
186 pylons_app = PylonsErrorHandlingMiddleware(
187 pylons_app, error_handler, reraise)
106 # handle not found view as a vcs call
107 settings = request.registry.settings
108 ae_client = getattr(request, 'ae_client', None)
109 vcs_app = VCSMiddleware(
110 HTTPNotFound(), request.registry, settings,
111 appenlight_client=ae_client)
188 112
189 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find a
190 # view to handle the request. Therefore it is wrapped around the pylons
191 # app. It has to be outside of the error handling otherwise error responses
192 # from the vcsserver are converted to HTML error pages. This confuses the
193 # command line tools and the user won't get a meaningful error message.
194 if vcs_server_enabled:
195 pylons_app = VCSMiddleware(
196 pylons_app, settings, appenlight_client, registry=config.registry)
197
198 # Convert WSGI app to pyramid view and return it.
199 return wsgiapp(pylons_app)
200
201
202 def add_pylons_compat_data(registry, global_config, settings):
203 """
204 Attach data to the registry to support the Pylons integration.
205 """
206 registry._pylons_compat_global_config = global_config
207 registry._pylons_compat_settings = settings
113 return wsgiapp(vcs_app)(None, request)
208 114
209 115
210 116 def error_handler(exception, request):
@@ -220,10 +126,6 b' def error_handler(exception, request):'
220 126 elif isinstance(exception, VCSCommunicationError):
221 127 base_response = VCSServerUnavailable()
222 128
223 def is_http_error(response):
224 # error which should have traceback
225 return response.status_code > 499
226
227 129 if is_http_error(base_response):
228 130 log.exception(
229 131 'error occurred handling this request for path: %s', request.path)
@@ -366,43 +268,29 b' def includeme(config):'
366 268 for inc in includes:
367 269 config.include(inc)
368 270
369 # This is the glue which allows us to migrate in chunks. By registering the
370 # pylons based application as the "Not Found" view in Pyramid, we will
371 # fallback to the old application each time the new one does not yet know
372 # how to handle a request.
373 config.add_notfound_view(make_not_found_view(config))
374
271 # custom not found view, if our pyramid app doesn't know how to handle
272 # the request pass it to potential VCS handling ap
273 config.add_notfound_view(not_found_view)
375 274 if not settings.get('debugtoolbar.enabled', False):
376 275 # disabled debugtoolbar handle all exceptions via the error_handlers
377 276 config.add_view(error_handler, context=Exception)
378 277
278 # all errors including 403/404/50X
379 279 config.add_view(error_handler, context=HTTPError)
380 280
381 281
382 282 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
383 283 """
384 284 Apply outer WSGI middlewares around the application.
385
386 Part of this has been moved up from the Pylons layer, so that the
387 data is also available if old Pylons code is hit through an already ported
388 view.
389 285 """
390 286 settings = config.registry.settings
391 287
392 288 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
393 289 pyramid_app = HttpsFixup(pyramid_app, settings)
394 290
395 # Add RoutesMiddleware to support the pylons compatibility tween during
396 # migration to pyramid.
397
398 # TODO(marcink): remove after migration to pyramid
399 if hasattr(config.registry, '_pylons_compat_config'):
400 routes_map = config.registry._pylons_compat_config['routes.map']
401 pyramid_app = SkippableRoutesMiddleware(
402 pyramid_app, routes_map,
403 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
404
405 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
291 pyramid_app, _ae_client = wrap_in_appenlight_if_enabled(
292 pyramid_app, settings)
293 config.registry.ae_client = _ae_client
406 294
407 295 if settings['gzip_responses']:
408 296 pyramid_app = make_gzip_middleware(
@@ -518,10 +406,10 b' def _int_setting(settings, name, default'
518 406
519 407
520 408 def _bool_setting(settings, name, default):
521 input = settings.get(name, default)
522 if isinstance(input, unicode):
523 input = input.encode('utf8')
524 settings[name] = asbool(input)
409 input_val = settings.get(name, default)
410 if isinstance(input_val, unicode):
411 input_val = input_val.encode('utf8')
412 settings[name] = asbool(input_val)
525 413
526 414
527 415 def _list_setting(settings, name, default):
@@ -32,26 +32,10 b' Please keep the following principles in '
32 32 """
33 33
34 34
35 def kombu_1_5_1_python_2_7_11():
36 """
37 Kombu 1.5.1 relies on a private method which got removed in Python 2.7.11.
38
39 This patch adds the symbol to the module :mod:`uuid` and assigns the value
40 ``None`` to it. This causes kombu to fall back to the public API of
41 :mod:`uuid`.
42
43 This patch can most probably be removed once celery and kombu are updated
44 to more recent versions.
45 """
46 import uuid
47
48 if not hasattr(uuid, '_uuid_generate_random'):
49 uuid._uuid_generate_random = None
50
51 35
52 36 def inspect_getargspec():
53 37 """
54 Pyramid and Pylons rely on inspect.getargspec to lookup the signature of
38 Pyramid rely on inspect.getargspec to lookup the signature of
55 39 view functions. This is not compatible with cython, therefore we replace
56 40 getargspec with a custom version.
57 41 Code is inspired by the inspect module from Python-3.4
@@ -110,7 +110,7 b' class IntegrationSettingsViewBase(BaseAp'
110 110
111 111 return False
112 112
113 def _get_local_tmpl_context(self, include_app_defaults=False):
113 def _get_local_tmpl_context(self, include_app_defaults=True):
114 114 _ = self.request.translate
115 115 c = super(IntegrationSettingsViewBase, self)._get_local_tmpl_context(
116 116 include_app_defaults=include_app_defaults)
@@ -366,7 +366,7 b' class GlobalIntegrationsView(Integration'
366 366 c.repo = self.repo
367 367 c.repo_group = self.repo_group
368 368 c.navlist = navigation_list(self.request)
369 self._register_global_c(c)
369
370 370 return c
371 371
372 372 @LoginRequired()
@@ -403,7 +403,7 b' class RepoIntegrationsView(IntegrationSe'
403 403 c.repo_name = self.db_repo.repo_name
404 404 c.repository_pull_requests = ScmModel().get_pull_requests(self.repo)
405 405
406 self._register_global_c(c)
406
407 407 return c
408 408
409 409 @LoginRequired()
@@ -434,7 +434,7 b' class RepoGroupIntegrationsView(Integrat'
434 434 c.repo = self.repo
435 435 c.repo_group = self.repo_group
436 436 c.navlist = navigation_list(self.request)
437 self._register_global_c(c)
437
438 438 return c
439 439
440 440 @LoginRequired()
@@ -20,7 +20,6 b''
20 20
21 21 import logging
22 22
23 from pylons.i18n.translation import _
24 23 from webhelpers.html.builder import literal
25 24 from webhelpers.html.tags import link_to
26 25
@@ -32,7 +31,7 b' from rhodecode.lib.vcs.exceptions import'
32 31 log = logging.getLogger(__name__)
33 32
34 33
35 def action_parser(user_log, feed=False, parse_cs=False):
34 def action_parser(request, user_log, feed=False, parse_cs=False):
36 35 """
37 36 This helper will action_map the specified string action into translated
38 37 fancy names with icons and links
@@ -42,11 +41,11 b' def action_parser(user_log, feed=False, '
42 41 :param parse_cs: parse Changesets into VCS instances
43 42 """
44 43 if user_log.version == 'v2':
45 ap = AuditLogParser(user_log)
44 ap = AuditLogParser(request, user_log)
46 45 return ap.callbacks()
47 46 else:
48 47 # old style
49 ap = ActionParser(user_log, feed=False, parse_commits=False)
48 ap = ActionParser(request, user_log, feed=False, parse_commits=False)
50 49 return ap.callbacks()
51 50
52 51
@@ -55,10 +54,11 b' class ActionParser(object):'
55 54 commits_limit = 3 # display this amount always
56 55 commits_top_limit = 50 # show up to this amount of commits hidden
57 56
58 def __init__(self, user_log, feed=False, parse_commits=False):
57 def __init__(self, request, user_log, feed=False, parse_commits=False):
59 58 self.user_log = user_log
60 59 self.feed = feed
61 60 self.parse_commits = parse_commits
61 self.request = request
62 62
63 63 self.action = user_log.action
64 64 self.action_params = ' '
@@ -86,7 +86,7 b' class ActionParser(object):'
86 86
87 87 @property
88 88 def action_map(self):
89
89 _ = self.request.translate
90 90 # action : translated str, callback(extractor), icon
91 91 action_map = {
92 92 'user_deleted_repo': (
@@ -166,6 +166,7 b' class ActionParser(object):'
166 166
167 167 def get_fork_name(self):
168 168 from rhodecode.lib import helpers as h
169 _ = self.request.translate
169 170 repo_name = self.action_params
170 171 _url = h.route_path('repo_summary', repo_name=repo_name)
171 172 return _('fork name %s') % link_to(self.action_params, _url)
@@ -180,6 +181,7 b' class ActionParser(object):'
180 181
181 182 def get_pull_request(self):
182 183 from rhodecode.lib import helpers as h
184 _ = self.request.translate
183 185 pull_request_id = self.action_params
184 186 if self.is_deleted():
185 187 repo_name = self.user_log.repository_name
@@ -201,6 +203,7 b' class ActionParser(object):'
201 203
202 204 def get_cs_links(self):
203 205 from rhodecode.lib import helpers as h
206 _ = self.request.translate
204 207 if self.is_deleted():
205 208 return self.action_params
206 209
@@ -277,7 +280,9 b' class ActionParser(object):'
277 280 def lnk(self, commit_or_id, repo_name):
278 281 from rhodecode.lib.helpers import tooltip
279 282 from rhodecode.lib import helpers as h
280
283 _ = self.request.translate
284 title = ''
285 lazy_cs = True
281 286 if isinstance(commit_or_id, (BaseCommit, AttributeDict)):
282 287 lazy_cs = True
283 288 if (getattr(commit_or_id, 'op', None) and
@@ -312,8 +317,9 b' class ActionParser(object):'
312 317
313 318
314 319 class AuditLogParser(object):
315 def __init__(self, audit_log_entry):
320 def __init__(self, request, audit_log_entry):
316 321 self.audit_log_entry = audit_log_entry
322 self.request = request
317 323
318 324 def get_icon(self, action):
319 325 return 'icon-rhodecode'
@@ -34,7 +34,7 b' import traceback'
34 34 from functools import wraps
35 35
36 36 import ipaddress
37 from beaker.cache import cache_region
37
38 38 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
39 39 from sqlalchemy.orm.exc import ObjectDeletedError
40 40 from sqlalchemy.orm import joinedload
@@ -52,42 +52,9 b' from rhodecode.model.notification import'
52 52 from rhodecode.model.scm import ScmModel
53 53 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
54 54
55 # NOTE(marcink): remove after base controller is no longer required
56 from pylons.controllers import WSGIController
57 from pylons.i18n import translation
58
59 55 log = logging.getLogger(__name__)
60 56
61 57
62 # hack to make the migration to pyramid easier
63 def render(template_name, extra_vars=None, cache_key=None,
64 cache_type=None, cache_expire=None):
65 """Render a template with Mako
66
67 Accepts the cache options ``cache_key``, ``cache_type``, and
68 ``cache_expire``.
69
70 """
71 from pylons.templating import literal
72 from pylons.templating import cached_template, pylons_globals
73
74 # Create a render callable for the cache function
75 def render_template():
76 # Pull in extra vars if needed
77 globs = extra_vars or {}
78
79 # Second, get the globals
80 globs.update(pylons_globals())
81
82 globs['_ungettext'] = globs['ungettext']
83 # Grab a template reference
84 template = globs['app_globals'].mako_lookup.get_template(template_name)
85
86 return literal(template.render_unicode(**globs))
87
88 return cached_template(template_name, render_template, cache_key=cache_key,
89 cache_type=cache_type, cache_expire=cache_expire)
90
91 58 def _filter_proxy(ip):
92 59 """
93 60 Passed in IP addresses in HEADERS can be in a special format of multiple
@@ -310,14 +277,10 b' def get_current_lang(request):'
310 277
311 278 def attach_context_attributes(context, request, user_id):
312 279 """
313 Attach variables into template context called `c`, please note that
314 request could be pylons or pyramid request in here.
280 Attach variables into template context called `c`.
315 281 """
316 # NOTE(marcink): remove check after pyramid migration
317 if hasattr(request, 'registry'):
318 config = request.registry.settings
319 else:
320 from pylons import config
282 config = request.registry.settings
283
321 284
322 285 rc_config = SettingsModel().get_all_settings(cache=True)
323 286
@@ -418,10 +381,6 b' def attach_context_attributes(context, r'
418 381 }
419 382 # END CONFIG VARS
420 383
421 # TODO: This dosn't work when called from pylons compatibility tween.
422 # Fix this and remove it from base controller.
423 # context.repo_name = get_repo_slug(request) # can be empty
424
425 384 diffmode = 'sideside'
426 385 if request.GET.get('diffmode'):
427 386 if request.GET['diffmode'] == 'unified':
@@ -439,20 +398,15 b' def attach_context_attributes(context, r'
439 398 context.backends.sort()
440 399 context.unread_notifications = NotificationModel().get_unread_cnt_for_user(user_id)
441 400
442 # NOTE(marcink): when migrated to pyramid we don't need to set this anymore,
443 # given request will ALWAYS be pyramid one
444 pyramid_request = pyramid.threadlocal.get_current_request()
445 context.pyramid_request = pyramid_request
446
447 401 # web case
448 if hasattr(pyramid_request, 'user'):
449 context.auth_user = pyramid_request.user
450 context.rhodecode_user = pyramid_request.user
402 if hasattr(request, 'user'):
403 context.auth_user = request.user
404 context.rhodecode_user = request.user
451 405
452 406 # api case
453 if hasattr(pyramid_request, 'rpc_user'):
454 context.auth_user = pyramid_request.rpc_user
455 context.rhodecode_user = pyramid_request.rpc_user
407 if hasattr(request, 'rpc_user'):
408 context.auth_user = request.rpc_user
409 context.rhodecode_user = request.rpc_user
456 410
457 411 # attach the whole call context to the request
458 412 request.call_context = context
@@ -500,82 +454,6 b' def get_auth_user(request):'
500 454 return auth_user
501 455
502 456
503 class BaseController(WSGIController):
504
505 def __before__(self):
506 """
507 __before__ is called before controller methods and after __call__
508 """
509 # on each call propagate settings calls into global settings.
510 from pylons import config
511 from pylons import tmpl_context as c, request, url
512 set_rhodecode_config(config)
513 attach_context_attributes(c, request, self._rhodecode_user.user_id)
514
515 # TODO: Remove this when fixed in attach_context_attributes()
516 c.repo_name = get_repo_slug(request) # can be empty
517
518 self.cut_off_limit_diff = safe_int(config.get('cut_off_limit_diff'))
519 self.cut_off_limit_file = safe_int(config.get('cut_off_limit_file'))
520 self.sa = meta.Session
521 self.scm_model = ScmModel(self.sa)
522
523 # set user language
524 user_lang = getattr(c.pyramid_request, '_LOCALE_', None)
525 if user_lang:
526 translation.set_lang(user_lang)
527 log.debug('set language to %s for user %s',
528 user_lang, self._rhodecode_user)
529
530 def _dispatch_redirect(self, with_url, environ, start_response):
531 from webob.exc import HTTPFound
532 resp = HTTPFound(with_url)
533 environ['SCRIPT_NAME'] = '' # handle prefix middleware
534 environ['PATH_INFO'] = with_url
535 return resp(environ, start_response)
536
537 def __call__(self, environ, start_response):
538 """Invoke the Controller"""
539 # WSGIController.__call__ dispatches to the Controller method
540 # the request is routed to. This routing information is
541 # available in environ['pylons.routes_dict']
542 from rhodecode.lib import helpers as h
543 from pylons import tmpl_context as c, request, url
544
545 # Provide the Pylons context to Pyramid's debugtoolbar if it asks
546 if environ.get('debugtoolbar.wants_pylons_context', False):
547 environ['debugtoolbar.pylons_context'] = c._current_obj()
548
549 _route_name = '.'.join([environ['pylons.routes_dict']['controller'],
550 environ['pylons.routes_dict']['action']])
551
552 self.rc_config = SettingsModel().get_all_settings(cache=True)
553 self.ip_addr = get_ip_addr(environ)
554
555 # The rhodecode auth user is looked up and passed through the
556 # environ by the pylons compatibility tween in pyramid.
557 # So we can just grab it from there.
558 auth_user = environ['rc_auth_user']
559
560 # set globals for auth user
561 request.user = auth_user
562 self._rhodecode_user = auth_user
563
564 log.info('IP: %s User: %s accessed %s [%s]' % (
565 self.ip_addr, auth_user, safe_unicode(get_access_path(environ)),
566 _route_name)
567 )
568
569 user_obj = auth_user.get_instance()
570 if user_obj and user_obj.user_data.get('force_password_change'):
571 h.flash('You are required to change your password', 'warning',
572 ignore_duplicate=True)
573 return self._dispatch_redirect(
574 url('my_account_password'), environ, start_response)
575
576 return WSGIController.__call__(self, environ, start_response)
577
578
579 457 def h_filter(s):
580 458 """
581 459 Custom filter for Mako templates. Mako by standard uses `markupsafe.escape`
@@ -623,6 +501,7 b' def bootstrap_config(request):'
623 501
624 502 # allow pyramid lookup in testing
625 503 config.include('pyramid_mako')
504 config.include('pyramid_beaker')
626 505
627 506 add_events_routes(config)
628 507
@@ -28,7 +28,6 b' import os'
28 28 import logging
29 29
30 30 from celery.task import task
31 from pylons import config
32 31
33 32 import rhodecode
34 33 from rhodecode.lib import audit_logger
@@ -42,9 +41,6 b' from rhodecode.lib.utils2 import safe_in'
42 41 from rhodecode.model.db import Repository, User
43 42
44 43
45 add_cache(config) # pragma: no cover
46
47
48 44 def get_logger(cls):
49 45 if rhodecode.CELERY_ENABLED:
50 46 try:
@@ -36,7 +36,7 b' class PylonsSettingsProxy(object):'
36 36 """
37 37 def __getattr__(self, key):
38 38 pylons_key = to_pylons(key)
39 proxy_config = rhodecode.PYRAMID_SETTINGS or pylons.config
39 proxy_config = rhodecode.PYRAMID_SETTINGS
40 40 try:
41 41 value = proxy_config[pylons_key]
42 42 if key in LIST_PARAMS:
@@ -59,7 +59,7 b' class PylonsSettingsProxy(object):'
59 59
60 60 def __setattr__(self, key, value):
61 61 pylons_key = to_pylons(key)
62 proxy_config = rhodecode.PYRAMID_SETTINGS or pylons.config
62 proxy_config = rhodecode.PYRAMID_SETTINGS
63 63 proxy_config[pylons_key] = value
64 64
65 65 def __setitem__(self, key, value):
@@ -30,7 +30,7 b' import logging'
30 30
31 31 from itertools import tee, imap
32 32
33 from pylons.i18n.translation import _
33 from rhodecode.translation import temp_translation_factory as _
34 34
35 35 from rhodecode.lib.vcs.exceptions import VCSError
36 36 from rhodecode.lib.vcs.nodes import FileNode, SubModuleNode
@@ -7,9 +7,9 b' import simplejson as json'
7 7 from rhodecode.lib.datelib import is_aware
8 8
9 9 try:
10 import pylons
10 import rhodecode.translation
11 11 except ImportError:
12 pylons = None
12 rhodecode = None
13 13
14 14 __all__ = ['json']
15 15
@@ -51,7 +51,7 b' def _obj_dump(obj):'
51 51 return str(obj)
52 52 elif isinstance(obj, complex):
53 53 return [obj.real, obj.imag]
54 elif pylons and isinstance(obj, pylons.i18n.translation.LazyString):
54 elif rhodecode and isinstance(obj, rhodecode.translation.LazyString):
55 55 return obj.eval()
56 56 else:
57 57 raise TypeError(repr(obj) + " is not JSON serializable")
@@ -91,11 +91,6 b' DEFAULT_USER = User.DEFAULT_USER'
91 91 DEFAULT_USER_EMAIL = User.DEFAULT_USER_EMAIL
92 92
93 93
94 def url(*args, **kw):
95 from pylons import url as pylons_url
96 return pylons_url(*args, **kw)
97
98
99 94 def asset(path, ver=None, **kwargs):
100 95 """
101 96 Helper to generate a static asset file path for rhodecode assets
@@ -1287,15 +1282,8 b' def initials_gravatar(email_address, fir'
1287 1282
1288 1283 def gravatar_url(email_address, size=30, request=None):
1289 1284 request = get_current_request()
1290 if request and hasattr(request, 'call_context'):
1291 _use_gravatar = request.call_context.visual.use_gravatar
1292 _gravatar_url = request.call_context.visual.gravatar_url
1293 else:
1294 # doh, we need to re-import those to mock it later
1295 from pylons import tmpl_context as c
1296
1297 _use_gravatar = c.visual.use_gravatar
1298 _gravatar_url = c.visual.gravatar_url
1285 _use_gravatar = request.call_context.visual.use_gravatar
1286 _gravatar_url = request.call_context.visual.gravatar_url
1299 1287
1300 1288 _gravatar_url = _gravatar_url or User.DEFAULT_GRAVATAR_URL
1301 1289
@@ -1745,8 +1733,6 b' def urlify_commit_message(commit_text, r'
1745 1733 :param commit_text:
1746 1734 :param repository:
1747 1735 """
1748 from pylons import url # doh, we need to re-import url to mock it later
1749
1750 1736 def escaper(string):
1751 1737 return string.replace('<', '&lt;').replace('>', '&gt;')
1752 1738
@@ -2006,8 +1992,6 b' def get_last_path_part(file_node):'
2006 1992 def route_url(*args, **kwargs):
2007 1993 """
2008 1994 Wrapper around pyramids `route_url` (fully qualified url) function.
2009 It is used to generate URLs from within pylons views or templates.
2010 This will be removed when pyramid migration if finished.
2011 1995 """
2012 1996 req = get_current_request()
2013 1997 return req.route_url(*args, **kwargs)
@@ -2015,9 +1999,7 b' def route_url(*args, **kwargs):'
2015 1999
2016 2000 def route_path(*args, **kwargs):
2017 2001 """
2018 Wrapper around pyramids `route_path` function. It is used to generate
2019 URLs from within pylons views or templates. This will be removed when
2020 pyramid migration if finished.
2002 Wrapper around pyramids `route_path` function.
2021 2003 """
2022 2004 req = get_current_request()
2023 2005 return req.route_path(*args, **kwargs)
@@ -2036,26 +2018,6 b' def current_route_path(request, **kw):'
2036 2018 return request.current_route_path(_query=new_args)
2037 2019
2038 2020
2039 def static_url(*args, **kwds):
2040 """
2041 Wrapper around pyramids `route_path` function. It is used to generate
2042 URLs from within pylons views or templates. This will be removed when
2043 pyramid migration if finished.
2044 """
2045 req = get_current_request()
2046 return req.static_url(*args, **kwds)
2047
2048
2049 def resource_path(*args, **kwds):
2050 """
2051 Wrapper around pyramids `route_path` function. It is used to generate
2052 URLs from within pylons views or templates. This will be removed when
2053 pyramid migration if finished.
2054 """
2055 req = get_current_request()
2056 return req.resource_path(*args, **kwds)
2057
2058
2059 2021 def api_call_example(method, args):
2060 2022 """
2061 2023 Generates an API call example via CURL
@@ -18,8 +18,8 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 import pylons
22 21 import webob
22 from pyramid.threadlocal import get_current_request
23 23
24 24 from rhodecode import events
25 25 from rhodecode.lib import hooks_base
@@ -31,12 +31,15 b' def _get_rc_scm_extras(username, repo_na'
31 31 from rhodecode.lib.base import vcs_operation_context
32 32 check_locking = action in ('pull', 'push')
33 33
34 request = get_current_request()
35
36 # default
37 dummy_environ = webob.Request.blank('').environ
34 38 try:
35 environ = pylons.request.environ
39 environ = request.environ or dummy_environ
36 40 except TypeError:
37 # we might use this outside of request context, let's fake the
38 # environ data
39 environ = webob.Request.blank('').environ
41 # we might use this outside of request context
42 environ = dummy_environ
40 43
41 44 extras = vcs_operation_context(
42 45 environ, repo_name, username, action, repo_alias, check_locking)
@@ -27,7 +27,7 b' import logging'
27 27 import os
28 28 import re
29 29
30 from pylons.i18n.translation import _
30 from rhodecode.translation import temp_translation_factory as _
31 31
32 32 from whoosh import query as query_lib, sorting
33 33 from whoosh.highlight import HtmlFormatter, ContextFragmenter
@@ -23,7 +23,7 b' import time'
23 23 import logging
24 24
25 25
26 from rhodecode.lib.base import get_ip_addr, get_access_path
26 from rhodecode.lib.base import get_ip_addr, get_access_path, get_user_agent
27 27 from rhodecode.lib.utils2 import safe_str
28 28
29 29
@@ -43,10 +43,11 b' class RequestWrapperTween(object):'
43 43 response = self.handler(request)
44 44 finally:
45 45 end = time.time()
46
47 log.info('IP: %s Request to %s time: %.3fs' % (
46 total = end - start
47 log.info('IP: %s Request to %s time: %.3fs [%s]' % (
48 48 get_ip_addr(request.environ),
49 safe_str(get_access_path(request.environ)), end - start)
49 safe_str(get_access_path(request.environ)), total,
50 get_user_agent(request. environ),)
50 51 )
51 52
52 53 return response
@@ -134,11 +134,11 b' class SimpleSvn(simplevcs.SimpleVCS):'
134 134 # SVN includes the whole path in it's requests, including
135 135 # subdirectories inside the repo. Therefore we have to search for
136 136 # the repo root directory.
137 if not is_valid_repo(repo_name, self.basepath, self.SCM):
137 if not is_valid_repo(repo_name, self.base_path, self.SCM):
138 138 current_path = ''
139 139 for component in repo_name.split('/'):
140 140 current_path += component
141 if is_valid_repo(current_path, self.basepath, self.SCM):
141 if is_valid_repo(current_path, self.base_path, self.SCM):
142 142 return current_path
143 143 current_path += '/'
144 144
@@ -31,7 +31,8 b' from functools import wraps'
31 31
32 32 import time
33 33 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
34 from webob.exc import (
34 # TODO(marcink): check if we should use webob.exc here ?
35 from pyramid.httpexceptions import (
35 36 HTTPNotFound, HTTPForbidden, HTTPNotAcceptable, HTTPInternalServerError)
36 37
37 38 import rhodecode
@@ -55,7 +56,7 b' from rhodecode.model import meta'
55 56 from rhodecode.model.db import User, Repository, PullRequest
56 57 from rhodecode.model.scm import ScmModel
57 58 from rhodecode.model.pull_request import PullRequestModel
58 from rhodecode.model.settings import SettingsModel
59 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
59 60
60 61 log = logging.getLogger(__name__)
61 62
@@ -103,14 +104,13 b' class SimpleVCS(object):'
103 104 'repository$' # shadow repo
104 105 .format(slug_pat=SLUG_RE.pattern))
105 106
106 def __init__(self, application, config, registry):
107 def __init__(self, config, registry):
107 108 self.registry = registry
108 self.application = application
109 109 self.config = config
110 110 # re-populated by specialized middleware
111 111 self.repo_vcs_config = base.Config()
112 112 self.rhodecode_settings = SettingsModel().get_all_settings(cache=True)
113 self.basepath = rhodecode.CONFIG['base_path']
113
114 114 registry.rhodecode_settings = self.rhodecode_settings
115 115 # authenticate this VCS request using authfunc
116 116 auth_ret_code_detection = \
@@ -120,6 +120,10 b' class SimpleVCS(object):'
120 120 auth_ret_code_detection)
121 121 self.ip_addr = '0.0.0.0'
122 122
123 @property
124 def base_path(self):
125 return self.repo_vcs_config.get(*VcsSettingsModel.PATH_SETTING)
126
123 127 def set_repo_names(self, environ):
124 128 """
125 129 This will populate the attributes acl_repo_name, url_repo_name,
@@ -381,6 +385,8 b' class SimpleVCS(object):'
381 385 # Check if the shadow repo actually exists, in case someone refers
382 386 # to it, and it has been deleted because of successful merge.
383 387 if self.is_shadow_repo and not self.is_shadow_repo_dir:
388 log.debug('Shadow repo detected, and shadow repo dir `%s` is missing',
389 self.is_shadow_repo_dir)
384 390 return HTTPNotFound()(environ, start_response)
385 391
386 392 # ======================================================================
@@ -493,7 +499,7 b' class SimpleVCS(object):'
493 499 # REQUEST HANDLING
494 500 # ======================================================================
495 501 repo_path = os.path.join(
496 safe_str(self.basepath), safe_str(self.vcs_repo_name))
502 safe_str(self.base_path), safe_str(self.vcs_repo_name))
497 503 log.debug('Repository path is %s', repo_path)
498 504
499 505 fix_PATH()
@@ -168,11 +168,11 b' def detect_vcs_request(environ, backends'
168 168
169 169 class VCSMiddleware(object):
170 170
171 def __init__(self, app, config, appenlight_client, registry):
171 def __init__(self, app, registry, config, appenlight_client):
172 172 self.application = app
173 self.registry = registry
173 174 self.config = config
174 175 self.appenlight_client = appenlight_client
175 self.registry = registry
176 176 self.use_gzip = True
177 177 # order in which we check the middlewares, based on vcs.backends config
178 178 self.check_middlewares = config['vcs.backends']
@@ -193,7 +193,7 b' class VCSMiddleware(object):'
193 193 log.debug('VCSMiddleware: detecting vcs type.')
194 194 handler = detect_vcs_request(environ, self.check_middlewares)
195 195 if handler:
196 app = handler(self.application, self.config, self.registry)
196 app = handler(self.config, self.registry)
197 197
198 198 return app
199 199
@@ -212,7 +212,7 b' class VCSMiddleware(object):'
212 212 # check for type, presence in database and on filesystem
213 213 if not vcs_handler.is_valid_and_existing_repo(
214 214 vcs_handler.acl_repo_name,
215 vcs_handler.basepath,
215 vcs_handler.base_path,
216 216 vcs_handler.SCM):
217 217 return HTTPNotFound()(environ, start_response)
218 218
@@ -578,9 +578,6 b' def rhodecode_config():'
578 578 blacklist = [
579 579 'rhodecode_license_key',
580 580 'routes.map',
581 'pylons.h',
582 'pylons.app_globals',
583 'pylons.environ_config',
584 581 'sqlalchemy.db1.url',
585 582 'channelstream.secret',
586 583 'beaker.session.secret',
@@ -97,18 +97,14 b' def repo_name_slug(value):'
97 97 #==============================================================================
98 98 def get_repo_slug(request):
99 99 _repo = ''
100 if isinstance(request, Request):
101 if hasattr(request, 'db_repo'):
102 # if our requests has set db reference use it for name, this
103 # translates the example.com/_<id> into proper repo names
104 _repo = request.db_repo.repo_name
105 elif getattr(request, 'matchdict', None):
106 # pyramid
107 _repo = request.matchdict.get('repo_name')
108 100
109 # TODO(marcink): remove after pylons migration...
110 if not _repo:
111 _repo = request.environ['pylons.routes_dict'].get('repo_name')
101 if hasattr(request, 'db_repo'):
102 # if our requests has set db reference use it for name, this
103 # translates the example.com/_<id> into proper repo names
104 _repo = request.db_repo.repo_name
105 elif getattr(request, 'matchdict', None):
106 # pyramid
107 _repo = request.matchdict.get('repo_name')
112 108
113 109 if _repo:
114 110 _repo = _repo.rstrip('/')
@@ -117,18 +113,14 b' def get_repo_slug(request):'
117 113
118 114 def get_repo_group_slug(request):
119 115 _group = ''
120 if isinstance(request, Request):
121 if hasattr(request, 'db_repo_group'):
122 # if our requests has set db reference use it for name, this
123 # translates the example.com/_<id> into proper repo group names
124 _group = request.db_repo_group.group_name
125 elif getattr(request, 'matchdict', None):
126 # pyramid
127 _group = request.matchdict.get('repo_group_name')
116 if hasattr(request, 'db_repo_group'):
117 # if our requests has set db reference use it for name, this
118 # translates the example.com/_<id> into proper repo group names
119 _group = request.db_repo_group.group_name
120 elif getattr(request, 'matchdict', None):
121 # pyramid
122 _group = request.matchdict.get('repo_group_name')
128 123
129 # TODO(marcink): remove after pylons migration...
130 if not _group:
131 _group = request.environ['pylons.routes_dict'].get('group_name')
132 124
133 125 if _group:
134 126 _group = _group.rstrip('/')
@@ -137,26 +129,21 b' def get_repo_group_slug(request):'
137 129
138 130 def get_user_group_slug(request):
139 131 _user_group = ''
140 if isinstance(request, Request):
141 132
142 if hasattr(request, 'db_user_group'):
143 _user_group = request.db_user_group.users_group_name
144 elif getattr(request, 'matchdict', None):
145 # pyramid
146 _user_group = request.matchdict.get('user_group_id')
133 if hasattr(request, 'db_user_group'):
134 _user_group = request.db_user_group.users_group_name
135 elif getattr(request, 'matchdict', None):
136 # pyramid
137 _user_group = request.matchdict.get('user_group_id')
147 138
148 try:
149 _user_group = UserGroup.get(_user_group)
150 if _user_group:
151 _user_group = _user_group.users_group_name
152 except Exception:
153 log.exception('Failed to get user group by id')
154 # catch all failures here
155 return None
156
157 # TODO(marcink): remove after pylons migration...
158 if not _user_group:
159 _user_group = request.environ['pylons.routes_dict'].get('user_group_id')
139 try:
140 _user_group = UserGroup.get(_user_group)
141 if _user_group:
142 _user_group = _user_group.users_group_name
143 except Exception:
144 log.exception('Failed to get user group by id')
145 # catch all failures here
146 return None
160 147
161 148 return _user_group
162 149
@@ -438,7 +425,7 b' def get_enabled_hook_classes(ui_settings'
438 425
439 426 def set_rhodecode_config(config):
440 427 """
441 Updates pylons config with new settings from database
428 Updates pyramid config with new settings from database
442 429
443 430 :param config:
444 431 """
@@ -881,19 +868,6 b' def read_opensource_licenses():'
881 868 return _license_cache
882 869
883 870
884 def get_registry(request):
885 """
886 Utility to get the pyramid registry from a request. During migration to
887 pyramid we sometimes want to use the pyramid registry from pylons context.
888 Therefore this utility returns `request.registry` for pyramid requests and
889 uses `get_current_registry()` for pylons requests.
890 """
891 try:
892 return request.registry
893 except AttributeError:
894 return get_current_registry()
895
896
897 871 def generate_platform_uuid():
898 872 """
899 873 Generates platform UUID based on it's name
@@ -18,27 +18,6 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 """
22 The application's model objects
23
24 :example:
25
26 .. code-block:: python
27
28 from paste.deploy import appconfig
29 from pylons import config
30 from sqlalchemy import engine_from_config
31 from rhodecode.config.environment import load_environment
32
33 conf = appconfig('config:development.ini', relative_to = './../../')
34 load_environment(conf.global_conf, conf.local_conf)
35
36 engine = engine_from_config(config, 'sqlalchemy.')
37 init_model(engine)
38 # RUN YOUR CODE HERE
39
40 """
41
42 21
43 22 import logging
44 23
@@ -26,7 +26,6 b' import logging'
26 26 import traceback
27 27 import collections
28 28
29 from pylons.i18n.translation import _
30 29 from pyramid.threadlocal import get_current_registry, get_current_request
31 30 from sqlalchemy.sql.expression import null
32 31 from sqlalchemy.sql.functions import coalesce
@@ -68,8 +67,8 b' class CommentsModel(BaseModel):'
68 67 user_objects.append(user_obj)
69 68 return user_objects
70 69
71 def _get_renderer(self, global_renderer='rst'):
72 request = get_current_request()
70 def _get_renderer(self, global_renderer='rst', request=None):
71 request = request or get_current_request()
73 72
74 73 try:
75 74 global_renderer = request.call_context.visual.default_renderer
@@ -194,9 +193,11 b' class CommentsModel(BaseModel):'
194 193 if not text:
195 194 log.warning('Missing text for comment, skipping...')
196 195 return
196 request = get_current_request()
197 _ = request.translate
197 198
198 199 if not renderer:
199 renderer = self._get_renderer()
200 renderer = self._get_renderer(request=request)
200 201
201 202 repo = self._get_repo(repo)
202 203 user = self._get_user(user)
@@ -268,7 +269,7 b' class CommentsModel(BaseModel):'
268 269 cs_author = repo.user
269 270 recipients += [cs_author]
270 271
271 commit_comment_url = self.get_url(comment)
272 commit_comment_url = self.get_url(comment, request=request)
272 273
273 274 target_repo_url = h.link_to(
274 275 repo.repo_name,
@@ -48,7 +48,7 b' import formencode'
48 48 from pkg_resources import resource_filename
49 49 from formencode import All, Pipe
50 50
51 from pylons.i18n.translation import _
51 from rhodecode.translation import temp_translation_factory as _
52 52 from pyramid.threadlocal import get_current_request
53 53
54 54 from rhodecode import BACKENDS
@@ -75,7 +75,9 b' form_renderer = RhodecodeFormZPTRenderer'
75 75 deform.Form.set_default_renderer(form_renderer)
76 76
77 77
78 def LoginForm():
78 def LoginForm(localizer):
79 _ = localizer
80
79 81 class _LoginForm(formencode.Schema):
80 82 allow_extra_fields = True
81 83 filter_extra_fields = True
@@ -101,33 +103,37 b' def LoginForm():'
101 103
102 104 remember = v.StringBoolean(if_missing=False)
103 105
104 chained_validators = [v.ValidAuth()]
106 chained_validators = [v.ValidAuth(localizer)]
105 107 return _LoginForm
106 108
107 109
108 def UserForm(edit=False, available_languages=[], old_data={}):
110 def UserForm(localizer, edit=False, available_languages=None, old_data=None):
111 old_data = old_data or {}
112 available_languages = available_languages or []
113 _ = localizer
114
109 115 class _UserForm(formencode.Schema):
110 116 allow_extra_fields = True
111 117 filter_extra_fields = True
112 118 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
113 v.ValidUsername(edit, old_data))
119 v.ValidUsername(localizer, edit, old_data))
114 120 if edit:
115 121 new_password = All(
116 v.ValidPassword(),
122 v.ValidPassword(localizer),
117 123 v.UnicodeString(strip=False, min=6, max=72, not_empty=False)
118 124 )
119 125 password_confirmation = All(
120 v.ValidPassword(),
126 v.ValidPassword(localizer),
121 127 v.UnicodeString(strip=False, min=6, max=72, not_empty=False),
122 128 )
123 129 admin = v.StringBoolean(if_missing=False)
124 130 else:
125 131 password = All(
126 v.ValidPassword(),
132 v.ValidPassword(localizer),
127 133 v.UnicodeString(strip=False, min=6, max=72, not_empty=True)
128 134 )
129 135 password_confirmation = All(
130 v.ValidPassword(),
136 v.ValidPassword(localizer),
131 137 v.UnicodeString(strip=False, min=6, max=72, not_empty=False)
132 138 )
133 139
@@ -137,17 +143,18 b' def UserForm(edit=False, available_langu'
137 143 active = v.StringBoolean(if_missing=False)
138 144 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
139 145 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
140 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
146 email = All(v.Email(not_empty=True), v.UniqSystemEmail(localizer, old_data))
141 147 extern_name = v.UnicodeString(strip=True)
142 148 extern_type = v.UnicodeString(strip=True)
143 149 language = v.OneOf(available_languages, hideList=False,
144 150 testValueList=True, if_missing=None)
145 chained_validators = [v.ValidPasswordsMatch()]
151 chained_validators = [v.ValidPasswordsMatch(localizer)]
146 152 return _UserForm
147 153
148 154
149 def UserGroupForm(edit=False, old_data=None, allow_disabled=False):
155 def UserGroupForm(localizer, edit=False, old_data=None, allow_disabled=False):
150 156 old_data = old_data or {}
157 _ = localizer
151 158
152 159 class _UserGroupForm(formencode.Schema):
153 160 allow_extra_fields = True
@@ -155,7 +162,7 b' def UserGroupForm(edit=False, old_data=N'
155 162
156 163 users_group_name = All(
157 164 v.UnicodeString(strip=True, min=1, not_empty=True),
158 v.ValidUserGroup(edit, old_data)
165 v.ValidUserGroup(localizer, edit, old_data)
159 166 )
160 167 user_group_description = v.UnicodeString(strip=True, min=1,
161 168 not_empty=False)
@@ -166,12 +173,13 b' def UserGroupForm(edit=False, old_data=N'
166 173 # this is user group owner
167 174 user = All(
168 175 v.UnicodeString(not_empty=True),
169 v.ValidRepoUser(allow_disabled))
176 v.ValidRepoUser(localizer, allow_disabled))
170 177 return _UserGroupForm
171 178
172 179
173 def RepoGroupForm(edit=False, old_data=None, available_groups=None,
174 can_create_in_root=False, allow_disabled=False):
180 def RepoGroupForm(localizer, edit=False, old_data=None, available_groups=None,
181 can_create_in_root=False, allow_disabled=False):
182 _ = localizer
175 183 old_data = old_data or {}
176 184 available_groups = available_groups or []
177 185
@@ -180,7 +188,7 b' def RepoGroupForm(edit=False, old_data=N'
180 188 filter_extra_fields = False
181 189
182 190 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
183 v.SlugifyName(),)
191 v.SlugifyName(localizer),)
184 192 group_description = v.UnicodeString(strip=True, min=1,
185 193 not_empty=False)
186 194 group_copy_permissions = v.StringBoolean(if_missing=False)
@@ -189,53 +197,57 b' def RepoGroupForm(edit=False, old_data=N'
189 197 testValueList=True, not_empty=True)
190 198 enable_locking = v.StringBoolean(if_missing=False)
191 199 chained_validators = [
192 v.ValidRepoGroup(edit, old_data, can_create_in_root)]
200 v.ValidRepoGroup(localizer, edit, old_data, can_create_in_root)]
193 201
194 202 if edit:
195 203 # this is repo group owner
196 204 user = All(
197 205 v.UnicodeString(not_empty=True),
198 v.ValidRepoUser(allow_disabled))
199
206 v.ValidRepoUser(localizer, allow_disabled))
200 207 return _RepoGroupForm
201 208
202 209
203 def RegisterForm(edit=False, old_data={}):
210 def RegisterForm(localizer, edit=False, old_data=None):
211 _ = localizer
212 old_data = old_data or {}
213
204 214 class _RegisterForm(formencode.Schema):
205 215 allow_extra_fields = True
206 216 filter_extra_fields = True
207 217 username = All(
208 v.ValidUsername(edit, old_data),
218 v.ValidUsername(localizer, edit, old_data),
209 219 v.UnicodeString(strip=True, min=1, not_empty=True)
210 220 )
211 221 password = All(
212 v.ValidPassword(),
222 v.ValidPassword(localizer),
213 223 v.UnicodeString(strip=False, min=6, max=72, not_empty=True)
214 224 )
215 225 password_confirmation = All(
216 v.ValidPassword(),
226 v.ValidPassword(localizer),
217 227 v.UnicodeString(strip=False, min=6, max=72, not_empty=True)
218 228 )
219 229 active = v.StringBoolean(if_missing=False)
220 230 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
221 231 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
222 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
232 email = All(v.Email(not_empty=True), v.UniqSystemEmail(localizer, old_data))
223 233
224 chained_validators = [v.ValidPasswordsMatch()]
225
234 chained_validators = [v.ValidPasswordsMatch(localizer)]
226 235 return _RegisterForm
227 236
228 237
229 def PasswordResetForm():
238 def PasswordResetForm(localizer):
239 _ = localizer
240
230 241 class _PasswordResetForm(formencode.Schema):
231 242 allow_extra_fields = True
232 243 filter_extra_fields = True
233 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
244 email = All(v.ValidSystemEmail(localizer), v.Email(not_empty=True))
234 245 return _PasswordResetForm
235 246
236 247
237 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None,
238 allow_disabled=False):
248 def RepoForm(localizer, edit=False, old_data=None, repo_groups=None,
249 landing_revs=None, allow_disabled=False):
250 _ = localizer
239 251 old_data = old_data or {}
240 252 repo_groups = repo_groups or []
241 253 landing_revs = landing_revs or []
@@ -245,8 +257,8 b' def RepoForm(edit=False, old_data=None, '
245 257 allow_extra_fields = True
246 258 filter_extra_fields = False
247 259 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
248 v.SlugifyName(), v.CannotHaveGitSuffix())
249 repo_group = All(v.CanWriteGroup(old_data),
260 v.SlugifyName(localizer), v.CannotHaveGitSuffix(localizer))
261 repo_group = All(v.CanWriteGroup(localizer, old_data),
250 262 v.OneOf(repo_groups, hideList=True))
251 263 repo_type = v.OneOf(supported_backends, required=False,
252 264 if_missing=old_data.get('repo_type'))
@@ -264,77 +276,91 b' def RepoForm(edit=False, old_data=None, '
264 276 # this is repo owner
265 277 user = All(
266 278 v.UnicodeString(not_empty=True),
267 v.ValidRepoUser(allow_disabled))
279 v.ValidRepoUser(localizer, allow_disabled))
268 280 clone_uri_change = v.UnicodeString(
269 281 not_empty=False, if_missing=v.Missing)
270 282
271 chained_validators = [v.ValidCloneUri(),
272 v.ValidRepoName(edit, old_data)]
283 chained_validators = [v.ValidCloneUri(localizer),
284 v.ValidRepoName(localizer, edit, old_data)]
273 285 return _RepoForm
274 286
275 287
276 def RepoPermsForm():
288 def RepoPermsForm(localizer):
289 _ = localizer
290
277 291 class _RepoPermsForm(formencode.Schema):
278 292 allow_extra_fields = True
279 293 filter_extra_fields = False
280 chained_validators = [v.ValidPerms(type_='repo')]
294 chained_validators = [v.ValidPerms(localizer, type_='repo')]
281 295 return _RepoPermsForm
282 296
283 297
284 def RepoGroupPermsForm(valid_recursive_choices):
298 def RepoGroupPermsForm(localizer, valid_recursive_choices):
299 _ = localizer
300
285 301 class _RepoGroupPermsForm(formencode.Schema):
286 302 allow_extra_fields = True
287 303 filter_extra_fields = False
288 304 recursive = v.OneOf(valid_recursive_choices)
289 chained_validators = [v.ValidPerms(type_='repo_group')]
305 chained_validators = [v.ValidPerms(localizer, type_='repo_group')]
290 306 return _RepoGroupPermsForm
291 307
292 308
293 def UserGroupPermsForm():
309 def UserGroupPermsForm(localizer):
310 _ = localizer
311
294 312 class _UserPermsForm(formencode.Schema):
295 313 allow_extra_fields = True
296 314 filter_extra_fields = False
297 chained_validators = [v.ValidPerms(type_='user_group')]
315 chained_validators = [v.ValidPerms(localizer, type_='user_group')]
298 316 return _UserPermsForm
299 317
300 318
301 def RepoFieldForm():
319 def RepoFieldForm(localizer):
320 _ = localizer
321
302 322 class _RepoFieldForm(formencode.Schema):
303 323 filter_extra_fields = True
304 324 allow_extra_fields = True
305 325
306 new_field_key = All(v.FieldKey(),
326 new_field_key = All(v.FieldKey(localizer),
307 327 v.UnicodeString(strip=True, min=3, not_empty=True))
308 328 new_field_value = v.UnicodeString(not_empty=False, if_missing=u'')
309 329 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
310 330 if_missing='str')
311 331 new_field_label = v.UnicodeString(not_empty=False)
312 332 new_field_desc = v.UnicodeString(not_empty=False)
313
314 333 return _RepoFieldForm
315 334
316 335
317 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
318 repo_groups=[], landing_revs=[]):
336 def RepoForkForm(localizer, edit=False, old_data=None,
337 supported_backends=BACKENDS.keys(), repo_groups=None,
338 landing_revs=None):
339 _ = localizer
340 old_data = old_data or {}
341 repo_groups = repo_groups or []
342 landing_revs = landing_revs or []
343
319 344 class _RepoForkForm(formencode.Schema):
320 345 allow_extra_fields = True
321 346 filter_extra_fields = False
322 347 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
323 v.SlugifyName())
324 repo_group = All(v.CanWriteGroup(),
348 v.SlugifyName(localizer))
349 repo_group = All(v.CanWriteGroup(localizer, ),
325 350 v.OneOf(repo_groups, hideList=True))
326 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
351 repo_type = All(v.ValidForkType(localizer, old_data), v.OneOf(supported_backends))
327 352 description = v.UnicodeString(strip=True, min=1, not_empty=True)
328 353 private = v.StringBoolean(if_missing=False)
329 354 copy_permissions = v.StringBoolean(if_missing=False)
330 355 fork_parent_id = v.UnicodeString()
331 chained_validators = [v.ValidForkName(edit, old_data)]
356 chained_validators = [v.ValidForkName(localizer, edit, old_data)]
332 357 landing_rev = v.OneOf(landing_revs, hideList=True)
333
334 358 return _RepoForkForm
335 359
336 360
337 def ApplicationSettingsForm():
361 def ApplicationSettingsForm(localizer):
362 _ = localizer
363
338 364 class _ApplicationSettingsForm(formencode.Schema):
339 365 allow_extra_fields = True
340 366 filter_extra_fields = False
@@ -346,11 +372,12 b' def ApplicationSettingsForm():'
346 372 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
347 373 rhodecode_create_personal_repo_group = v.StringBoolean(if_missing=False)
348 374 rhodecode_personal_repo_group_pattern = v.UnicodeString(strip=True, min=1, not_empty=False)
349
350 375 return _ApplicationSettingsForm
351 376
352 377
353 def ApplicationVisualisationForm():
378 def ApplicationVisualisationForm(localizer):
379 _ = localizer
380
354 381 class _ApplicationVisualisationForm(formencode.Schema):
355 382 allow_extra_fields = True
356 383 filter_extra_fields = False
@@ -370,11 +397,11 b' def ApplicationVisualisationForm():'
370 397 rhodecode_support_url = v.UnicodeString()
371 398 rhodecode_show_revision_number = v.StringBoolean(if_missing=False)
372 399 rhodecode_show_sha_length = v.Int(min=4, not_empty=True)
373
374 400 return _ApplicationVisualisationForm
375 401
376 402
377 403 class _BaseVcsSettingsForm(formencode.Schema):
404
378 405 allow_extra_fields = True
379 406 filter_extra_fields = False
380 407 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
@@ -403,48 +430,54 b' class _BaseVcsSettingsForm(formencode.Sc'
403 430 vcs_svn_proxy_http_server_url = v.UnicodeString(strip=True, if_missing=None)
404 431
405 432
406 def ApplicationUiSettingsForm():
433 def ApplicationUiSettingsForm(localizer):
434 _ = localizer
435
407 436 class _ApplicationUiSettingsForm(_BaseVcsSettingsForm):
408 437 web_push_ssl = v.StringBoolean(if_missing=False)
409 438 paths_root_path = All(
410 v.ValidPath(),
439 v.ValidPath(localizer),
411 440 v.UnicodeString(strip=True, min=1, not_empty=True)
412 441 )
413 442 largefiles_usercache = All(
414 v.ValidPath(),
443 v.ValidPath(localizer),
415 444 v.UnicodeString(strip=True, min=2, not_empty=True))
416 445 vcs_git_lfs_store_location = All(
417 v.ValidPath(),
446 v.ValidPath(localizer),
418 447 v.UnicodeString(strip=True, min=2, not_empty=True))
419 448 extensions_hgsubversion = v.StringBoolean(if_missing=False)
420 449 extensions_hggit = v.StringBoolean(if_missing=False)
421 new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch')
422 new_svn_tag = v.ValidSvnPattern(section='vcs_svn_tag')
423
450 new_svn_branch = v.ValidSvnPattern(localizer, section='vcs_svn_branch')
451 new_svn_tag = v.ValidSvnPattern(localizer, section='vcs_svn_tag')
424 452 return _ApplicationUiSettingsForm
425 453
426 454
427 def RepoVcsSettingsForm(repo_name):
455 def RepoVcsSettingsForm(localizer, repo_name):
456 _ = localizer
457
428 458 class _RepoVcsSettingsForm(_BaseVcsSettingsForm):
429 459 inherit_global_settings = v.StringBoolean(if_missing=False)
430 new_svn_branch = v.ValidSvnPattern(
460 new_svn_branch = v.ValidSvnPattern(localizer,
431 461 section='vcs_svn_branch', repo_name=repo_name)
432 new_svn_tag = v.ValidSvnPattern(
462 new_svn_tag = v.ValidSvnPattern(localizer,
433 463 section='vcs_svn_tag', repo_name=repo_name)
434
435 464 return _RepoVcsSettingsForm
436 465
437 466
438 def LabsSettingsForm():
467 def LabsSettingsForm(localizer):
468 _ = localizer
469
439 470 class _LabSettingsForm(formencode.Schema):
440 471 allow_extra_fields = True
441 472 filter_extra_fields = False
442
443 473 return _LabSettingsForm
444 474
445 475
446 476 def ApplicationPermissionsForm(
447 register_choices, password_reset_choices, extern_activate_choices):
477 localizer, register_choices, password_reset_choices,
478 extern_activate_choices):
479 _ = localizer
480
448 481 class _DefaultPermissionsForm(formencode.Schema):
449 482 allow_extra_fields = True
450 483 filter_extra_fields = True
@@ -454,12 +487,13 b' def ApplicationPermissionsForm('
454 487 default_register_message = v.UnicodeString()
455 488 default_password_reset = v.OneOf(password_reset_choices)
456 489 default_extern_activate = v.OneOf(extern_activate_choices)
457
458 490 return _DefaultPermissionsForm
459 491
460 492
461 def ObjectPermissionsForm(repo_perms_choices, group_perms_choices,
493 def ObjectPermissionsForm(localizer, repo_perms_choices, group_perms_choices,
462 494 user_group_perms_choices):
495 _ = localizer
496
463 497 class _ObjectPermissionsForm(formencode.Schema):
464 498 allow_extra_fields = True
465 499 filter_extra_fields = True
@@ -469,13 +503,14 b' def ObjectPermissionsForm(repo_perms_cho'
469 503 default_repo_perm = v.OneOf(repo_perms_choices)
470 504 default_group_perm = v.OneOf(group_perms_choices)
471 505 default_user_group_perm = v.OneOf(user_group_perms_choices)
472
473 506 return _ObjectPermissionsForm
474 507
475 508
476 def UserPermissionsForm(create_choices, create_on_write_choices,
509 def UserPermissionsForm(localizer, create_choices, create_on_write_choices,
477 510 repo_group_create_choices, user_group_create_choices,
478 511 fork_choices, inherit_default_permissions_choices):
512 _ = localizer
513
479 514 class _DefaultPermissionsForm(formencode.Schema):
480 515 allow_extra_fields = True
481 516 filter_extra_fields = True
@@ -488,21 +523,24 b' def UserPermissionsForm(create_choices, '
488 523 default_repo_group_create = v.OneOf(repo_group_create_choices)
489 524 default_fork_create = v.OneOf(fork_choices)
490 525 default_inherit_default_permissions = v.OneOf(inherit_default_permissions_choices)
491
492 526 return _DefaultPermissionsForm
493 527
494 528
495 def UserIndividualPermissionsForm():
529 def UserIndividualPermissionsForm(localizer):
530 _ = localizer
531
496 532 class _DefaultPermissionsForm(formencode.Schema):
497 533 allow_extra_fields = True
498 534 filter_extra_fields = True
499 535
500 536 inherit_default_permissions = v.StringBoolean(if_missing=False)
501
502 537 return _DefaultPermissionsForm
503 538
504 539
505 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
540 def DefaultsForm(localizer, edit=False, old_data=None, supported_backends=BACKENDS.keys()):
541 _ = localizer
542 old_data = old_data or {}
543
506 544 class _DefaultsForm(formencode.Schema):
507 545 allow_extra_fields = True
508 546 filter_extra_fields = True
@@ -511,34 +549,39 b' def DefaultsForm(edit=False, old_data={}'
511 549 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
512 550 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
513 551 default_repo_enable_locking = v.StringBoolean(if_missing=False)
514
515 552 return _DefaultsForm
516 553
517 554
518 def AuthSettingsForm():
555 def AuthSettingsForm(localizer):
556 _ = localizer
557
519 558 class _AuthSettingsForm(formencode.Schema):
520 559 allow_extra_fields = True
521 560 filter_extra_fields = True
522 auth_plugins = All(v.ValidAuthPlugins(),
523 v.UniqueListFromString()(not_empty=True))
524
561 auth_plugins = All(v.ValidAuthPlugins(localizer),
562 v.UniqueListFromString(localizer)(not_empty=True))
525 563 return _AuthSettingsForm
526 564
527 565
528 def UserExtraEmailForm():
566 def UserExtraEmailForm(localizer):
567 _ = localizer
568
529 569 class _UserExtraEmailForm(formencode.Schema):
530 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
570 email = All(v.UniqSystemEmail(localizer), v.Email(not_empty=True))
531 571 return _UserExtraEmailForm
532 572
533 573
534 def UserExtraIpForm():
574 def UserExtraIpForm(localizer):
575 _ = localizer
576
535 577 class _UserExtraIpForm(formencode.Schema):
536 ip = v.ValidIp()(not_empty=True)
578 ip = v.ValidIp(localizer)(not_empty=True)
537 579 return _UserExtraIpForm
538 580
539 581
582 def PullRequestForm(localizer, repo_id):
583 _ = localizer
540 584
541 def PullRequestForm(repo_id):
542 585 class ReviewerForm(formencode.Schema):
543 586 user_id = v.Int(not_empty=True)
544 587 reasons = All()
@@ -553,8 +596,8 b' def PullRequestForm(repo_id):'
553 596 source_ref = v.UnicodeString(strip=True, required=True)
554 597 target_repo = v.UnicodeString(strip=True, required=True)
555 598 target_ref = v.UnicodeString(strip=True, required=True)
556 revisions = All(#v.NotReviewedRevisions(repo_id)(),
557 v.UniqueList()(not_empty=True))
599 revisions = All(#v.NotReviewedRevisions(localizer, repo_id)(),
600 v.UniqueList(localizer)(not_empty=True))
558 601 review_members = formencode.ForEach(ReviewerForm())
559 602 pullrequest_title = v.UnicodeString(strip=True, required=True)
560 603 pullrequest_desc = v.UnicodeString(strip=True, required=False)
@@ -562,9 +605,11 b' def PullRequestForm(repo_id):'
562 605 return _PullRequestForm
563 606
564 607
565 def IssueTrackerPatternsForm():
608 def IssueTrackerPatternsForm(localizer):
609 _ = localizer
610
566 611 class _IssueTrackerPatternsForm(formencode.Schema):
567 612 allow_extra_fields = True
568 613 filter_extra_fields = False
569 chained_validators = [v.ValidPattern()]
614 chained_validators = [v.ValidPattern(localizer)]
570 615 return _IssueTrackerPatternsForm
@@ -30,7 +30,7 b' import logging'
30 30 import cStringIO
31 31 import pkg_resources
32 32
33 from pylons.i18n.translation import _
33 from rhodecode.translation import temp_translation_factory as _
34 34 from sqlalchemy import func
35 35 from zope.cachedescriptors.property import Lazy as LazyProperty
36 36
@@ -26,7 +26,7 b' import logging'
26 26 import traceback
27 27
28 28 import datetime
29 from pylons.i18n.translation import _
29 from rhodecode.translation import temp_translation_factory as _
30 30
31 31 import ipaddress
32 32 from sqlalchemy.exc import DatabaseError
@@ -754,14 +754,12 b' class UserModel(BaseModel):'
754 754 :param user:
755 755 :param email:
756 756 """
757 from rhodecode.model import forms
758 form = forms.UserExtraEmailForm()()
759 data = form.to_python({'email': email})
757
760 758 user = self._get_user(user)
761 759
762 760 obj = UserEmailMap()
763 761 obj.user = user
764 obj.email = data['email']
762 obj.email = email
765 763 self.sa.add(obj)
766 764 return obj
767 765
@@ -811,14 +809,11 b' class UserModel(BaseModel):'
811 809 :param user:
812 810 :param ip:
813 811 """
814 from rhodecode.model import forms
815 form = forms.UserExtraIpForm()()
816 data = form.to_python({'ip': ip})
812
817 813 user = self._get_user(user)
818
819 814 obj = UserIpMap()
820 815 obj.user = user
821 obj.ip_addr = data['ip']
816 obj.ip_addr = ip
822 817 obj.description = description
823 818 self.sa.add(obj)
824 819 return obj
@@ -22,10 +22,11 b''
22 22 Set of generic validators
23 23 """
24 24
25 import logging
25
26 26 import os
27 27 import re
28 from collections import defaultdict
28 import logging
29 import collections
29 30
30 31 import formencode
31 32 import ipaddress
@@ -33,7 +34,7 b' from formencode.validators import ('
33 34 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
34 35 NotEmpty, IPAddress, CIDR, String, FancyValidator
35 36 )
36 from pylons.i18n.translation import _
37
37 38 from sqlalchemy.sql.expression import true
38 39 from sqlalchemy.util import OrderedSet
39 40 from webhelpers.pylonslib.secure_form import authentication_token
@@ -62,17 +63,11 b' log = logging.getLogger(__name__)'
62 63 class _Missing(object):
63 64 pass
64 65
66
65 67 Missing = _Missing()
66 68
67 69
68 class StateObj(object):
69 """
70 this is needed to translate the messages using _() in validators
71 """
72 _ = staticmethod(_)
73
74
75 def M(self, key, state=None, **kwargs):
70 def M(self, key, state, **kwargs):
76 71 """
77 72 returns string from self.message based on given key,
78 73 passed kw params are used to substitute %(named)s params inside
@@ -81,16 +76,16 b' def M(self, key, state=None, **kwargs):'
81 76 :param msg:
82 77 :param state:
83 78 """
84 if state is None:
85 state = StateObj()
86 else:
87 state._ = staticmethod(_)
79
80 #state._ = staticmethod(_)
88 81 # inject validator into state object
89 82 return self.message(key, state, **kwargs)
90 83
91 84
92 def UniqueList(convert=None):
93 class _UniqueList(formencode.FancyValidator):
85 def UniqueList(localizer, convert=None):
86 _ = localizer
87
88 class _validator(formencode.FancyValidator):
94 89 """
95 90 Unique List !
96 91 """
@@ -123,20 +118,23 b' def UniqueList(convert=None):'
123 118
124 119 def empty_value(self, value):
125 120 return []
126
127 return _UniqueList
121 return _validator
128 122
129 123
130 def UniqueListFromString():
131 class _UniqueListFromString(UniqueList()):
124 def UniqueListFromString(localizer):
125 _ = localizer
126
127 class _validator(UniqueList(localizer)):
132 128 def _to_python(self, value, state):
133 129 if isinstance(value, basestring):
134 130 value = aslist(value, ',')
135 return super(_UniqueListFromString, self)._to_python(value, state)
136 return _UniqueListFromString
131 return super(_validator, self)._to_python(value, state)
132 return _validator
137 133
138 134
139 def ValidSvnPattern(section, repo_name=None):
135 def ValidSvnPattern(localizer, section, repo_name=None):
136 _ = localizer
137
140 138 class _validator(formencode.validators.FancyValidator):
141 139 messages = {
142 140 'pattern_exists': _(u'Pattern already exists'),
@@ -154,7 +152,10 b' def ValidSvnPattern(section, repo_name=N'
154 152 return _validator
155 153
156 154
157 def ValidUsername(edit=False, old_data={}):
155 def ValidUsername(localizer, edit=False, old_data=None):
156 _ = localizer
157 old_data = old_data or {}
158
158 159 class _validator(formencode.validators.FancyValidator):
159 160 messages = {
160 161 'username_exists': _(u'Username "%(username)s" already exists'),
@@ -187,13 +188,9 b' def ValidUsername(edit=False, old_data={'
187 188 return _validator
188 189
189 190
190 def ValidRegex(msg=None):
191 class _validator(formencode.validators.Regex):
192 messages = {'invalid': msg or _(u'The input is not valid')}
193 return _validator
191 def ValidRepoUser(localizer, allow_disabled=False):
192 _ = localizer
194 193
195
196 def ValidRepoUser(allow_disabled=False):
197 194 class _validator(formencode.validators.FancyValidator):
198 195 messages = {
199 196 'invalid_username': _(u'Username %(username)s is not valid'),
@@ -213,11 +210,13 b' def ValidRepoUser(allow_disabled=False):'
213 210 raise formencode.Invalid(
214 211 msg, value, state, error_dict={'username': msg}
215 212 )
216
217 213 return _validator
218 214
219 215
220 def ValidUserGroup(edit=False, old_data={}):
216 def ValidUserGroup(localizer, edit=False, old_data=None):
217 _ = localizer
218 old_data = old_data or {}
219
221 220 class _validator(formencode.validators.FancyValidator):
222 221 messages = {
223 222 'invalid_group': _(u'Invalid user group name'),
@@ -254,11 +253,13 b' def ValidUserGroup(edit=False, old_data='
254 253 raise formencode.Invalid(
255 254 msg, value, state, error_dict={'users_group_name': msg}
256 255 )
257
258 256 return _validator
259 257
260 258
261 def ValidRepoGroup(edit=False, old_data={}, can_create_in_root=False):
259 def ValidRepoGroup(localizer, edit=False, old_data=None, can_create_in_root=False):
260 _ = localizer
261 old_data = old_data or {}
262
262 263 class _validator(formencode.validators.FancyValidator):
263 264 messages = {
264 265 'group_parent_id': _(u'Cannot assign this group as parent'),
@@ -375,11 +376,12 b' def ValidRepoGroup(edit=False, old_data='
375 376 msg = M(self, 'repo_exists', state, group_name=group_name)
376 377 raise formencode.Invalid(
377 378 msg, value, state, error_dict={'group_name': msg})
378
379 379 return _validator
380 380
381 381
382 def ValidPassword():
382 def ValidPassword(localizer):
383 _ = localizer
384
383 385 class _validator(formencode.validators.FancyValidator):
384 386 messages = {
385 387 'invalid_password':
@@ -395,24 +397,11 b' def ValidPassword():'
395 397 return _validator
396 398
397 399
398 def ValidOldPassword(username):
399 class _validator(formencode.validators.FancyValidator):
400 messages = {
401 'invalid_password': _(u'Invalid old password')
402 }
400 def ValidPasswordsMatch(
401 localizer, passwd='new_password',
402 passwd_confirmation='password_confirmation'):
403 _ = localizer
403 404
404 def validate_python(self, value, state):
405 from rhodecode.authentication.base import authenticate, HTTP_TYPE
406 if not authenticate(username, value, '', HTTP_TYPE):
407 msg = M(self, 'invalid_password', state)
408 raise formencode.Invalid(
409 msg, value, state, error_dict={'current_password': msg}
410 )
411 return _validator
412
413
414 def ValidPasswordsMatch(
415 passwd='new_password', passwd_confirmation='password_confirmation'):
416 405 class _validator(formencode.validators.FancyValidator):
417 406 messages = {
418 407 'password_mismatch': _(u'Passwords do not match'),
@@ -430,7 +419,9 b' def ValidPasswordsMatch('
430 419 return _validator
431 420
432 421
433 def ValidAuth():
422 def ValidAuth(localizer):
423 _ = localizer
424
434 425 class _validator(formencode.validators.FancyValidator):
435 426 messages = {
436 427 'invalid_password': _(u'invalid password'),
@@ -464,7 +455,9 b' def ValidAuth():'
464 455 return _validator
465 456
466 457
467 def ValidAuthToken():
458 def ValidAuthToken(localizer):
459 _ = localizer
460
468 461 class _validator(formencode.validators.FancyValidator):
469 462 messages = {
470 463 'invalid_token': _(u'Token mismatch')
@@ -477,7 +470,10 b' def ValidAuthToken():'
477 470 return _validator
478 471
479 472
480 def ValidRepoName(edit=False, old_data={}):
473 def ValidRepoName(localizer, edit=False, old_data=None):
474 old_data = old_data or {}
475 _ = localizer
476
481 477 class _validator(formencode.validators.FancyValidator):
482 478 messages = {
483 479 'invalid_repo_name':
@@ -558,11 +554,15 b' def ValidRepoName(edit=False, old_data={'
558 554 return _validator
559 555
560 556
561 def ValidForkName(*args, **kwargs):
562 return ValidRepoName(*args, **kwargs)
557 def ValidForkName(localizer, *args, **kwargs):
558 _ = localizer
559
560 return ValidRepoName(localizer, *args, **kwargs)
563 561
564 562
565 def SlugifyName():
563 def SlugifyName(localizer):
564 _ = localizer
565
566 566 class _validator(formencode.validators.FancyValidator):
567 567
568 568 def _to_python(self, value, state):
@@ -570,11 +570,12 b' def SlugifyName():'
570 570
571 571 def validate_python(self, value, state):
572 572 pass
573
574 573 return _validator
575 574
576 575
577 def CannotHaveGitSuffix():
576 def CannotHaveGitSuffix(localizer):
577 _ = localizer
578
578 579 class _validator(formencode.validators.FancyValidator):
579 580 messages = {
580 581 'has_git_suffix':
@@ -590,11 +591,12 b' def CannotHaveGitSuffix():'
590 591 self, 'has_git_suffix', state)
591 592 raise formencode.Invalid(
592 593 msg, value, state, error_dict={'repo_name': msg})
593
594 594 return _validator
595 595
596 596
597 def ValidCloneUri():
597 def ValidCloneUri(localizer):
598 _ = localizer
599
598 600 class InvalidCloneUrl(Exception):
599 601 allowed_prefixes = ()
600 602
@@ -652,19 +654,22 b' def ValidCloneUri():'
652 654 url_handler(repo_type, url)
653 655 except InvalidCloneUrl as e:
654 656 log.warning(e)
655 msg = M(self, 'invalid_clone_uri', rtype=repo_type,
657 msg = M(self, 'invalid_clone_uri', state, rtype=repo_type,
656 658 allowed_prefixes=','.join(e.allowed_prefixes))
657 659 raise formencode.Invalid(msg, value, state,
658 660 error_dict={'clone_uri': msg})
659 661 except Exception:
660 662 log.exception('Url validation failed')
661 msg = M(self, 'clone_uri', rtype=repo_type)
663 msg = M(self, 'clone_uri', state, rtype=repo_type)
662 664 raise formencode.Invalid(msg, value, state,
663 665 error_dict={'clone_uri': msg})
664 666 return _validator
665 667
666 668
667 def ValidForkType(old_data={}):
669 def ValidForkType(localizer, old_data=None):
670 _ = localizer
671 old_data = old_data or {}
672
668 673 class _validator(formencode.validators.FancyValidator):
669 674 messages = {
670 675 'invalid_fork_type': _(u'Fork have to be the same type as parent')
@@ -679,7 +684,9 b' def ValidForkType(old_data={}):'
679 684 return _validator
680 685
681 686
682 def CanWriteGroup(old_data=None):
687 def CanWriteGroup(localizer, old_data=None):
688 _ = localizer
689
683 690 class _validator(formencode.validators.FancyValidator):
684 691 messages = {
685 692 'permission_denied': _(
@@ -730,11 +737,11 b' def CanWriteGroup(old_data=None):'
730 737 raise formencode.Invalid(
731 738 msg, value, state, error_dict={'repo_type': msg}
732 739 )
733
734 740 return _validator
735 741
736 742
737 def ValidPerms(type_='repo'):
743 def ValidPerms(localizer, type_='repo'):
744 _ = localizer
738 745 if type_ == 'repo_group':
739 746 EMPTY_PERM = 'group.none'
740 747 elif type_ == 'repo':
@@ -756,8 +763,8 b" def ValidPerms(type_='repo'):"
756 763
757 764 # Read the perm_new_member/perm_del_member attributes and group
758 765 # them by they IDs
759 new_perms_group = defaultdict(dict)
760 del_perms_group = defaultdict(dict)
766 new_perms_group = collections.defaultdict(dict)
767 del_perms_group = collections.defaultdict(dict)
761 768 for k, v in value.copy().iteritems():
762 769 if k.startswith('perm_del_member'):
763 770 # delete from org storage so we don't process that later
@@ -851,29 +858,9 b" def ValidPerms(type_='repo'):"
851 858 return _validator
852 859
853 860
854 def ValidSettings():
855 class _validator(formencode.validators.FancyValidator):
856 def _to_python(self, value, state):
857 # settings form for users that are not admin
858 # can't edit certain parameters, it's extra backup if they mangle
859 # with forms
860
861 forbidden_params = [
862 'user', 'repo_type', 'repo_enable_locking',
863 'repo_enable_downloads', 'repo_enable_statistics'
864 ]
861 def ValidPath(localizer):
862 _ = localizer
865 863
866 for param in forbidden_params:
867 if param in value:
868 del value[param]
869 return value
870
871 def validate_python(self, value, state):
872 pass
873 return _validator
874
875
876 def ValidPath():
877 864 class _validator(formencode.validators.FancyValidator):
878 865 messages = {
879 866 'invalid_path': _(u'This is not a valid path')
@@ -888,7 +875,10 b' def ValidPath():'
888 875 return _validator
889 876
890 877
891 def UniqSystemEmail(old_data={}):
878 def UniqSystemEmail(localizer, old_data=None):
879 _ = localizer
880 old_data = old_data or {}
881
892 882 class _validator(formencode.validators.FancyValidator):
893 883 messages = {
894 884 'email_taken': _(u'This e-mail address is already taken')
@@ -908,7 +898,9 b' def UniqSystemEmail(old_data={}):'
908 898 return _validator
909 899
910 900
911 def ValidSystemEmail():
901 def ValidSystemEmail(localizer):
902 _ = localizer
903
912 904 class _validator(formencode.validators.FancyValidator):
913 905 messages = {
914 906 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
@@ -924,11 +916,11 b' def ValidSystemEmail():'
924 916 raise formencode.Invalid(
925 917 msg, value, state, error_dict={'email': msg}
926 918 )
927
928 919 return _validator
929 920
930 921
931 def NotReviewedRevisions(repo_id):
922 def NotReviewedRevisions(localizer, repo_id):
923 _ = localizer
932 924 class _validator(formencode.validators.FancyValidator):
933 925 messages = {
934 926 'rev_already_reviewed':
@@ -960,7 +952,9 b' def NotReviewedRevisions(repo_id):'
960 952 return _validator
961 953
962 954
963 def ValidIp():
955 def ValidIp(localizer):
956 _ = localizer
957
964 958 class _validator(CIDR):
965 959 messages = {
966 960 'badFormat': _(u'Please enter a valid IPv4 or IpV6 address'),
@@ -984,11 +978,12 b' def ValidIp():'
984 978 except ValueError:
985 979 raise formencode.Invalid(self.message('badFormat', state),
986 980 value, state)
987
988 981 return _validator
989 982
990 983
991 def FieldKey():
984 def FieldKey(localizer):
985 _ = localizer
986
992 987 class _validator(formencode.validators.FancyValidator):
993 988 messages = {
994 989 'badFormat': _(
@@ -1003,7 +998,9 b' def FieldKey():'
1003 998 return _validator
1004 999
1005 1000
1006 def ValidAuthPlugins():
1001 def ValidAuthPlugins(localizer):
1002 _ = localizer
1003
1007 1004 class _validator(formencode.validators.FancyValidator):
1008 1005 messages = {
1009 1006 'import_duplicate': _(
@@ -1033,11 +1030,11 b' def ValidAuthPlugins():'
1033 1030 log.exception(
1034 1031 'Exception during import of auth legacy plugin "{}"'
1035 1032 .format(plugin_id))
1036 msg = M(self, 'import_error', plugin_id=plugin_id)
1033 msg = M(self, 'import_error', state, plugin_id=plugin_id)
1037 1034 raise formencode.Invalid(msg, value, state)
1038 1035
1039 1036 if not hasattr(plugin, 'includeme'):
1040 msg = M(self, 'missing_includeme', plugin_id=plugin_id)
1037 msg = M(self, 'missing_includeme', state, plugin_id=plugin_id)
1041 1038 raise formencode.Invalid(msg, value, state)
1042 1039
1043 1040 return plugin
@@ -1051,7 +1048,7 b' def ValidAuthPlugins():'
1051 1048 plugin = loadplugin(plugin_id)
1052 1049
1053 1050 if plugin is None:
1054 msg = M(self, 'no_plugin', plugin_id=plugin_id)
1051 msg = M(self, 'no_plugin', state, plugin_id=plugin_id)
1055 1052 raise formencode.Invalid(msg, value, state)
1056 1053
1057 1054 return plugin
@@ -1074,13 +1071,13 b' def ValidAuthPlugins():'
1074 1071 next_to_load=plugin)
1075 1072 raise formencode.Invalid(msg, value, state)
1076 1073 unique_names[plugin.name] = plugin
1077
1078 1074 return _validator
1079 1075
1080 1076
1081 def ValidPattern():
1077 def ValidPattern(localizer):
1078 _ = localizer
1082 1079
1083 class _Validator(formencode.validators.FancyValidator):
1080 class _validator(formencode.validators.FancyValidator):
1084 1081 messages = {
1085 1082 'bad_format': _(u'Url must start with http or /'),
1086 1083 }
@@ -1129,4 +1126,4 b' def ValidPattern():'
1129 1126 delete_patterns = [delete_patterns]
1130 1127 value['delete_patterns'] = delete_patterns
1131 1128 return value
1132 return _Validator
1129 return _validator
@@ -21,7 +21,6 b' import io'
21 21 import re
22 22 import datetime
23 23 import logging
24 import pylons
25 24 import Queue
26 25 import subprocess32
27 26 import os
@@ -36,14 +35,11 b' from threading import Thread'
36 35 from rhodecode.translation import _ as tsf
37 36 from rhodecode.config.jsroutes import generate_jsroutes_content
38 37 from rhodecode.lib import auth
38 from rhodecode.lib.base import get_auth_user
39
39 40
40 41 import rhodecode
41 42
42 from pylons.i18n.translation import _get_translator
43 from pylons.util import ContextObj
44 from routes.util import URLGenerator
45
46 from rhodecode.lib.base import attach_context_attributes, get_auth_user
47 43
48 44 log = logging.getLogger(__name__)
49 45
@@ -51,11 +47,6 b' log = logging.getLogger(__name__)'
51 47 def add_renderer_globals(event):
52 48 from rhodecode.lib import helpers
53 49
54 # NOTE(marcink):
55 # Put pylons stuff into the context. This will be removed as soon as
56 # migration to pyramid is finished.
57 event['c'] = pylons.tmpl_context
58
59 50 # TODO: When executed in pyramid view context the request is not available
60 51 # in the event. Find a better solution to get the request.
61 52 request = event['request'] or get_current_request()
@@ -68,12 +59,11 b' def add_renderer_globals(event):'
68 59
69 60 def add_localizer(event):
70 61 request = event.request
71 localizer = get_localizer(request)
62 localizer = request.localizer
72 63
73 64 def auto_translate(*args, **kwargs):
74 65 return localizer.translate(tsf(*args, **kwargs))
75 66
76 request.localizer = localizer
77 67 request.translate = auto_translate
78 68 request.plularize = localizer.pluralize
79 69
@@ -108,39 +98,6 b' def add_request_user_context(event):'
108 98 request.environ['rc_auth_user'] = auth_user
109 99
110 100
111 def add_pylons_context(event):
112 request = event.request
113
114 config = rhodecode.CONFIG
115 environ = request.environ
116 session = request.session
117
118 if hasattr(request, 'vcs_call'):
119 # skip vcs calls
120 return
121
122 # Setup pylons globals.
123 pylons.config._push_object(config)
124 pylons.request._push_object(request)
125 pylons.session._push_object(session)
126 pylons.translator._push_object(_get_translator(config.get('lang')))
127
128 pylons.url._push_object(URLGenerator(config['routes.map'], environ))
129 session_key = (
130 config['pylons.environ_config'].get('session', 'beaker.session'))
131 environ[session_key] = session
132
133 if hasattr(request, 'rpc_method'):
134 # skip api calls
135 return
136
137 # Setup the pylons context object ('c')
138 context = ContextObj()
139 context.rhodecode_user = request.user
140 attach_context_attributes(context, request, request.user.user_id)
141 pylons.tmpl_context._push_object(context)
142
143
144 101 def inject_app_settings(event):
145 102 settings = event.app.registry.settings
146 103 # inject info about available permissions
@@ -61,14 +61,14 b''
61 61 </td>
62 62 <td>
63 63 % if c.audit_log_entry.version == c.audit_log_entry.VERSION_1:
64 ${h.action_parser(l)[0]()}
64 ${h.action_parser(request, l)[0]()}
65 65 % else:
66 66 ${h.literal(c.audit_log_entry.action)}
67 67 % endif
68 68
69 69 <div class="journal_action_params">
70 70 % if c.audit_log_entry.version == c.audit_log_entry.VERSION_1:
71 ${h.literal(h.action_parser(l)[1]())}
71 ${h.literal(h.action_parser(request, l)[1]())}
72 72 % endif
73 73 </div>
74 74 </td>
@@ -14,7 +14,7 b''
14 14 <input type='submit' value="${_('filter')}" class="btn" />
15 15 ${_('Audit logs')} - ${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)}
16 16 ${h.end_form()}
17 <p class="tooltip filterexample" title="${h.tooltip(h.journal_filter_help(c.pyramid_request))}">${_('Example Queries')}</p>
17 <p class="tooltip filterexample" title="${h.tooltip(h.journal_filter_help(request))}">${_('Example Queries')}</p>
18 18 </%def>
19 19
20 20 <%def name="menu_bar_nav()">
@@ -26,14 +26,14 b''
26 26 </td>
27 27 <td class="td-journalaction">
28 28 % if l.version == l.VERSION_1:
29 ${h.action_parser(l)[0]()}
29 ${h.action_parser(request, l)[0]()}
30 30 % else:
31 31 ${h.literal(l.action)}
32 32 % endif
33 33
34 34 <div class="journal_action_params">
35 35 % if l.version == l.VERSION_1:
36 ${h.literal(h.action_parser(l)[1]())}
36 ${h.literal(h.action_parser(request, l)[1]())}
37 37 % endif
38 38 </div>
39 39 </td>
@@ -14,7 +14,7 b''
14 14 <input class="q_filter_box ${'' if c.filter_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.filter_term or ''}" placeholder="${_('audit filter...')}"/>
15 15 <input type='submit' value="${_('filter')}" class="btn" />
16 16 ${h.end_form()}
17 <p class="tooltip filterexample" style="position: inherit" title="${h.tooltip(h.journal_filter_help(c.pyramid_request))}">${_('Example Queries')}</p>
17 <p class="tooltip filterexample" style="position: inherit" title="${h.tooltip(h.journal_filter_help(request))}">${_('Example Queries')}</p>
18 18
19 19 <%include file="/admin/admin_log_base.mako" />
20 20
@@ -14,7 +14,7 b''
14 14 <input class="q_filter_box ${'' if c.filter_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.filter_term or ''}" placeholder="${_('audit filter...')}"/>
15 15 <input type='submit' value="${_('filter')}" class="btn" />
16 16 ${h.end_form()}
17 <p class="tooltip filterexample" style="position: inherit" title="${h.tooltip(h.journal_filter_help(c.pyramid_request))}">${_('Example Queries')}</p>
17 <p class="tooltip filterexample" style="position: inherit" title="${h.tooltip(h.journal_filter_help(request))}">${_('Example Queries')}</p>
18 18
19 19 <%include file="/admin/admin_log_base.mako" />
20 20
@@ -1,11 +1,8 b''
1 <%
2 from pyramid.renderers import render as pyramid_render
3 from pyramid.threadlocal import get_current_registry, get_current_request
4 pyramid_registry = get_current_registry()
5 %>
6 % for plugin, config in getattr(pyramid_registry, 'rhodecode_plugins', {}).items():
7 % if config['template_hooks'].get('plugin_init_template'):
8 ${pyramid_render(config['template_hooks'].get('plugin_init_template'),
9 {'config':config}, request=get_current_request(), package='rc_ae')|n}
10 % endif
1
2 % for plugin, config in getattr(request.registry, 'rhodecode_plugins', {}).items():
3 <% tmpl = config['template_hooks'].get('plugin_init_template') %>
4
5 % if tmpl:
6 <%include file="${tmpl}" args="config=config"/>
7 % endif
11 8 % endfor
@@ -1,3 +1,5 b''
1 <%page args="config"/>
2
1 3 <script>
2 4 var CHANNELSTREAM_URLS = ${config['url_gen'](request)|n};
3 5 %if request.registry.rhodecode_plugins['channelstream']['enabled'] and c.rhodecode_user.username != h.DEFAULT_USER:
@@ -15,7 +15,7 b''
15 15 ${_('Journal')} - ${_ungettext('%s entry', '%s entries', c.journal_pager.item_count) % (c.journal_pager.item_count)}
16 16 ${h.end_form()}
17 17 </h1>
18 <p class="tooltip filterexample" title="${h.tooltip(h.journal_filter_help(c.pyramid_request))}">${_('Example Queries')}</p>
18 <p class="tooltip filterexample" title="${h.tooltip(h.journal_filter_help(request))}">${_('Example Queries')}</p>
19 19 </%def>
20 20 <%def name="menu_bar_nav()">
21 21 ${self.menu_items(active='journal')}
@@ -14,8 +14,8 b''
14 14 %endif
15 15 <div class="journal_action_container">
16 16 % for entry in entries:
17 <div class="journal_icon"> ${h.action_parser(entry)[2]()}</div>
18 <div class="journal_action">${h.action_parser(entry)[0]()}</div>
17 <div class="journal_icon"> ${h.action_parser(request, entry)[2]()}</div>
18 <div class="journal_action">${h.action_parser(request, entry)[0]()}</div>
19 19 <div class="journal_repo">
20 20 <span class="journal_repo_name">
21 21 %if entry.repository is not None:
@@ -26,7 +26,7 b''
26 26 %endif
27 27 </span>
28 28 </div>
29 <div class="journal_action_params">${h.literal(h.action_parser(entry)[1]())}</div>
29 <div class="journal_action_params">${h.literal(h.action_parser(request, entry)[1]())}</div>
30 30 <div class="date">
31 31 ${h.age_component(entry.action_date, time_is_local=True)}
32 32 </div>
@@ -38,7 +38,7 b''
38 38 %endif
39 39 </div>
40 40 <div class="inner form">
41 ${h.form(request.route_path('login', _query={'came_from': came_from}), needs_csrf_token=False)}
41 ${h.form(request.route_path('login', _query={'came_from': c.came_from}), needs_csrf_token=False)}
42 42
43 43 <label for="username">${_('Username')}:</label>
44 44 ${h.text('username', class_='focus', value=defaults.get('username'))}
@@ -74,7 +74,7 b''
74 74 % endfor
75 75 <div class="field">
76 76 <p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Example Queries')}</p>
77 <pre id="search-help" style="display: none">${h.tooltip(h.search_filter_help(c.searcher, c.pyramid_request))}</pre>
77 <pre id="search-help" style="display: none">${h.tooltip(h.search_filter_help(c.searcher, request))}</pre>
78 78 </div>
79 79
80 80 <div class="field">${c.runtime}</div>
@@ -28,8 +28,6 b' from os.path import join as jn'
28 28
29 29 from tempfile import _RandomNameSequence
30 30
31 from pylons import url
32
33 31 import pytest
34 32
35 33 from rhodecode.model.db import User
@@ -43,7 +41,7 b' log = logging.getLogger(__name__)'
43 41
44 42 __all__ = [
45 43 'get_new_dir', 'TestController',
46 'url', 'link_to', 'ldap_lib_installed', 'clear_all_caches',
44 'link_to', 'ldap_lib_installed', 'clear_all_caches',
47 45 'assert_session_flash', 'login_user', 'no_newline_id_generator',
48 46 'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'SVN_REPO',
49 47 'NEW_HG_REPO', 'NEW_GIT_REPO',
@@ -55,8 +53,6 b' log = logging.getLogger(__name__)'
55 53 'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'SCM_TESTS',
56 54 ]
57 55
58 # Invoke websetup with the current config file
59 # SetupCommand('setup-app').run([config_file])
60 56
61 57 # SOME GLOBALS FOR TESTS
62 58 TEST_DIR = tempfile.gettempdir()
@@ -61,7 +61,7 b' def pytest_collection_modifyitems(sessio'
61 61
62 62 @pytest.fixture
63 63 def db_backend(
64 request, db_backend_name, pylons_config, tmpdir_factory):
64 request, db_backend_name, ini_config, tmpdir_factory):
65 65 basetemp = tmpdir_factory.getbasetemp().strpath
66 66 klass = _get_backend(db_backend_name)
67 67
@@ -69,7 +69,7 b' def db_backend('
69 69 connection_string = request.config.getoption(option_name) or None
70 70
71 71 return klass(
72 config_file=pylons_config, basetemp=basetemp,
72 config_file=ini_config, basetemp=basetemp,
73 73 connection_string=connection_string)
74 74
75 75
@@ -95,7 +95,7 b' def test_webook_parse_url_for_pull_reque'
95 95 'http://server.com/dev/dev-yyy']),
96 96 ])
97 97 def test_webook_parse_url_for_push_event(
98 pylonsapp, repo_push_event, base_data, template, expected_urls):
98 baseapp, repo_push_event, base_data, template, expected_urls):
99 99 base_data['push'] = {
100 100 'branches': [{'name': 'stable'}, {'name': 'dev'}],
101 101 'commits': [{'branch': 'stable', 'raw_id': 'stable-xxx'},
@@ -73,7 +73,7 b' def get_environ(url, request_method):'
73 73 ('/info/lfs/info/lfs/objects/batch', 'pull', 'POST'),
74 74
75 75 ])
76 def test_get_action(url, expected_action, request_method, pylonsapp, request_stub):
76 def test_get_action(url, expected_action, request_method, baseapp, request_stub):
77 77 app = simplegit.SimpleGit(application=None,
78 78 config={'auth_ret_code': '', 'base_path': ''},
79 79 registry=request_stub.registry)
@@ -102,7 +102,7 b' def test_get_action(url, expected_action'
102 102 ('/info/lfs/info/lfs/objects/batch', 'info/lfs', 'POST'),
103 103
104 104 ])
105 def test_get_repository_name(url, expected_repo_name, request_method, pylonsapp, request_stub):
105 def test_get_repository_name(url, expected_repo_name, request_method, baseapp, request_stub):
106 106 app = simplegit.SimpleGit(application=None,
107 107 config={'auth_ret_code': '', 'base_path': ''},
108 108 registry=request_stub.registry)
@@ -110,7 +110,7 b' def test_get_repository_name(url, expect'
110 110 get_environ(url, request_method))
111 111
112 112
113 def test_get_config(user_util, pylonsapp, request_stub):
113 def test_get_config(user_util, baseapp, request_stub):
114 114 repo = user_util.create_repo(repo_type='git')
115 115 app = simplegit.SimpleGit(application=None,
116 116 config={'auth_ret_code': '', 'base_path': ''},
@@ -130,7 +130,7 b' def test_get_config(user_util, pylonsapp'
130 130 assert git_config == expected_config
131 131
132 132
133 def test_create_wsgi_app_uses_scm_app_from_simplevcs(pylonsapp, request_stub):
133 def test_create_wsgi_app_uses_scm_app_from_simplevcs(baseapp, request_stub):
134 134 config = {
135 135 'auth_ret_code': '',
136 136 'base_path': '',
@@ -78,7 +78,7 b' def test_get_repository_name(url, expect'
78 78 assert expected_repo_name == app._get_repository_name(get_environ(url))
79 79
80 80
81 def test_get_config(user_util, pylonsapp, request_stub):
81 def test_get_config(user_util, baseapp, request_stub):
82 82 repo = user_util.create_repo(repo_type='git')
83 83 app = simplehg.SimpleHg(application=None,
84 84 config={'auth_ret_code': '', 'base_path': ''},
@@ -29,7 +29,7 b' from rhodecode.lib.middleware.simplesvn '
29 29
30 30 class TestSimpleSvn(object):
31 31 @pytest.fixture(autouse=True)
32 def simple_svn(self, pylonsapp, request_stub):
32 def simple_svn(self, baseapp, request_stub):
33 33 self.app = SimpleSvn(
34 34 application='None',
35 35 config={'auth_ret_code': '',
@@ -74,13 +74,13 b' class StubVCSController(simplevcs.Simple'
74 74
75 75
76 76 @pytest.fixture
77 def vcscontroller(pylonsapp, config_stub, request_stub):
77 def vcscontroller(baseapp, config_stub, request_stub):
78 78 config_stub.testing_securitypolicy()
79 79 config_stub.include('rhodecode.authentication')
80 80
81 81 controller = StubVCSController(
82 pylonsapp, pylonsapp.config, request_stub.registry)
83 app = HttpsFixup(controller, pylonsapp.config)
82 baseapp, baseapp.config, request_stub.registry)
83 app = HttpsFixup(controller, baseapp.config)
84 84 app = CustomTestApp(app)
85 85
86 86 _remove_default_user_from_query_cache()
@@ -134,10 +134,10 b' class StubFailVCSController(simplevcs.Si'
134 134
135 135
136 136 @pytest.fixture(scope='module')
137 def fail_controller(pylonsapp):
137 def fail_controller(baseapp):
138 138 controller = StubFailVCSController(
139 pylonsapp, pylonsapp.config, pylonsapp.config)
140 controller = HttpsFixup(controller, pylonsapp.config)
139 baseapp, baseapp.config, baseapp.config)
140 controller = HttpsFixup(controller, baseapp.config)
141 141 controller = CustomTestApp(controller)
142 142 return controller
143 143
@@ -152,18 +152,18 b' def test_provides_traceback_for_appenlig'
152 152 assert 'appenlight.__traceback' in response.request.environ
153 153
154 154
155 def test_provides_utils_scm_app_as_scm_app_by_default(pylonsapp, request_stub):
155 def test_provides_utils_scm_app_as_scm_app_by_default(baseapp, request_stub):
156 156 controller = StubVCSController(
157 pylonsapp, pylonsapp.config, request_stub.registry)
157 baseapp, baseapp.config, request_stub.registry)
158 158 assert controller.scm_app is scm_app_http
159 159
160 160
161 def test_allows_to_override_scm_app_via_config(pylonsapp, request_stub):
162 config = pylonsapp.config.copy()
161 def test_allows_to_override_scm_app_via_config(baseapp, request_stub):
162 config = baseapp.config.copy()
163 163 config['vcs.scm_app_implementation'] = (
164 164 'rhodecode.tests.lib.middleware.mock_scm_app')
165 165 controller = StubVCSController(
166 pylonsapp, config, request_stub.registry)
166 baseapp, config, request_stub.registry)
167 167 assert controller.scm_app is mock_scm_app
168 168
169 169
@@ -219,13 +219,13 b' class TestShadowRepoRegularExpression(ob'
219 219 class TestShadowRepoExposure(object):
220 220
221 221 def test_pull_on_shadow_repo_propagates_to_wsgi_app(
222 self, pylonsapp, request_stub):
222 self, baseapp, request_stub):
223 223 """
224 224 Check that a pull action to a shadow repo is propagated to the
225 225 underlying wsgi app.
226 226 """
227 227 controller = StubVCSController(
228 pylonsapp, pylonsapp.config, request_stub.registry)
228 baseapp, baseapp.config, request_stub.registry)
229 229 controller._check_ssl = mock.Mock()
230 230 controller.is_shadow_repo = True
231 231 controller._action = 'pull'
@@ -244,13 +244,13 b' class TestShadowRepoExposure(object):'
244 244 # Assert that we got the response from the wsgi app.
245 245 assert response_body == controller.stub_response_body
246 246
247 def test_pull_on_shadow_repo_that_is_missing(self, pylonsapp, request_stub):
247 def test_pull_on_shadow_repo_that_is_missing(self, baseapp, request_stub):
248 248 """
249 249 Check that a pull action to a shadow repo is propagated to the
250 250 underlying wsgi app.
251 251 """
252 252 controller = StubVCSController(
253 pylonsapp, pylonsapp.config, request_stub.registry)
253 baseapp, baseapp.config, request_stub.registry)
254 254 controller._check_ssl = mock.Mock()
255 255 controller.is_shadow_repo = True
256 256 controller._action = 'pull'
@@ -269,12 +269,12 b' class TestShadowRepoExposure(object):'
269 269 # Assert that we got the response from the wsgi app.
270 270 assert '404 Not Found' in response_body
271 271
272 def test_push_on_shadow_repo_raises(self, pylonsapp, request_stub):
272 def test_push_on_shadow_repo_raises(self, baseapp, request_stub):
273 273 """
274 274 Check that a push action to a shadow repo is aborted.
275 275 """
276 276 controller = StubVCSController(
277 pylonsapp, pylonsapp.config, request_stub.registry)
277 baseapp, baseapp.config, request_stub.registry)
278 278 controller._check_ssl = mock.Mock()
279 279 controller.is_shadow_repo = True
280 280 controller._action = 'push'
@@ -293,14 +293,14 b' class TestShadowRepoExposure(object):'
293 293 # Assert that a 406 error is returned.
294 294 assert '406 Not Acceptable' in response_body
295 295
296 def test_set_repo_names_no_shadow(self, pylonsapp, request_stub):
296 def test_set_repo_names_no_shadow(self, baseapp, request_stub):
297 297 """
298 298 Check that the set_repo_names method sets all names to the one returned
299 299 by the _get_repository_name method on a request to a non shadow repo.
300 300 """
301 301 environ_stub = {}
302 302 controller = StubVCSController(
303 pylonsapp, pylonsapp.config, request_stub.registry)
303 baseapp, baseapp.config, request_stub.registry)
304 304 controller._name = 'RepoGroup/MyRepo'
305 305 controller.set_repo_names(environ_stub)
306 306 assert not controller.is_shadow_repo
@@ -310,7 +310,7 b' class TestShadowRepoExposure(object):'
310 310 controller._get_repository_name(environ_stub))
311 311
312 312 def test_set_repo_names_with_shadow(
313 self, pylonsapp, pr_util, config_stub, request_stub):
313 self, baseapp, pr_util, config_stub, request_stub):
314 314 """
315 315 Check that the set_repo_names method sets correct names on a request
316 316 to a shadow repo.
@@ -324,7 +324,7 b' class TestShadowRepoExposure(object):'
324 324 pr_segment=TestShadowRepoRegularExpression.pr_segment,
325 325 shadow_segment=TestShadowRepoRegularExpression.shadow_segment)
326 326 controller = StubVCSController(
327 pylonsapp, pylonsapp.config, request_stub.registry)
327 baseapp, baseapp.config, request_stub.registry)
328 328 controller._name = shadow_url
329 329 controller.set_repo_names({})
330 330
@@ -340,7 +340,7 b' class TestShadowRepoExposure(object):'
340 340 assert controller.is_shadow_repo
341 341
342 342 def test_set_repo_names_with_shadow_but_missing_pr(
343 self, pylonsapp, pr_util, config_stub, request_stub):
343 self, baseapp, pr_util, config_stub, request_stub):
344 344 """
345 345 Checks that the set_repo_names method enforces matching target repos
346 346 and pull request IDs.
@@ -352,7 +352,7 b' class TestShadowRepoExposure(object):'
352 352 pr_segment=TestShadowRepoRegularExpression.pr_segment,
353 353 shadow_segment=TestShadowRepoRegularExpression.shadow_segment)
354 354 controller = StubVCSController(
355 pylonsapp, pylonsapp.config, request_stub.registry)
355 baseapp, baseapp.config, request_stub.registry)
356 356 controller._name = shadow_url
357 357 controller.set_repo_names({})
358 358
@@ -108,8 +108,7 b' class TestVCSMiddleware(object):'
108 108 config = {'appenlight': False, 'vcs.backends': ['svn']}
109 109 registry = Mock()
110 110 middleware = vcs.VCSMiddleware(
111 application, config=config,
112 appenlight_client=None, registry=registry)
111 application, registry, config, appenlight_client=None)
113 112 middleware.use_gzip = False
114 113
115 114 with patch.object(SimpleSvn, '_is_svn_enabled') as mock_method:
@@ -128,8 +127,7 b' class TestVCSMiddleware(object):'
128 127 config = {'appenlight': False, 'vcs.backends': ['svn']}
129 128 registry = Mock()
130 129 middleware = vcs.VCSMiddleware(
131 application, config=config,
132 appenlight_client=None, registry=registry)
130 application, registry, config, appenlight_client=None)
133 131 middleware.use_gzip = False
134 132
135 133 with patch.object(SimpleSvn, '_is_svn_enabled') as mock_method:
@@ -31,19 +31,13 b' def test_vcs_available_returns_summary_p'
31 31
32 32
33 33 @pytest.mark.usefixtures('autologin_user', 'app')
34 def test_vcs_unavailable_returns_vcs_error_page(app, backend, app_settings):
34 def test_vcs_unavailable_returns_vcs_error_page(app, backend):
35 35 from rhodecode.lib.vcs.exceptions import VCSCommunicationError
36 from rhodecode.lib.middleware.error_handling import (
37 PylonsErrorHandlingMiddleware)
38 36
39 37 # Depending on the used VCSServer protocol we have to patch a different
40 38 # RemoteRepo class to raise an exception. For the test it doesn't matter
41 39 # if http is used, it just requires the exception to be raised.
42 vcs_protocol = app_settings['vcs.server.protocol']
43 if vcs_protocol == 'http':
44 from rhodecode.lib.vcs.client_http import RemoteRepo
45 else:
46 pytest.fail('Unknown VCS server protocol: "{}"'.format(vcs_protocol))
40 from rhodecode.lib.vcs.client_http import RemoteRepo
47 41
48 42 url = '/{repo_name}'.format(repo_name=backend.repo.repo_name)
49 43
@@ -29,6 +29,6 b' from rhodecode.model.db import UserLog'
29 29 'user_closed_pull_request',
30 30 'user_merged_pull_request'
31 31 ])
32 def test_action_map_pr_values(pylonsapp, pr_key):
32 def test_action_map_pr_values(baseapp, pr_key):
33 33 parser = ActionParser(UserLog(action="test:test"))
34 34 assert pr_key in parser.action_map
@@ -26,7 +26,7 b' from rhodecode.model import db'
26 26
27 27
28 28 @pytest.fixture
29 def db_manage(pylonsapp):
29 def db_manage(baseapp):
30 30 db_manage = DbManage(
31 31 log_sql=True, dbconf='fake', root='fake', tests=False,
32 32 cli_args={}, SESSION=db.Session())
@@ -34,7 +34,7 b' def db_manage(pylonsapp):'
34 34
35 35
36 36 @pytest.fixture(autouse=True)
37 def session_rollback(pylonsapp, request):
37 def session_rollback(baseapp, request):
38 38 """
39 39 Rollback the database session after the test run.
40 40
@@ -27,7 +27,7 b' import pytest'
27 27
28 28 from rhodecode.lib.ext_json import json
29 29 from rhodecode.lib.ext_json import formatted_json
30 from pylons.i18n.translation import _, ungettext
30 from rhodecode.translation import _, _pluralize
31 31
32 32
33 33 class Timezone(datetime.tzinfo):
@@ -158,9 +158,9 b' def test_formatted_json():'
158 158 assert formatted_json(data) == expected_data
159 159
160 160
161 def test_pylons_lazy_translation_string(pylonsapp):
161 def test_pylons_lazy_translation_string(baseapp):
162 162 data = {'label': _('hello')}
163 data2 = {'label2': ungettext('singular', 'plural', 1)}
163 data2 = {'label2': _pluralize('singular', 'plural', 1)}
164 164
165 165 assert json.dumps(data) == '{"label": "hello"}'
166 166 assert json.dumps(data2) == '{"label2": "singular"}'
@@ -22,8 +22,6 b' import copy'
22 22 import mock
23 23 import pytest
24 24
25 from pylons.util import ContextObj
26
27 25 from rhodecode.lib import helpers
28 26 from rhodecode.lib.utils2 import AttributeDict
29 27 from rhodecode.model.settings import IssueTrackerSettingsModel
@@ -188,8 +186,9 b' def test_process_patterns_non_existent_r'
188 186 assert processed_text == expected_text
189 187
190 188
191 def test_get_visual_attr(pylonsapp):
192 c = ContextObj()
189 def test_get_visual_attr(baseapp):
190 from rhodecode.apps._base import TemplateArgs
191 c = TemplateArgs()
193 192 assert None is helpers.get_visual_attr(c, 'fakse')
194 193
195 194 # emulate the c.visual behaviour
@@ -142,7 +142,7 b' def test_mention_extractor(text, expecte'
142 142 ({'months': -1, 'days': -2}, u'1m, 2d ago', {'short_format': True}),
143 143 ({'years': -1, 'months': -1}, u'1y, 1m ago', {'short_format': True}),
144 144 ])
145 def test_age(age_args, expected, kw, pylonsapp):
145 def test_age(age_args, expected, kw, baseapp):
146 146 from rhodecode.lib.utils2 import age
147 147 from dateutil import relativedelta
148 148 n = datetime.datetime(year=2012, month=5, day=17)
@@ -174,7 +174,7 b' def test_age(age_args, expected, kw, pyl'
174 174 ({'months': 1, 'days': 1}, u'in 1m, 1d', {'short_format': True}),
175 175 ({'years': 1, 'months': 1}, u'in 1y, 1m', {'short_format': True}),
176 176 ])
177 def test_age_in_future(age_args, expected, kw, pylonsapp):
177 def test_age_in_future(age_args, expected, kw, baseapp):
178 178 from rhodecode.lib.utils2 import age
179 179 from dateutil import relativedelta
180 180 n = datetime.datetime(year=2012, month=5, day=17)
@@ -551,7 +551,7 b' def test_get_repo_by_id(test, expected):'
551 551 ("test_non_asci_ąćę", None),
552 552 (u"test_non_asci_unicode_ąćę", None),
553 553 ])
554 def test_invalidation_context(pylonsapp, test_repo_name, repo_type):
554 def test_invalidation_context(baseapp, test_repo_name, repo_type):
555 555 from beaker.cache import cache_region
556 556 from rhodecode.lib import caches
557 557 from rhodecode.model.db import CacheKey
@@ -581,7 +581,7 b' def test_invalidation_context(pylonsapp,'
581 581 assert isinstance(context, caches.ActiveRegionCache)
582 582
583 583
584 def test_invalidation_context_exception_in_compute(pylonsapp):
584 def test_invalidation_context_exception_in_compute(baseapp):
585 585 from rhodecode.model.db import CacheKey
586 586 from beaker.cache import cache_region
587 587
@@ -600,7 +600,7 b' def test_invalidation_context_exception_'
600 600
601 601
602 602 @pytest.mark.parametrize('execution_number', range(5))
603 def test_cache_invalidation_race_condition(execution_number, pylonsapp):
603 def test_cache_invalidation_race_condition(execution_number, baseapp):
604 604 import time
605 605 from beaker.cache import cache_region
606 606 from rhodecode.model.db import CacheKey
@@ -104,7 +104,7 b' HG_HOOKS = frozenset('
104 104 ([HOOK_PULL], [HOOK_PRE_PUSH, HOOK_PRETX_PUSH, HOOK_PUSH, HOOK_REPO_SIZE,
105 105 HOOK_PUSH_KEY]),
106 106 ])
107 def test_make_db_config_hg_hooks(pylonsapp, request, disabled_hooks,
107 def test_make_db_config_hg_hooks(baseapp, request, disabled_hooks,
108 108 expected_hooks):
109 109 disable_hooks(request, disabled_hooks)
110 110
@@ -130,25 +130,25 b' def test_get_enabled_hook_classes(disabl'
130 130 assert sorted(result) == expected_hooks
131 131
132 132
133 def test_get_filesystem_repos_finds_repos(tmpdir, pylonsapp):
133 def test_get_filesystem_repos_finds_repos(tmpdir, baseapp):
134 134 _stub_git_repo(tmpdir.ensure('repo', dir=True))
135 135 repos = list(utils.get_filesystem_repos(str(tmpdir)))
136 136 assert repos == [('repo', ('git', tmpdir.join('repo')))]
137 137
138 138
139 def test_get_filesystem_repos_skips_directories(tmpdir, pylonsapp):
139 def test_get_filesystem_repos_skips_directories(tmpdir, baseapp):
140 140 tmpdir.ensure('not-a-repo', dir=True)
141 141 repos = list(utils.get_filesystem_repos(str(tmpdir)))
142 142 assert repos == []
143 143
144 144
145 def test_get_filesystem_repos_skips_directories_with_repos(tmpdir, pylonsapp):
145 def test_get_filesystem_repos_skips_directories_with_repos(tmpdir, baseapp):
146 146 _stub_git_repo(tmpdir.ensure('subdir/repo', dir=True))
147 147 repos = list(utils.get_filesystem_repos(str(tmpdir)))
148 148 assert repos == []
149 149
150 150
151 def test_get_filesystem_repos_finds_repos_in_subdirectories(tmpdir, pylonsapp):
151 def test_get_filesystem_repos_finds_repos_in_subdirectories(tmpdir, baseapp):
152 152 _stub_git_repo(tmpdir.ensure('subdir/repo', dir=True))
153 153 repos = list(utils.get_filesystem_repos(str(tmpdir), recursive=True))
154 154 assert repos == [('subdir/repo', ('git', tmpdir.join('subdir', 'repo')))]
@@ -34,7 +34,7 b' def test_obfuscate_url_pw():'
34 34 'www.test.com', 'test.com', 'test.co.uk', '192.168.1.3'])
35 35 @pytest.mark.parametrize('port', [None, '80', '443', '999'])
36 36 @pytest.mark.parametrize('script_path', [None, '/', '/prefix', '/prefix/more'])
37 def test_routes_generator(pylonsapp, scheme, domain, port, script_path):
37 def test_routes_generator(baseapp, scheme, domain, port, script_path):
38 38 server_url = '%s://%s' % (scheme, domain)
39 39 if port is not None:
40 40 server_url += ':' + port
@@ -44,7 +44,7 b' def repo_name(backend_hg):'
44 44 class TestPermissions(object):
45 45
46 46 @pytest.fixture(scope='class', autouse=True)
47 def default_permissions(self, request, pylonsapp):
47 def default_permissions(self, request, baseapp):
48 48 # recreate default user to get a clean start
49 49 PermissionModel().create_default_user_permissions(
50 50 user=User.DEFAULT_USER, force=True)
@@ -475,7 +475,7 b' def merge_extras(user_regular):'
475 475 class TestUpdateCommentHandling(object):
476 476
477 477 @pytest.fixture(autouse=True, scope='class')
478 def enable_outdated_comments(self, request, pylonsapp):
478 def enable_outdated_comments(self, request, baseapp):
479 479 config_patch = mock.patch.dict(
480 480 'rhodecode.CONFIG', {'rhodecode_use_outdated_comments': True})
481 481 config_patch.start()
@@ -64,7 +64,7 b" def permissions_setup_func(group_name='g"
64 64
65 65
66 66 @pytest.fixture(scope='module', autouse=True)
67 def prepare(request, pylonsapp):
67 def prepare(request, baseapp):
68 68 global test_u1_id, _get_repo_perms, _get_group_perms
69 69 test_u1 = _create_project_tree()
70 70 Session().commit()
@@ -115,7 +115,7 b' class TestGetUsers(object):'
115 115
116 116
117 117 @pytest.fixture
118 def test_user(request, pylonsapp):
118 def test_user(request, baseapp):
119 119 usr = UserModel().create_or_update(
120 120 username=u'test_user',
121 121 password=u'qweqwe',
@@ -38,11 +38,18 b' from rhodecode.tests.fixture import Fixt'
38 38
39 39 fixture = Fixture()
40 40
41 pytestmark = pytest.mark.usefixtures('pylonsapp')
41 pytestmark = pytest.mark.usefixtures('baseapp')
42 42
43 43
44 def test_Message_extractor():
45 validator = v.ValidUsername()
44 @pytest.fixture
45 def localizer():
46 def func(msg):
47 return msg
48 return func
49
50
51 def test_Message_extractor(localizer):
52 validator = v.ValidUsername(localizer)
46 53 pytest.raises(formencode.Invalid, validator.to_python, 'default')
47 54
48 55 class StateObj(object):
@@ -52,8 +59,8 b' def test_Message_extractor():'
52 59 formencode.Invalid, validator.to_python, 'default', StateObj)
53 60
54 61
55 def test_ValidUsername():
56 validator = v.ValidUsername()
62 def test_ValidUsername(localizer):
63 validator = v.ValidUsername(localizer)
57 64
58 65 pytest.raises(formencode.Invalid, validator.to_python, 'default')
59 66 pytest.raises(formencode.Invalid, validator.to_python, 'new_user')
@@ -62,18 +69,18 b' def test_ValidUsername():'
62 69 formencode.Invalid, validator.to_python, TEST_USER_ADMIN_LOGIN)
63 70 assert 'test' == validator.to_python('test')
64 71
65 validator = v.ValidUsername(edit=True, old_data={'user_id': 1})
72 validator = v.ValidUsername(localizer, edit=True, old_data={'user_id': 1})
66 73
67 74
68 def test_ValidRepoUser():
69 validator = v.ValidRepoUser()
75 def test_ValidRepoUser(localizer):
76 validator = v.ValidRepoUser(localizer)
70 77 pytest.raises(formencode.Invalid, validator.to_python, 'nouser')
71 78 assert TEST_USER_ADMIN_LOGIN == \
72 79 validator.to_python(TEST_USER_ADMIN_LOGIN)
73 80
74 81
75 def test_ValidUserGroup():
76 validator = v.ValidUserGroup()
82 def test_ValidUserGroup(localizer):
83 validator = v.ValidUserGroup(localizer)
77 84 pytest.raises(formencode.Invalid, validator.to_python, 'default')
78 85 pytest.raises(formencode.Invalid, validator.to_python, '.,')
79 86
@@ -82,7 +89,7 b' def test_ValidUserGroup():'
82 89 Session().commit()
83 90 pytest.raises(formencode.Invalid, validator.to_python, 'test')
84 91 assert gr.users_group_id is not None
85 validator = v.ValidUserGroup(
92 validator = v.ValidUserGroup(localizer,
86 93 edit=True,
87 94 old_data={'users_group_id': gr2.users_group_id})
88 95
@@ -109,24 +116,24 b' def repo_group(request):'
109 116 return gr
110 117
111 118
112 def test_ValidRepoGroup_same_name_as_repo():
113 validator = v.ValidRepoGroup()
119 def test_ValidRepoGroup_same_name_as_repo(localizer):
120 validator = v.ValidRepoGroup(localizer)
114 121 with pytest.raises(formencode.Invalid) as excinfo:
115 122 validator.to_python({'group_name': HG_REPO})
116 123 expected_msg = 'Repository with name "vcs_test_hg" already exists'
117 124 assert expected_msg in str(excinfo.value)
118 125
119 126
120 def test_ValidRepoGroup_group_exists(repo_group):
121 validator = v.ValidRepoGroup()
127 def test_ValidRepoGroup_group_exists(localizer, repo_group):
128 validator = v.ValidRepoGroup(localizer)
122 129 with pytest.raises(formencode.Invalid) as excinfo:
123 130 validator.to_python({'group_name': repo_group.group_name})
124 131 expected_msg = 'Group "test_gr" already exists'
125 132 assert expected_msg in str(excinfo.value)
126 133
127 134
128 def test_ValidRepoGroup_invalid_parent(repo_group):
129 validator = v.ValidRepoGroup(edit=True,
135 def test_ValidRepoGroup_invalid_parent(localizer, repo_group):
136 validator = v.ValidRepoGroup(localizer, edit=True,
130 137 old_data={'group_id': repo_group.group_id})
131 138 with pytest.raises(formencode.Invalid) as excinfo:
132 139 validator.to_python({
@@ -137,8 +144,8 b' def test_ValidRepoGroup_invalid_parent(r'
137 144 assert expected_msg in str(excinfo.value)
138 145
139 146
140 def test_ValidRepoGroup_edit_group_no_root_permission(repo_group):
141 validator = v.ValidRepoGroup(
147 def test_ValidRepoGroup_edit_group_no_root_permission(localizer, repo_group):
148 validator = v.ValidRepoGroup(localizer,
142 149 edit=True, old_data={'group_id': repo_group.group_id},
143 150 can_create_in_root=False)
144 151
@@ -156,15 +163,15 b' def test_ValidRepoGroup_edit_group_no_ro'
156 163 validator.to_python({'enable_locking': 'true', 'group_parent_id': '-1'})
157 164
158 165
159 def test_ValidPassword():
160 validator = v.ValidPassword()
166 def test_ValidPassword(localizer):
167 validator = v.ValidPassword(localizer)
161 168 assert 'lol' == validator.to_python('lol')
162 169 assert None == validator.to_python(None)
163 170 pytest.raises(formencode.Invalid, validator.to_python, 'ąćżź')
164 171
165 172
166 def test_ValidPasswordsMatch():
167 validator = v.ValidPasswordsMatch()
173 def test_ValidPasswordsMatch(localizer):
174 validator = v.ValidPasswordsMatch(localizer)
168 175 pytest.raises(
169 176 formencode.Invalid,
170 177 validator.to_python, {'password': 'pass',
@@ -184,11 +191,11 b' def test_ValidPasswordsMatch():'
184 191 'password_confirmation': 'pass'})
185 192
186 193
187 def test_ValidAuth(config_stub):
194 def test_ValidAuth(localizer, config_stub):
188 195 config_stub.testing_securitypolicy()
189 196 config_stub.include('rhodecode.authentication')
190 197
191 validator = v.ValidAuth()
198 validator = v.ValidAuth(localizer)
192 199 valid_creds = {
193 200 'username': TEST_USER_REGULAR2_LOGIN,
194 201 'password': TEST_USER_REGULAR2_PASS,
@@ -202,17 +209,14 b' def test_ValidAuth(config_stub):'
202 209 formencode.Invalid, validator.to_python, invalid_creds)
203 210
204 211
205 # TODO: johbo: Fix or wipe this test
206 def test_ValidAuthToken():
207 validator = v.ValidAuthToken()
208 # this is untestable without a threadlocal
209 # pytest.raises(formencode.Invalid,
210 # validator.to_python, 'BadToken')
212 def test_ValidAuthToken(localizer):
213 validator = v.ValidAuthToken(localizer)
214 pytest.raises(formencode.Invalid, validator.to_python, 'BadToken')
211 215 validator
212 216
213 217
214 def test_ValidRepoName():
215 validator = v.ValidRepoName()
218 def test_ValidRepoName(localizer):
219 validator = v.ValidRepoName(localizer)
216 220
217 221 pytest.raises(
218 222 formencode.Invalid, validator.to_python, {'repo_name': ''})
@@ -232,7 +236,7 b' def test_ValidRepoName():'
232 236 # 'repo_group': gr.group_id})
233 237
234 238
235 def test_ValidForkName():
239 def test_ValidForkName(localizer):
236 240 # this uses ValidRepoName validator
237 241 assert True
238 242
@@ -241,37 +245,26 b' def test_ValidForkName():'
241 245 ('ala ma kota', 'ala-ma-kota'), ('@nooo', 'nooo'),
242 246 ('$!haha lolz !', 'haha-lolz'), ('$$$$$', ''), ('{}OK!', 'OK'),
243 247 ('/]re po', 're-po')])
244 def test_SlugifyName(name, expected):
245 validator = v.SlugifyName()
248 def test_SlugifyName(name, expected, localizer):
249 validator = v.SlugifyName(localizer)
246 250 assert expected == validator.to_python(name)
247 251
248 252
249 def test_ValidForkType():
250 validator = v.ValidForkType(old_data={'repo_type': 'hg'})
253 def test_ValidForkType(localizer):
254 validator = v.ValidForkType(localizer, old_data={'repo_type': 'hg'})
251 255 assert 'hg' == validator.to_python('hg')
252 256 pytest.raises(formencode.Invalid, validator.to_python, 'git')
253 257
254 258
255 def test_ValidSettings():
256 validator = v.ValidSettings()
257 assert {'pass': 'pass'} == \
258 validator.to_python(value={'user': 'test',
259 'pass': 'pass'})
260
261 assert {'user2': 'test', 'pass': 'pass'} == \
262 validator.to_python(value={'user2': 'test',
263 'pass': 'pass'})
264
265
266 def test_ValidPath():
267 validator = v.ValidPath()
259 def test_ValidPath(localizer):
260 validator = v.ValidPath(localizer)
268 261 assert TESTS_TMP_PATH == validator.to_python(TESTS_TMP_PATH)
269 262 pytest.raises(
270 263 formencode.Invalid, validator.to_python, '/no_such_dir')
271 264
272 265
273 def test_UniqSystemEmail():
274 validator = v.UniqSystemEmail(old_data={})
266 def test_UniqSystemEmail(localizer):
267 validator = v.UniqSystemEmail(localizer, old_data={})
275 268
276 269 assert 'mail@python.org' == validator.to_python('MaiL@Python.org')
277 270
@@ -279,17 +272,17 b' def test_UniqSystemEmail():'
279 272 pytest.raises(formencode.Invalid, validator.to_python, email)
280 273
281 274
282 def test_ValidSystemEmail():
283 validator = v.ValidSystemEmail()
275 def test_ValidSystemEmail(localizer):
276 validator = v.ValidSystemEmail(localizer)
284 277 email = TEST_USER_REGULAR2_EMAIL
285 278
286 279 assert email == validator.to_python(email)
287 280 pytest.raises(formencode.Invalid, validator.to_python, 'err')
288 281
289 282
290 def test_NotReviewedRevisions():
283 def test_NotReviewedRevisions(localizer):
291 284 repo_id = Repository.get_by_repo_name(HG_REPO).repo_id
292 validator = v.NotReviewedRevisions(repo_id)
285 validator = v.NotReviewedRevisions(localizer, repo_id)
293 286 rev = '0' * 40
294 287 # add status for a rev, that should throw an error because it is already
295 288 # reviewed
@@ -88,7 +88,7 b' class RcWebServer(object):'
88 88
89 89
90 90 @pytest.fixture(scope="module")
91 def rcextensions(request, pylonsapp, tmpdir_factory):
91 def rcextensions(request, baseapp, tmpdir_factory):
92 92 """
93 93 Installs a testing rcextensions pack to ensure they work as expected.
94 94 """
@@ -114,7 +114,7 b' def rcextensions(request, pylonsapp, tmp'
114 114
115 115
116 116 @pytest.fixture(scope="module")
117 def repos(request, pylonsapp):
117 def repos(request, baseapp):
118 118 """Create a copy of each test repo in a repo group."""
119 119 fixture = Fixture()
120 120 repo_group = fixture.create_repo_group(REPO_GROUP)
@@ -146,7 +146,7 b' def rc_web_server_config(testini_factory'
146 146
147 147 @pytest.fixture(scope="module")
148 148 def rc_web_server(
149 request, pylonsapp, rc_web_server_config, repos, rcextensions):
149 request, baseapp, rc_web_server_config, repos, rcextensions):
150 150 """
151 151 Run the web server as a subprocess.
152 152
@@ -188,7 +188,7 b' def rc_web_server('
188 188
189 189
190 190 @pytest.fixture
191 def disable_locking(pylonsapp):
191 def disable_locking(baseapp):
192 192 r = Repository.get_by_repo_name(GIT_REPO)
193 193 Repository.unlock(r)
194 194 r.enable_locking = False
@@ -203,7 +203,7 b' def disable_locking(pylonsapp):'
203 203
204 204
205 205 @pytest.fixture
206 def enable_auth_plugins(request, pylonsapp, csrf_token):
206 def enable_auth_plugins(request, baseapp, csrf_token):
207 207 """
208 208 Return a factory object that when called, allows to control which
209 209 authentication plugins are enabled.
@@ -110,7 +110,6 b' def pytest_addoption(parser):'
110 110 def pytest_configure(config):
111 111 # Appy the kombu patch early on, needed for test discovery on Python 2.7.11
112 112 from rhodecode.config import patches
113 patches.kombu_1_5_1_python_2_7_11()
114 113
115 114
116 115 def pytest_collection_modifyitems(session, config, items):
@@ -221,9 +220,9 b' def http_environ(http_host_stub):'
221 220
222 221
223 222 @pytest.fixture(scope='function')
224 def app(request, config_stub, pylonsapp, http_environ):
223 def app(request, config_stub, baseapp, http_environ):
225 224 app = CustomTestApp(
226 pylonsapp,
225 baseapp,
227 226 extra_environ=http_environ)
228 227 if request.cls:
229 228 request.cls.app = app
@@ -231,31 +230,14 b' def app(request, config_stub, pylonsapp,'
231 230
232 231
233 232 @pytest.fixture(scope='session')
234 def app_settings(pylonsapp, pylons_config):
233 def app_settings(baseapp, ini_config):
235 234 """
236 235 Settings dictionary used to create the app.
237 236
238 237 Parses the ini file and passes the result through the sanitize and apply
239 238 defaults mechanism in `rhodecode.config.middleware`.
240 239 """
241 from paste.deploy.loadwsgi import loadcontext, APP
242 from rhodecode.config.middleware import (
243 sanitize_settings_and_apply_defaults)
244 context = loadcontext(APP, 'config:' + pylons_config)
245 settings = sanitize_settings_and_apply_defaults(context.config())
246 return settings
247
248
249 @pytest.fixture(scope='session')
250 def db(app_settings):
251 """
252 Initializes the database connection.
253
254 It uses the same settings which are used to create the ``pylonsapp`` or
255 ``app`` fixtures.
256 """
257 from rhodecode.config.utils import initialize_database
258 initialize_database(app_settings)
240 return baseapp.config.get_settings()
259 241
260 242
261 243 LoginData = collections.namedtuple('LoginData', ('csrf_token', 'user'))
@@ -306,8 +288,8 b' def real_crypto_backend(monkeypatch):'
306 288
307 289
308 290 @pytest.fixture(scope='class')
309 def index_location(request, pylonsapp):
310 index_location = pylonsapp.config['app_conf']['search.location']
291 def index_location(request, baseapp):
292 index_location = baseapp.config.get_settings()['search.location']
311 293 if request.cls:
312 294 request.cls.index_location = index_location
313 295 return index_location
@@ -421,7 +403,7 b' class TestRepoContainer(object):'
421 403
422 404
423 405 @pytest.fixture
424 def backend(request, backend_alias, pylonsapp, test_repo):
406 def backend(request, backend_alias, baseapp, test_repo):
425 407 """
426 408 Parametrized fixture which represents a single backend implementation.
427 409
@@ -449,18 +431,18 b' def backend(request, backend_alias, pylo'
449 431
450 432
451 433 @pytest.fixture
452 def backend_git(request, pylonsapp, test_repo):
453 return backend(request, 'git', pylonsapp, test_repo)
434 def backend_git(request, baseapp, test_repo):
435 return backend(request, 'git', baseapp, test_repo)
454 436
455 437
456 438 @pytest.fixture
457 def backend_hg(request, pylonsapp, test_repo):
458 return backend(request, 'hg', pylonsapp, test_repo)
439 def backend_hg(request, baseapp, test_repo):
440 return backend(request, 'hg', baseapp, test_repo)
459 441
460 442
461 443 @pytest.fixture
462 def backend_svn(request, pylonsapp, test_repo):
463 return backend(request, 'svn', pylonsapp, test_repo)
444 def backend_svn(request, baseapp, test_repo):
445 return backend(request, 'svn', baseapp, test_repo)
464 446
465 447
466 448 @pytest.fixture
@@ -672,7 +654,7 b' class Backend(object):'
672 654
673 655
674 656 @pytest.fixture
675 def vcsbackend(request, backend_alias, tests_tmp_path, pylonsapp, test_repo):
657 def vcsbackend(request, backend_alias, tests_tmp_path, baseapp, test_repo):
676 658 """
677 659 Parametrized fixture which represents a single vcs backend implementation.
678 660
@@ -700,18 +682,18 b' def vcsbackend(request, backend_alias, t'
700 682
701 683
702 684 @pytest.fixture
703 def vcsbackend_git(request, tests_tmp_path, pylonsapp, test_repo):
704 return vcsbackend(request, 'git', tests_tmp_path, pylonsapp, test_repo)
685 def vcsbackend_git(request, tests_tmp_path, baseapp, test_repo):
686 return vcsbackend(request, 'git', tests_tmp_path, baseapp, test_repo)
705 687
706 688
707 689 @pytest.fixture
708 def vcsbackend_hg(request, tests_tmp_path, pylonsapp, test_repo):
709 return vcsbackend(request, 'hg', tests_tmp_path, pylonsapp, test_repo)
690 def vcsbackend_hg(request, tests_tmp_path, baseapp, test_repo):
691 return vcsbackend(request, 'hg', tests_tmp_path, baseapp, test_repo)
710 692
711 693
712 694 @pytest.fixture
713 def vcsbackend_svn(request, tests_tmp_path, pylonsapp, test_repo):
714 return vcsbackend(request, 'svn', tests_tmp_path, pylonsapp, test_repo)
695 def vcsbackend_svn(request, tests_tmp_path, baseapp, test_repo):
696 return vcsbackend(request, 'svn', tests_tmp_path, baseapp, test_repo)
715 697
716 698
717 699 @pytest.fixture
@@ -1093,7 +1075,7 b' class PRTestUtility(object):'
1093 1075
1094 1076
1095 1077 @pytest.fixture
1096 def user_admin(pylonsapp):
1078 def user_admin(baseapp):
1097 1079 """
1098 1080 Provides the default admin test user as an instance of `db.User`.
1099 1081 """
@@ -1102,7 +1084,7 b' def user_admin(pylonsapp):'
1102 1084
1103 1085
1104 1086 @pytest.fixture
1105 def user_regular(pylonsapp):
1087 def user_regular(baseapp):
1106 1088 """
1107 1089 Provides the default regular test user as an instance of `db.User`.
1108 1090 """
@@ -1111,7 +1093,7 b' def user_regular(pylonsapp):'
1111 1093
1112 1094
1113 1095 @pytest.fixture
1114 def user_util(request, pylonsapp):
1096 def user_util(request, baseapp):
1115 1097 """
1116 1098 Provides a wired instance of `UserUtility` with integrated cleanup.
1117 1099 """
@@ -1386,10 +1368,10 b' def collect_appenlight_stats(request, te'
1386 1368 if not request.config.getoption('--appenlight'):
1387 1369 return
1388 1370 else:
1389 # Only request the pylonsapp fixture if appenlight tracking is
1371 # Only request the baseapp fixture if appenlight tracking is
1390 1372 # enabled. This will speed up a test run of unit tests by 2 to 3
1391 1373 # seconds if appenlight is not enabled.
1392 pylonsapp = request.getfuncargvalue("pylonsapp")
1374 baseapp = request.getfuncargvalue("baseapp")
1393 1375 url = '{}/api/logs'.format(request.config.getoption('--appenlight-url'))
1394 1376 client = AppenlightClient(
1395 1377 url=url,
@@ -1402,8 +1384,8 b' def collect_appenlight_stats(request, te'
1402 1384 'message': "Starting",
1403 1385 })
1404 1386
1405 server_and_port = pylonsapp.config['vcs.server']
1406 protocol = pylonsapp.config['vcs.server.protocol']
1387 server_and_port = baseapp.config.get_settings()['vcs.server']
1388 protocol = baseapp.config.get_settings()['vcs.server.protocol']
1407 1389 server = create_vcsserver_proxy(server_and_port, protocol)
1408 1390 with server:
1409 1391 vcs_pid = server.get_pid()
@@ -1509,13 +1491,13 b' class AppenlightClient():'
1509 1491
1510 1492 if not response.status_code == 200:
1511 1493 pprint.pprint(self.stats)
1512 print response.headers
1513 print response.text
1494 print(response.headers)
1495 print(response.text)
1514 1496 raise Exception('Sending to appenlight failed')
1515 1497
1516 1498
1517 1499 @pytest.fixture
1518 def gist_util(request, pylonsapp):
1500 def gist_util(request, baseapp):
1519 1501 """
1520 1502 Provides a wired instance of `GistUtility` with integrated cleanup.
1521 1503 """
@@ -1821,7 +1803,7 b' def local_dt_to_utc():'
1821 1803
1822 1804
1823 1805 @pytest.fixture
1824 def disable_anonymous_user(request, pylonsapp):
1806 def disable_anonymous_user(request, baseapp):
1825 1807 set_anonymous_access(False)
1826 1808
1827 1809 @request.addfinalizer
@@ -18,9 +18,8 b''
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 import os
21 22 import json
22 import logging.config
23 import os
24 23 import platform
25 24 import socket
26 25 import subprocess32
@@ -28,16 +27,9 b' import time'
28 27 from urllib2 import urlopen, URLError
29 28
30 29 import configobj
31 import pylons
32 30 import pytest
33 import webob
34 from beaker.session import SessionObject
35 from paste.deploy import loadapp
36 from pylons.i18n.translation import _get_translator
37 from pylons.util import ContextObj
38 from routes.util import URLGenerator
39 31
40 from rhodecode.lib import vcs
32 import pyramid.paster
41 33 from rhodecode.tests.fixture import TestINI
42 34 import rhodecode
43 35
@@ -246,7 +238,7 b' class HttpVCSServer(VCSServer):'
246 238
247 239
248 240 @pytest.fixture(scope='session')
249 def pylons_config(request, tmpdir_factory, rcserver_port, vcsserver_port):
241 def ini_config(request, tmpdir_factory, rcserver_port, vcsserver_port):
250 242 option_name = 'pylons_config'
251 243 log_level = _use_log_level(request.config)
252 244
@@ -333,23 +325,28 b' def available_port(available_port_factor'
333 325
334 326
335 327 @pytest.fixture(scope='session')
336 def pylonsapp(pylons_config, vcsserver, http_environ_session):
337 print("Using the RhodeCode configuration:{}".format(pylons_config))
338 logging.config.fileConfig(
339 pylons_config, disable_existing_loggers=False)
340 app = _setup_pylons_environment(pylons_config, http_environ_session)
328 def baseapp(ini_config, vcsserver, http_environ_session):
329 from rhodecode.lib.pyramid_utils import get_app_config
330 from rhodecode.config.middleware import make_pyramid_app
331
332 print("Using the RhodeCode configuration:{}".format(ini_config))
333 pyramid.paster.setup_logging(ini_config)
334
335 settings = get_app_config(ini_config)
336 app = make_pyramid_app({}, **settings)
337
341 338 return app
342 339
343 340
344 341 @pytest.fixture(scope='session')
345 def testini_factory(tmpdir_factory, pylons_config):
342 def testini_factory(tmpdir_factory, ini_config):
346 343 """
347 344 Factory to create an INI file based on TestINI.
348 345
349 346 It will make sure to place the INI file in the correct directory.
350 347 """
351 348 basetemp = tmpdir_factory.getbasetemp().strpath
352 return TestIniFactory(basetemp, pylons_config)
349 return TestIniFactory(basetemp, ini_config)
353 350
354 351
355 352 class TestIniFactory(object):
@@ -387,36 +384,3 b' def get_config('
387 384 dir=basetemp)
388 385
389 386 return temp_ini_file.create()
390
391
392 def _setup_pylons_environment(pylons_config, http_environ):
393 current_path = os.getcwd()
394 pylonsapp = loadapp(
395 'config:' + pylons_config, relative_to=current_path)
396
397 # Using rhodecode.CONFIG which is assigned during "load_environment".
398 # The indirect approach is used, because "pylonsapp" may actually be
399 # the Pyramid application.
400 pylonsapp_config = rhodecode.CONFIG
401 _init_stack(pylonsapp_config, environ=http_environ)
402
403 # For compatibility add the attribute "config" which would be
404 # present on the Pylons application.
405 pylonsapp.config = pylonsapp_config
406 return pylonsapp
407
408
409 def _init_stack(config=None, environ=None):
410 if not config:
411 config = pylons.test.pylonsapp.config
412 if not environ:
413 environ = {}
414 pylons.url._push_object(URLGenerator(config['routes.map'], environ or {}))
415 pylons.app_globals._push_object(config['pylons.app_globals'])
416 pylons.config._push_object(config)
417 pylons.tmpl_context._push_object(ContextObj())
418 # Initialize a translator for tests that utilize i18n
419 translator = _get_translator(pylons.config.get('lang'))
420 pylons.translator._push_object(translator)
421 pylons.session._push_object(SessionObject(environ or {}))
422 pylons.request._push_object(webob.Request.blank('', environ=environ))
@@ -390,7 +390,7 b' beaker.cache.sql_cache_short.key_length '
390 390
391 391 ## default is memory cache, configure only if required
392 392 ## using multi-node or multi-worker setup
393 #beaker.cache.auth_plugins.type = ext:database
393 beaker.cache.auth_plugins.type = memory
394 394 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
395 395 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
396 396 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
@@ -31,9 +31,7 b' from os.path import dirname as dn'
31 31
32 32 from tempfile import _RandomNameSequence
33 33 from subprocess32 import Popen, PIPE
34 from paste.deploy import appconfig
35 34
36 from rhodecode.lib.utils import add_cache
37 35 from rhodecode.lib.utils2 import engine_from_config
38 36 from rhodecode.lib.auth import get_crypt_password
39 37 from rhodecode.model import init_model
@@ -41,13 +39,9 b' from rhodecode.model import meta'
41 39 from rhodecode.model.db import User, Repository
42 40
43 41 from rhodecode.tests import TESTS_TMP_PATH, HG_REPO
44 from rhodecode.config.environment import load_environment
45 42
46 43 rel_path = dn(dn(dn(dn(os.path.abspath(__file__)))))
47 conf = appconfig('config:rc.ini', relative_to=rel_path)
48 load_environment(conf.global_conf, conf.local_conf)
49 44
50 add_cache(conf)
51 45
52 46 USER = 'test_admin'
53 47 PASS = 'test12'
@@ -69,15 +63,16 b' class Command(object):'
69 63 command = cmd + ' ' + ' '.join(args)
70 64 log.debug('Executing %s' % command)
71 65 if DEBUG:
72 print command
66 print(command)
73 67 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
74 68 stdout, stderr = p.communicate()
75 69 if DEBUG:
76 print stdout, stderr
70 print('{} {}'.format(stdout, stderr))
77 71 return stdout, stderr
78 72
79 73
80 74 def get_session():
75 conf = {}
81 76 engine = engine_from_config(conf, 'sqlalchemy.db1.')
82 77 init_model(engine)
83 78 sa = meta.Session
@@ -85,20 +80,20 b' def get_session():'
85 80
86 81
87 82 def create_test_user(force=True):
88 print 'creating test user'
83 print('creating test user')
89 84 sa = get_session()
90 85
91 86 user = sa.query(User).filter(User.username == USER).scalar()
92 87
93 88 if force and user is not None:
94 print 'removing current user'
89 print('removing current user')
95 90 for repo in sa.query(Repository).filter(Repository.user == user).all():
96 91 sa.delete(repo)
97 92 sa.delete(user)
98 93 sa.commit()
99 94
100 95 if user is None or force:
101 print 'creating new one'
96 print('creating new one')
102 97 new_usr = User()
103 98 new_usr.username = USER
104 99 new_usr.password = get_crypt_password(PASS)
@@ -110,11 +105,11 b' def create_test_user(force=True):'
110 105 sa.add(new_usr)
111 106 sa.commit()
112 107
113 print 'done'
108 print('done')
114 109
115 110
116 111 def create_test_repo(force=True):
117 print 'creating test repo'
112 print('creating test repo')
118 113 from rhodecode.model.repo import RepoModel
119 114 sa = get_session()
120 115
@@ -125,7 +120,7 b' def create_test_repo(force=True):'
125 120 repo = sa.query(Repository).filter(Repository.repo_name == HG_REPO).scalar()
126 121
127 122 if repo is None:
128 print 'repo not found creating'
123 print('repo not found creating')
129 124
130 125 form_data = {'repo_name': HG_REPO,
131 126 'repo_type': 'hg',
@@ -135,7 +130,7 b' def create_test_repo(force=True):'
135 130 rm.base_path = '/home/hg'
136 131 rm.create(form_data, user)
137 132
138 print 'done'
133 print('done')
139 134
140 135
141 136 def get_anonymous_access():
@@ -177,6 +172,7 b' def test_clone_with_credentials(repo=HG_'
177 172 elif backend == 'git':
178 173 assert """Cloning into""" in stdout, 'no messages about cloning'
179 174
175
180 176 if __name__ == '__main__':
181 177 try:
182 178 create_test_user(force=False)
@@ -199,9 +195,9 b" if __name__ == '__main__':"
199 195 seq=seq, backend=backend)
200 196 s = time.time()
201 197 for i in range(1, int(sys.argv[2]) + 1):
202 print 'take', i
198 print('take {}'.format(i))
203 199 test_clone_with_credentials(repo=sys.argv[1], method=METHOD,
204 200 seq=seq, backend=backend)
205 print 'time taken %.3f' % (time.time() - s)
201 print('time taken %.3f' % (time.time() - s))
206 202 except Exception as e:
207 203 sys.exit('stop on %s' % e)
@@ -97,11 +97,13 b' class CustomTestResponse(TestResponse):'
97 97
98 98 def get_session_from_response(self):
99 99 """
100 This returns the session from a response object. Pylons has some magic
101 to make the session available as `response.session`. But pyramid
102 doesn't expose it.
100 This returns the session from a response object.
103 101 """
104 return self.request.environ['beaker.session']
102
103 from pyramid_beaker import session_factory_from_settings
104 session = session_factory_from_settings(
105 self.test_app.app.config.get_settings())
106 return session(self.request)
105 107
106 108
107 109 class TestRequest(webob.BaseRequest):
@@ -110,6 +112,9 b' class TestRequest(webob.BaseRequest):'
110 112 disabled = True
111 113 ResponseClass = CustomTestResponse
112 114
115 def add_response_callback(self, callback):
116 pass
117
113 118
114 119 class CustomTestApp(TestApp):
115 120 """
@@ -34,7 +34,7 b' from rhodecode.tests.vcs.base import Bac'
34 34
35 35 @pytest.fixture()
36 36 def vcs_repository_support(
37 request, backend_alias, pylonsapp, _vcs_repo_container):
37 request, backend_alias, baseapp, _vcs_repo_container):
38 38 """
39 39 Provide a test repository for the test run.
40 40
@@ -65,7 +65,7 b' class TestGitRepository:'
65 65 % TEST_GIT_REPO_CLONE)
66 66
67 67 @pytest.fixture(autouse=True)
68 def prepare(self, request, pylonsapp):
68 def prepare(self, request, baseapp):
69 69 self.repo = GitRepository(TEST_GIT_REPO, bare=True)
70 70
71 71 def get_clone_repo(self):
@@ -1153,7 +1153,7 b' class TestGitRegression(BackendTestMixin'
1153 1153
1154 1154 class TestDiscoverGitVersion:
1155 1155
1156 def test_returns_git_version(self, pylonsapp):
1156 def test_returns_git_version(self, baseapp):
1157 1157 version = discover_git_version()
1158 1158 assert version
1159 1159
@@ -51,7 +51,7 b' REPO_PATH_GENERATOR = repo_path_generato'
51 51
52 52
53 53 @pytest.fixture(scope='class', autouse=True)
54 def repo(request, pylonsapp):
54 def repo(request, baseapp):
55 55 repo = MercurialRepository(TEST_HG_REPO)
56 56 if request.cls:
57 57 request.cls.repo = repo
@@ -49,7 +49,7 b" TEST_GIT_REPO = os.environ.get('TEST_GIT"
49 49
50 50
51 51 @pytest.fixture(params=('hg', 'git'))
52 def repo(request, pylonsapp):
52 def repo(request, baseapp):
53 53 repos = {
54 54 'hg': TEST_HG_REPO,
55 55 'git': TEST_GIT_REPO,
@@ -59,12 +59,12 b' def repo(request, pylonsapp):'
59 59
60 60
61 61 @pytest.fixture
62 def server(pylonsapp):
62 def server(baseapp):
63 63 """
64 64 Returns a proxy of the server object.
65 65 """
66 server_and_port = pylonsapp.config['vcs.server']
67 protocol = pylonsapp.config['vcs.server.protocol']
66 server_and_port = baseapp.config.get_settings()['vcs.server']
67 protocol = baseapp.config.get_settings()['vcs.server.protocol']
68 68 server = create_vcsserver_proxy(server_and_port, protocol)
69 69 return server
70 70
@@ -31,12 +31,12 b' from rhodecode.lib.vcs.exceptions import'
31 31
32 32 pytestmark = [
33 33 pytest.mark.backends("svn"),
34 pytest.mark.usefixtures("pylonsapp"),
34 pytest.mark.usefixtures("baseapp"),
35 35 ]
36 36
37 37
38 38 @pytest.fixture
39 def repo(pylonsapp):
39 def repo(baseapp):
40 40 repo = SubversionRepository(os.path.join(TESTS_TMP_PATH, SVN_REPO))
41 41 return repo
42 42
@@ -32,7 +32,7 b' from rhodecode.lib.vcs.utils.helpers imp'
32 32 from rhodecode.lib.vcs.utils.paths import get_dirs_for_path
33 33
34 34
35 @pytest.mark.usefixtures("pylonsapp")
35 @pytest.mark.usefixtures("baseapp")
36 36 class TestPaths:
37 37
38 38 def _test_get_dirs_for_path(self, path, expected):
@@ -34,7 +34,7 b' from rhodecode.lib.vcs.backends.hg impor'
34 34 from rhodecode.tests import TEST_HG_REPO, TEST_GIT_REPO
35 35
36 36
37 pytestmark = pytest.mark.usefixtures("pylonsapp")
37 pytestmark = pytest.mark.usefixtures("baseapp")
38 38
39 39
40 40 def test_get_backend():
@@ -19,16 +19,24 b''
19 19 from pyramid.i18n import TranslationStringFactory, TranslationString
20 20
21 21 # Create a translation string factory for the 'rhodecode' domain.
22 from pyramid.threadlocal import get_current_request
23
22 24 _ = TranslationStringFactory('rhodecode')
23 25
26 temp_translation_factory = _
24 27
25 class LazyString(object):
28
29 class _LazyString(object):
26 30 def __init__(self, *args, **kw):
27 31 self.args = args
28 32 self.kw = kw
29 33
30 34 def eval(self):
31 return _(*self.args, **self.kw)
35 req = get_current_request()
36 translator = _
37 if req:
38 translator = req.translator
39 return translator(*self.args, **self.kw)
32 40
33 41 def __unicode__(self):
34 42 return unicode(self.eval())
@@ -36,6 +44,9 b' class LazyString(object):'
36 44 def __str__(self):
37 45 return self.eval()
38 46
47 def __repr__(self):
48 return self.__str__()
49
39 50 def __mod__(self, other):
40 51 return self.eval() % other
41 52
@@ -45,7 +56,7 b' class LazyString(object):'
45 56
46 57 def lazy_ugettext(*args, **kw):
47 58 """ Lazily evaluated version of _() """
48 return LazyString(*args, **kw)
59 return _LazyString(*args, **kw)
49 60
50 61
51 62 def _pluralize(msgid1, msgid2, n, mapping=None):
@@ -35,19 +35,22 b' def vcs_detection_tween_factory(handler,'
35 35 Do detection of vcs type, and save results for other layers to re-use
36 36 this information
37 37 """
38
39 vcs_handler = detect_vcs_request(
38 vcs_server_enabled = request.registry.settings.get('vcs.server.enable')
39 vcs_handler = vcs_server_enabled and detect_vcs_request(
40 40 request.environ, request.registry.settings.get('vcs.backends'))
41 41
42 42 if vcs_handler:
43 43 # save detected VCS type for later re-use
44 44 request.environ[VCS_TYPE_KEY] = vcs_handler.SCM
45 45 request.vcs_call = vcs_handler.SCM
46
47 log.debug('Processing request with `%s` handler', handler)
46 48 return handler(request)
47 49
48 50 # mark that we didn't detect an VCS, and we can skip detection later on
49 51 request.environ[VCS_TYPE_KEY] = VCS_TYPE_SKIP
50 52
53 log.debug('Processing request with `%s` handler', handler)
51 54 return handler(request)
52 55
53 56 return vcs_detection_tween
@@ -62,7 +65,5 b' def includeme(config):'
62 65 'pyramid.events.NewRequest')
63 66 config.add_subscriber('rhodecode.subscribers.add_request_user_context',
64 67 'pyramid.events.ContextFound')
65 config.add_subscriber('rhodecode.subscribers.add_pylons_context',
66 'pyramid.events.ContextFound')
67 68
68 69 config.add_tween('rhodecode.tweens.vcs_detection_tween_factory')
@@ -66,85 +66,10 b' def _get_requirements(req_filename, excl'
66 66 # requirements extract
67 67 setup_requirements = ['PasteScript', 'pytest-runner']
68 68 install_requirements = _get_requirements(
69 'requirements.txt', exclude=['setuptools'])
69 'requirements.txt', exclude=['setuptools', 'entrypoints'])
70 70 test_requirements = _get_requirements(
71 71 'requirements_test.txt', extras=['configobj'])
72 72
73 install_requirements = [
74 'Babel',
75 'Beaker',
76 'FormEncode',
77 'Mako',
78 'Markdown',
79 'MarkupSafe',
80 'MySQL-python',
81 'Paste',
82 'PasteDeploy',
83 'PasteScript',
84 'Pygments',
85 'pygments-markdown-lexer',
86 'Pylons',
87 'Routes',
88 'SQLAlchemy',
89 'Tempita',
90 'URLObject',
91 'WebError',
92 'WebHelpers',
93 'WebHelpers2',
94 'WebOb',
95 'WebTest',
96 'Whoosh',
97 'alembic',
98 'amqplib',
99 'anyjson',
100 'appenlight-client',
101 'authomatic',
102 'cssselect',
103 'celery',
104 'channelstream',
105 'colander',
106 'decorator',
107 'deform',
108 'docutils',
109 'gevent',
110 'gunicorn',
111 'infrae.cache',
112 'ipython',
113 'iso8601',
114 'kombu',
115 'lxml',
116 'msgpack-python',
117 'nbconvert',
118 'packaging',
119 'psycopg2',
120 'py-gfm',
121 'pycrypto',
122 'pycurl',
123 'pyparsing',
124 'pyramid',
125 'pyramid-debugtoolbar',
126 'pyramid-mako',
127 'pyramid-beaker',
128 'pysqlite',
129 'python-dateutil',
130 'python-ldap',
131 'python-memcached',
132 'python-pam',
133 'recaptcha-client',
134 'redis',
135 'repoze.lru',
136 'requests',
137 'simplejson',
138 'sshpubkeys',
139 'subprocess32',
140 'waitress',
141 'zope.cachedescriptors',
142 'dogpile.cache',
143 'dogpile.core',
144 'psutil',
145 'py-bcrypt',
146 ]
147
148 73
149 74 def get_version():
150 75 version = pkgutil.get_data('rhodecode', 'VERSION')
@@ -1,12 +0,0 b''
1 diff -rup celery-2.2.10-orig/setup.py celery-2.2.10/setup.py
2 --- celery-2.2.10-orig/setup.py 2017-02-25 15:30:34.000000000 +0100
3 +++ celery-2.2.10/setup.py 2017-02-25 15:30:34.000000000 +0100
4 @@ -48,7 +48,7 @@ try:
5 except ImportError:
6 install_requires.append("importlib")
7 install_requires.extend([
8 - "python-dateutil>=1.5.0,<2.0.0",
9 + "python-dateutil>=1.5.0,<2.2.0",
10 "anyjson>=0.3.1",
11 "kombu>=1.1.2,<2.0.0",
12 "pyparsing>=1.5.0,<2.0.0",
@@ -1,15 +0,0 b''
1 diff -rup kombu-1.5.1-orig/kombu/utils/__init__.py kombu-1.5.1/kombu/utils/__init__.py
2 --- kombu-1.5.1-orig/kombu/utils/__init__.py 2016-03-09 15:11:34.000000000 +0100
3 +++ kombu-1.5.1/kombu/utils/__init__.py 2016-03-09 15:15:52.000000000 +0100
4 @@ -11,7 +11,10 @@ Internal utilities.
5 import sys
6
7 from time import sleep
8 -from uuid import UUID, uuid4 as _uuid4, _uuid_generate_random
9 +from uuid import UUID, uuid4 as _uuid4
10 +
11 +# Fix for Python 2.7.11
12 +_uuid_generate_random = None
13
14 from kombu.utils.encoding import safe_repr as _safe_repr
15
@@ -1,184 +0,0 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 Routes configuration
23
24 The more specific and detailed routes should be defined first so they
25 may take precedent over the more generic routes. For more information
26 refer to the routes manual at http://routes.groovie.org/docs/
27
28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 and _route_name variable which uses some of stored naming here to do redirects.
30 """
31 import os
32 import re
33 from routes import Mapper
34
35 # prefix for non repository related links needs to be prefixed with `/`
36 ADMIN_PREFIX = '/_admin'
37 STATIC_FILE_PREFIX = '/_static'
38
39 # Default requirements for URL parts
40 URL_NAME_REQUIREMENTS = {
41 # group name can have a slash in them, but they must not end with a slash
42 'group_name': r'.*?[^/]',
43 'repo_group_name': r'.*?[^/]',
44 # repo names can have a slash in them, but they must not end with a slash
45 'repo_name': r'.*?[^/]',
46 # file path eats up everything at the end
47 'f_path': r'.*',
48 # reference types
49 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
50 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
51 }
52
53
54 class JSRoutesMapper(Mapper):
55 """
56 Wrapper for routes.Mapper to make pyroutes compatible url definitions
57 """
58 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
59 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
60 def __init__(self, *args, **kw):
61 super(JSRoutesMapper, self).__init__(*args, **kw)
62 self._jsroutes = []
63
64 def connect(self, *args, **kw):
65 """
66 Wrapper for connect to take an extra argument jsroute=True
67
68 :param jsroute: boolean, if True will add the route to the pyroutes list
69 """
70 if kw.pop('jsroute', False):
71 if not self._named_route_regex.match(args[0]):
72 raise Exception('only named routes can be added to pyroutes')
73 self._jsroutes.append(args[0])
74
75 super(JSRoutesMapper, self).connect(*args, **kw)
76
77 def _extract_route_information(self, route):
78 """
79 Convert a route into tuple(name, path, args), eg:
80 ('show_user', '/profile/%(username)s', ['username'])
81 """
82 routepath = route.routepath
83 def replace(matchobj):
84 if matchobj.group(1):
85 return "%%(%s)s" % matchobj.group(1).split(':')[0]
86 else:
87 return "%%(%s)s" % matchobj.group(2)
88
89 routepath = self._argument_prog.sub(replace, routepath)
90 return (
91 route.name,
92 routepath,
93 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
94 for arg in self._argument_prog.findall(route.routepath)]
95 )
96
97 def jsroutes(self):
98 """
99 Return a list of pyroutes.js compatible routes
100 """
101 for route_name in self._jsroutes:
102 yield self._extract_route_information(self._routenames[route_name])
103
104
105 def make_map(config):
106 """Create, configure and return the routes Mapper"""
107 rmap = JSRoutesMapper(
108 directory=config['pylons.paths']['controllers'],
109 always_scan=config['debug'])
110 rmap.minimization = False
111 rmap.explicit = False
112
113 from rhodecode.lib.utils2 import str2bool
114 from rhodecode.model import repo, repo_group
115
116 def check_repo(environ, match_dict):
117 """
118 check for valid repository for proper 404 handling
119
120 :param environ:
121 :param match_dict:
122 """
123 repo_name = match_dict.get('repo_name')
124
125 if match_dict.get('f_path'):
126 # fix for multiple initial slashes that causes errors
127 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
128 repo_model = repo.RepoModel()
129 by_name_match = repo_model.get_by_repo_name(repo_name)
130 # if we match quickly from database, short circuit the operation,
131 # and validate repo based on the type.
132 if by_name_match:
133 return True
134
135 by_id_match = repo_model.get_repo_by_id(repo_name)
136 if by_id_match:
137 repo_name = by_id_match.repo_name
138 match_dict['repo_name'] = repo_name
139 return True
140
141 return False
142
143 def check_group(environ, match_dict):
144 """
145 check for valid repository group path for proper 404 handling
146
147 :param environ:
148 :param match_dict:
149 """
150 repo_group_name = match_dict.get('group_name')
151 repo_group_model = repo_group.RepoGroupModel()
152 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
153 if by_name_match:
154 return True
155
156 return False
157
158 def check_user_group(environ, match_dict):
159 """
160 check for valid user group for proper 404 handling
161
162 :param environ:
163 :param match_dict:
164 """
165 return True
166
167 def check_int(environ, match_dict):
168 return match_dict.get('id').isdigit()
169
170
171 #==========================================================================
172 # CUSTOM ROUTES HERE
173 #==========================================================================
174
175 # ADMIN MY ACCOUNT
176 with rmap.submapper(path_prefix=ADMIN_PREFIX,
177 controller='admin/my_account') as m:
178
179 # NOTE(marcink): this needs to be kept for password force flag to be
180 # handled in pylons controllers, remove after full migration to pyramid
181 m.connect('my_account_password', '/my_account/password',
182 action='my_account_password', conditions={'method': ['GET']})
183
184 return rmap
@@ -1,42 +0,0 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 The application's Globals object
23 """
24
25 from beaker.cache import CacheManager
26 from beaker.util import parse_cache_config_options
27
28
29 class Globals(object):
30 """
31 Globals acts as a container for objects available throughout the
32 life of the application
33 """
34
35 def __init__(self, config):
36 """One instance of Globals is created during application
37 initialization and is available during requests via the
38 'app_globals' variable
39
40 """
41 self.cache = CacheManager(**parse_cache_config_options(config))
42 self.available_permissions = None # propagated after init_model
@@ -1,108 +0,0 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 import logging
23 from pyramid import httpexceptions
24 from pyramid.httpexceptions import (
25 HTTPRedirection, HTTPError, HTTPInternalServerError)
26 from pyramid.threadlocal import get_current_request
27
28 from rhodecode.lib.exceptions import VCSServerUnavailable
29 from rhodecode.lib.vcs.exceptions import VCSCommunicationError
30
31
32 log = logging.getLogger(__name__)
33
34
35 class PylonsErrorHandlingMiddleware(object):
36 """
37 This middleware is wrapped around the old pylons application to catch
38 errors and invoke our error handling view to return a proper error page.
39 """
40 def __init__(self, app, error_view, reraise=False):
41 self.app = app
42 self.error_view = error_view
43 self._reraise = reraise
44
45 def __call__(self, environ, start_response):
46 # We need to use the pyramid request here instead of creating a custom
47 # instance from the environ because this request maybe passed to the
48 # error handler view which is a pyramid view and expects a pyramid
49 # request which has been processed by the pyramid router.
50 request = get_current_request()
51
52 response = self.handle_request(request)
53 return response(environ, start_response)
54
55 def is_http_error(self, response):
56 # webob type error responses
57 return 400 <= response.status_int <= 599
58
59 def reraise(self):
60 return self._reraise
61
62 def handle_request(self, request):
63 """
64 Calls the underlying WSGI app (typically the old RhodeCode pylons app)
65 and returns the response if no error happened. In case of an error it
66 invokes the error handling view to return a proper error page as
67 response.
68
69 - old webob type exceptions get converted to pyramid exceptions
70 - pyramid exceptions are passed to the error handler view
71 """
72 try:
73 response = request.get_response(self.app)
74 if self.is_http_error(response):
75 response = webob_to_pyramid_http_response(response)
76 return self.error_view(response, request)
77 except HTTPRedirection as e:
78 # pyramid type redirection, with status codes in the 300s
79 log.debug('Handling pyramid HTTPRedirection: %s', e)
80 return e
81 except HTTPError as e:
82 # pyramid type exceptions, with status codes in the 400s and 500s
83 log.debug('Handling pyramid HTTPError: %s', e)
84 return self.error_view(e, request)
85 except Exception as e:
86 log.debug('Handling general error: %s', e)
87
88 if self.reraise():
89 raise
90
91 if isinstance(e, VCSCommunicationError):
92 return self.error_view(VCSServerUnavailable(), request)
93
94 return self.error_view(HTTPInternalServerError(), request)
95
96 return response
97
98
99 def webob_to_pyramid_http_response(webob_response):
100 log.debug('response is webob http error[%s], handling now...',
101 webob_response.status_int)
102 ResponseClass = httpexceptions.status_map[webob_response.status_int]
103 pyramid_response = ResponseClass(webob_response.status)
104 pyramid_response.status = webob_response.status
105 pyramid_response.headers.update(webob_response.headers)
106 if pyramid_response.headers['content-type'] == 'text/html':
107 pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8'
108 return pyramid_response
General Comments 0
You need to be logged in to leave comments. Login now