Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
a0c2eb46
Kaydet (Commit)
a0c2eb46
authored
Mar 13, 2015
tarafından
Claude Paroz
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fixed #23960 -- Removed http.fix_location_header
Thanks Carl Meyer for the report and Tim Graham for the review.
üst
0339844b
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
127 additions
and
156 deletions
+127
-156
base.py
django/core/handlers/base.py
+0
-1
__init__.py
django/http/__init__.py
+3
-3
utils.py
django/http/utils.py
+0
-13
common.py
django/middleware/common.py
+1
-1
locale.py
django/middleware/locale.py
+6
-10
testcases.py
django/test/testcases.py
+21
-7
deprecation.txt
docs/internals/deprecation.txt
+4
-0
request-response.txt
docs/ref/request-response.txt
+4
-2
1.9.txt
docs/releases/1.9.txt
+15
-0
tools.txt
docs/topics/testing/tools.txt
+6
-9
test_edit.py
tests/generic_views/test_edit.py
+20
-20
tests.py
tests/http_utils/tests.py
+2
-16
tests.py
tests/i18n/patterns/tests.py
+1
-1
tests.py
tests/middleware/tests.py
+6
-6
tests.py
tests/test_client/tests.py
+14
-27
tests.py
tests/test_client_regress/tests.py
+19
-14
generic_urls.py
tests/view_tests/generic_urls.py
+0
-1
test_i18n.py
tests/view_tests/tests/test_i18n.py
+4
-4
test_specials.py
tests/view_tests/tests/test_specials.py
+0
-11
views.py
tests/view_tests/views.py
+1
-10
No files found.
django/core/handlers/base.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -23,7 +23,6 @@ logger = logging.getLogger('django.request')
class
BaseHandler
(
object
):
# Changes that are always applied to a response (in this order).
response_fixes
=
[
http
.
fix_location_header
,
http
.
conditional_content_removal
,
]
...
...
django/http/__init__.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -8,7 +8,7 @@ from django.http.response import (
HttpResponseNotFound
,
HttpResponseNotAllowed
,
HttpResponseGone
,
HttpResponseServerError
,
Http404
,
BadHeaderError
,
JsonResponse
,
)
from
django.http.utils
import
fix_location_header
,
conditional_content_removal
from
django.http.utils
import
conditional_content_removal
__all__
=
[
'SimpleCookie'
,
'parse_cookie'
,
'HttpRequest'
,
'QueryDict'
,
...
...
@@ -17,6 +17,6 @@ __all__ = [
'HttpResponsePermanentRedirect'
,
'HttpResponseNotModified'
,
'HttpResponseBadRequest'
,
'HttpResponseForbidden'
,
'HttpResponseNotFound'
,
'HttpResponseNotAllowed'
,
'HttpResponseGone'
,
'HttpResponseServerError'
,
'Http404'
,
'BadHeaderError'
,
'
fix_location_header'
,
'Json
Response'
,
'
FileResponse'
,
'
conditional_content_removal'
,
'Http404'
,
'BadHeaderError'
,
'
JsonResponse'
,
'File
Response'
,
'conditional_content_removal'
,
]
django/http/utils.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -9,19 +9,6 @@ Functions that modify an HTTP request or response in some way.
# universally applicable.
def
fix_location_header
(
request
,
response
):
"""
Ensures that we always use an absolute URI in any location header in the
response. This is required by RFC 2616, section 14.30.
Code constructing response objects is free to insert relative paths, as
this function converts them to absolute paths.
"""
if
'Location'
in
response
:
response
[
'Location'
]
=
request
.
build_absolute_uri
(
response
[
'Location'
])
return
response
def
conditional_content_removal
(
request
,
response
):
"""
Removes the content of responses for HEAD requests, 1xx, 204 and 304
...
...
django/middleware/common.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -86,7 +86,7 @@ class CommonMiddleware(object):
if
new_url
==
old_url
:
# No redirects required.
return
if
new_url
[
0
]:
if
new_url
[
0
]
!=
old_url
[
0
]
:
newurl
=
"
%
s://
%
s
%
s"
%
(
request
.
scheme
,
new_url
[
0
],
urlquote
(
new_url
[
1
]))
...
...
django/middleware/locale.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -40,16 +40,12 @@ class LocaleMiddleware(object):
if
path_valid
:
script_prefix
=
get_script_prefix
()
language_url
=
"
%
s://
%
s
%
s"
%
(
request
.
scheme
,
request
.
get_host
(),
# insert language after the script prefix and before the
# rest of the URL
request
.
get_full_path
()
.
replace
(
script_prefix
,
'
%
s
%
s/'
%
(
script_prefix
,
language
),
1
)
# Insert language after the script prefix and before the
# rest of the URL
language_url
=
request
.
get_full_path
()
.
replace
(
script_prefix
,
'
%
s
%
s/'
%
(
script_prefix
,
language
),
1
)
return
self
.
response_redirect_class
(
language_url
)
...
...
django/test/testcases.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -37,7 +37,9 @@ from django.test.utils import (
override_settings
,
)
from
django.utils
import
six
from
django.utils.deprecation
import
RemovedInDjango20Warning
from
django.utils.deprecation
import
(
RemovedInDjango20Warning
,
RemovedInDjango21Warning
,
)
from
django.utils.encoding
import
force_text
from
django.utils.six.moves.urllib.parse
import
(
unquote
,
urlparse
,
urlsplit
,
urlunsplit
,
...
...
@@ -249,11 +251,15 @@ class SimpleTestCase(unittest.TestCase):
TestClient to do a request (use fetch_redirect_response=False to check
such links without fetching them).
"""
if
host
is
not
None
:
warnings
.
warn
(
"The host argument is deprecated and no longer used by assertRedirects"
,
RemovedInDjango21Warning
,
stacklevel
=
2
)
if
msg_prefix
:
msg_prefix
+=
": "
e_scheme
,
e_netloc
,
e_path
,
e_query
,
e_fragment
=
urlsplit
(
expected_url
)
if
hasattr
(
response
,
'redirect_chain'
):
# The request was a followed redirect
self
.
assertTrue
(
len
(
response
.
redirect_chain
)
>
0
,
...
...
@@ -295,10 +301,18 @@ class SimpleTestCase(unittest.TestCase):
" response code was
%
d (expected
%
d)"
%
(
path
,
redirect_response
.
status_code
,
target_status_code
))
e_scheme
=
e_scheme
if
e_scheme
else
scheme
or
'http'
e_netloc
=
e_netloc
if
e_netloc
else
host
or
'testserver'
expected_url
=
urlunsplit
((
e_scheme
,
e_netloc
,
e_path
,
e_query
,
e_fragment
))
if
url
!=
expected_url
:
# For temporary backwards compatibility, try to compare with a relative url
e_scheme
,
e_netloc
,
e_path
,
e_query
,
e_fragment
=
urlsplit
(
expected_url
)
relative_url
=
urlunsplit
((
''
,
''
,
e_path
,
e_query
,
e_fragment
))
if
url
==
relative_url
:
warnings
.
warn
(
"assertRedirects had to strip the scheme and domain from the "
"expected URL, as it was always added automatically to URLs "
"before Django 1.9. Please update your expected URLs by "
"removing the scheme and domain."
,
RemovedInDjango21Warning
,
stacklevel
=
2
)
expected_url
=
relative_url
self
.
assertEqual
(
url
,
expected_url
,
msg_prefix
+
"Response redirected to '
%
s', expected '
%
s'"
%
...
...
docs/internals/deprecation.txt
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -22,6 +22,10 @@ details on these changes.
* The ``assignment_tag`` helper will be removed.
* The ``host`` argument to ``assertsRedirects`` will be removed. The
compatibility layer which allows absolute URLs to be considered equal to
relative ones when the path is identical will also be removed.
.. _deprecation-removed-in-2.0:
2.0
...
...
docs/ref/request-response.txt
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -824,8 +824,10 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
The first argument to the constructor is required -- the path to redirect
to. This can be a fully qualified URL
(e.g. ``'http://www.yahoo.com/search/'``) or an absolute path with no
domain (e.g. ``'/search/'``). See :class:`HttpResponse` for other optional
(e.g. ``'http://www.yahoo.com/search/'``), an absolute path with no domain
(e.g. ``'/search/'``), or even a relative path (e.g. ``'search/'``). In that
last case, the client browser will reconstruct the full URL itself
according to the current path. See :class:`HttpResponse` for other optional
constructor arguments. Note that this returns an HTTP status code 302.
.. attribute:: HttpResponseRedirect.url
...
...
docs/releases/1.9.txt
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -266,6 +266,21 @@ a directory. Now, Django only silences the exception if the template source
does not exist. All other situations result in the original ``IOError`` being
raised.
HTTP redirects no longer forced to absolute URIs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Relative redirects are no longer converted to absolute URIs. :rfc:`2616`
required the ``Location`` header in redirect responses to be an absolute URI,
but it has been superseded by :rfc:`7231` which allows relative URIs in
``Location``, recognizing the actual practice of user agents, almost all of
which support them.
Consequently, the expected URLs passed to ``assertRedirects`` should generally
no longer include the scheme and domain part of the URLs. For example,
``self.assertRedirects(response, 'http://testserver/some-url/')`` should be
replaced by ``self.assertRedirects(response, '/some-url/')`` (unless the
redirection specifically contained an absolute URL, of course).
Miscellaneous
~~~~~~~~~~~~~
...
...
docs/topics/testing/tools.txt
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -1398,7 +1398,7 @@ your test suite.
You can use this as a context manager in the same way as
:meth:`~SimpleTestCase.assertTemplateUsed`.
.. method:: SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200,
host=None,
msg_prefix='', fetch_redirect_response=True)
.. method:: SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='', fetch_redirect_response=True)
Asserts that the response returned a ``status_code`` redirect status,
redirected to ``expected_url`` (including any ``GET`` data), and that the
...
...
@@ -1408,14 +1408,6 @@ your test suite.
``target_status_code`` will be the url and status code for the final
point of the redirect chain.
The ``host`` argument sets a default host if ``expected_url`` doesn't
include one (e.g. ``"/bar/"``). If ``expected_url`` is an absolute URL that
includes a host (e.g. ``"http://testhost/bar/"``), the ``host`` parameter
will be ignored. Note that the test client doesn't support fetching external
URLs, but the parameter may be useful if you are testing with a custom HTTP
host (for example, initializing the test client with
``Client(HTTP_HOST="testhost")``.
If ``fetch_redirect_response`` is ``False``, the final page won't be
loaded. Since the test client can't fetch externals URLs, this is
particularly useful if ``expected_url`` isn't part of your Django app.
...
...
@@ -1425,6 +1417,11 @@ your test suite.
the original request's scheme is used. If present, the scheme in
``expected_url`` is the one used to make the comparisons to.
.. deprecated:: 1.9
The ``host`` argument is deprecated, as redirections are no longer
forced to be absolute URLs.
.. method:: SimpleTestCase.assertHTMLEqual(html1, html2, msg=None)
Asserts that the strings ``html1`` and ``html2`` are equal. The comparison
...
...
tests/generic_views/test_edit.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -87,7 +87,7 @@ class BasicFormTests(TestCase):
def
test_post_data
(
self
):
res
=
self
.
client
.
post
(
'/contact/'
,
{
'name'
:
"Me"
,
'message'
:
"Hello"
})
self
.
assertRedirects
(
res
,
'
http://testserver
/list/authors/'
)
self
.
assertRedirects
(
res
,
'/list/authors/'
)
class
ModelFormMixinTests
(
TestCase
):
...
...
@@ -117,7 +117,7 @@ class CreateViewTests(TestCase):
res
=
self
.
client
.
post
(
'/edit/authors/create/'
,
{
'name'
:
'Randall Munroe'
,
'slug'
:
'randall-munroe'
})
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/list/authors/'
)
self
.
assertRedirects
(
res
,
'/list/authors/'
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[
'<Author: Randall Munroe>'
])
def
test_create_invalid
(
self
):
...
...
@@ -133,14 +133,14 @@ class CreateViewTests(TestCase):
{
'name'
:
'Rene Magritte'
})
self
.
assertEqual
(
res
.
status_code
,
302
)
artist
=
Artist
.
objects
.
get
(
name
=
'Rene Magritte'
)
self
.
assertRedirects
(
res
,
'
http://testserver
/detail/artist/
%
d/'
%
artist
.
pk
)
self
.
assertRedirects
(
res
,
'/detail/artist/
%
d/'
%
artist
.
pk
)
self
.
assertQuerysetEqual
(
Artist
.
objects
.
all
(),
[
'<Artist: Rene Magritte>'
])
def
test_create_with_redirect
(
self
):
res
=
self
.
client
.
post
(
'/edit/authors/create/redirect/'
,
{
'name'
:
'Randall Munroe'
,
'slug'
:
'randall-munroe'
})
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/edit/authors/create/'
)
self
.
assertRedirects
(
res
,
'/edit/authors/create/'
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[
'<Author: Randall Munroe>'
])
@ignore_warnings
(
category
=
RemovedInDjango20Warning
)
...
...
@@ -152,7 +152,7 @@ class CreateViewTests(TestCase):
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[
'<Author: Randall Munroe>'
])
self
.
assertEqual
(
res
.
status_code
,
302
)
pk
=
Author
.
objects
.
first
()
.
pk
self
.
assertRedirects
(
res
,
'
http://testserver
/edit/author/
%
d/update/'
%
pk
)
self
.
assertRedirects
(
res
,
'/edit/author/
%
d/update/'
%
pk
)
# Also test with escaped chars in URL
res
=
self
.
client
.
post
(
'/edit/authors/create/interpolate_redirect_nonascii/'
,
...
...
@@ -160,7 +160,7 @@ class CreateViewTests(TestCase):
)
self
.
assertEqual
(
res
.
status_code
,
302
)
pk
=
Author
.
objects
.
get
(
name
=
'John Doe'
)
.
pk
self
.
assertRedirects
(
res
,
'
http://testserver
/
%
C3
%
A9dit/author/{}/update/'
.
format
(
pk
))
self
.
assertRedirects
(
res
,
'/
%
C3
%
A9dit/author/{}/update/'
.
format
(
pk
))
def
test_create_with_special_properties
(
self
):
res
=
self
.
client
.
get
(
'/edit/authors/create/special/'
)
...
...
@@ -189,7 +189,7 @@ class CreateViewTests(TestCase):
res
=
self
.
client
.
post
(
'/edit/authors/create/restricted/'
,
{
'name'
:
'Randall Munroe'
,
'slug'
:
'randall-munroe'
})
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/accounts/login/?next=/edit/authors/create/restricted/'
)
self
.
assertRedirects
(
res
,
'/accounts/login/?next=/edit/authors/create/restricted/'
)
def
test_create_view_with_restricted_fields
(
self
):
...
...
@@ -249,7 +249,7 @@ class UpdateViewTests(TestCase):
res
=
self
.
client
.
post
(
'/edit/author/
%
d/update/'
%
a
.
pk
,
{
'name'
:
'Randall Munroe (xkcd)'
,
'slug'
:
'randall-munroe'
})
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/list/authors/'
)
self
.
assertRedirects
(
res
,
'/list/authors/'
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[
'<Author: Randall Munroe (xkcd)>'
])
def
test_update_invalid
(
self
):
...
...
@@ -269,7 +269,7 @@ class UpdateViewTests(TestCase):
res
=
self
.
client
.
post
(
'/edit/artists/
%
d/update/'
%
a
.
pk
,
{
'name'
:
'Rene Magritte'
})
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/detail/artist/
%
d/'
%
a
.
pk
)
self
.
assertRedirects
(
res
,
'/detail/artist/
%
d/'
%
a
.
pk
)
self
.
assertQuerysetEqual
(
Artist
.
objects
.
all
(),
[
'<Artist: Rene Magritte>'
])
def
test_update_with_redirect
(
self
):
...
...
@@ -280,7 +280,7 @@ class UpdateViewTests(TestCase):
res
=
self
.
client
.
post
(
'/edit/author/
%
d/update/redirect/'
%
a
.
pk
,
{
'name'
:
'Randall Munroe (author of xkcd)'
,
'slug'
:
'randall-munroe'
})
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/edit/authors/create/'
)
self
.
assertRedirects
(
res
,
'/edit/authors/create/'
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[
'<Author: Randall Munroe (author of xkcd)>'
])
@ignore_warnings
(
category
=
RemovedInDjango20Warning
)
...
...
@@ -296,7 +296,7 @@ class UpdateViewTests(TestCase):
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[
'<Author: Randall Munroe (author of xkcd)>'
])
self
.
assertEqual
(
res
.
status_code
,
302
)
pk
=
Author
.
objects
.
first
()
.
pk
self
.
assertRedirects
(
res
,
'
http://testserver
/edit/author/
%
d/update/'
%
pk
)
self
.
assertRedirects
(
res
,
'/edit/author/
%
d/update/'
%
pk
)
# Also test with escaped chars in URL
res
=
self
.
client
.
post
(
'/edit/author/
%
d/update/interpolate_redirect_nonascii/'
%
a
.
pk
,
...
...
@@ -304,7 +304,7 @@ class UpdateViewTests(TestCase):
)
self
.
assertEqual
(
res
.
status_code
,
302
)
pk
=
Author
.
objects
.
get
(
name
=
'John Doe'
)
.
pk
self
.
assertRedirects
(
res
,
'
http://testserver
/
%
C3
%
A9dit/author/{}/update/'
.
format
(
pk
))
self
.
assertRedirects
(
res
,
'/
%
C3
%
A9dit/author/{}/update/'
.
format
(
pk
))
def
test_update_with_special_properties
(
self
):
a
=
Author
.
objects
.
create
(
...
...
@@ -322,7 +322,7 @@ class UpdateViewTests(TestCase):
res
=
self
.
client
.
post
(
'/edit/author/
%
d/update/special/'
%
a
.
pk
,
{
'name'
:
'Randall Munroe (author of xkcd)'
,
'slug'
:
'randall-munroe'
})
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/detail/author/
%
d/'
%
a
.
pk
)
self
.
assertRedirects
(
res
,
'/detail/author/
%
d/'
%
a
.
pk
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[
'<Author: Randall Munroe (author of xkcd)>'
])
def
test_update_without_redirect
(
self
):
...
...
@@ -354,7 +354,7 @@ class UpdateViewTests(TestCase):
res
=
self
.
client
.
post
(
'/edit/author/update/'
,
{
'name'
:
'Randall Munroe (xkcd)'
,
'slug'
:
'randall-munroe'
})
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/list/authors/'
)
self
.
assertRedirects
(
res
,
'/list/authors/'
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[
'<Author: Randall Munroe (xkcd)>'
])
...
...
@@ -372,7 +372,7 @@ class DeleteViewTests(TestCase):
# Deletion with POST
res
=
self
.
client
.
post
(
'/edit/author/
%
d/delete/'
%
a
.
pk
)
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/list/authors/'
)
self
.
assertRedirects
(
res
,
'/list/authors/'
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[])
def
test_delete_by_delete
(
self
):
...
...
@@ -380,14 +380,14 @@ class DeleteViewTests(TestCase):
a
=
Author
.
objects
.
create
(
**
{
'name'
:
'Randall Munroe'
,
'slug'
:
'randall-munroe'
})
res
=
self
.
client
.
delete
(
'/edit/author/
%
d/delete/'
%
a
.
pk
)
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/list/authors/'
)
self
.
assertRedirects
(
res
,
'/list/authors/'
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[])
def
test_delete_with_redirect
(
self
):
a
=
Author
.
objects
.
create
(
**
{
'name'
:
'Randall Munroe'
,
'slug'
:
'randall-munroe'
})
res
=
self
.
client
.
post
(
'/edit/author/
%
d/delete/redirect/'
%
a
.
pk
)
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/edit/authors/create/'
)
self
.
assertRedirects
(
res
,
'/edit/authors/create/'
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[])
@ignore_warnings
(
category
=
RemovedInDjango20Warning
)
...
...
@@ -395,13 +395,13 @@ class DeleteViewTests(TestCase):
a
=
Author
.
objects
.
create
(
**
{
'name'
:
'Randall Munroe'
,
'slug'
:
'randall-munroe'
})
res
=
self
.
client
.
post
(
'/edit/author/
%
d/delete/interpolate_redirect/'
%
a
.
pk
)
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/edit/authors/create/?deleted=
%
d'
%
a
.
pk
)
self
.
assertRedirects
(
res
,
'/edit/authors/create/?deleted=
%
d'
%
a
.
pk
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[])
# Also test with escaped chars in URL
a
=
Author
.
objects
.
create
(
**
{
'name'
:
'Randall Munroe'
,
'slug'
:
'randall-munroe'
})
res
=
self
.
client
.
post
(
'/edit/author/{}/delete/interpolate_redirect_nonascii/'
.
format
(
a
.
pk
))
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/
%
C3
%
A9dit/authors/create/?deleted={}'
.
format
(
a
.
pk
))
self
.
assertRedirects
(
res
,
'/
%
C3
%
A9dit/authors/create/?deleted={}'
.
format
(
a
.
pk
))
def
test_delete_with_special_properties
(
self
):
a
=
Author
.
objects
.
create
(
**
{
'name'
:
'Randall Munroe'
,
'slug'
:
'randall-munroe'
})
...
...
@@ -414,7 +414,7 @@ class DeleteViewTests(TestCase):
res
=
self
.
client
.
post
(
'/edit/author/
%
d/delete/special/'
%
a
.
pk
)
self
.
assertEqual
(
res
.
status_code
,
302
)
self
.
assertRedirects
(
res
,
'
http://testserver
/list/authors/'
)
self
.
assertRedirects
(
res
,
'/list/authors/'
)
self
.
assertQuerysetEqual
(
Author
.
objects
.
all
(),
[])
def
test_delete_without_redirect
(
self
):
...
...
tests/http_utils/tests.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -3,10 +3,8 @@ from __future__ import unicode_literals
import
gzip
import
io
from
django.http
import
(
HttpRequest
,
HttpResponse
,
HttpResponseRedirect
,
StreamingHttpResponse
,
)
from
django.http.utils
import
conditional_content_removal
,
fix_location_header
from
django.http
import
HttpRequest
,
HttpResponse
,
StreamingHttpResponse
from
django.http.utils
import
conditional_content_removal
from
django.test
import
TestCase
...
...
@@ -71,15 +69,3 @@ class HttpUtilTests(TestCase):
res
=
StreamingHttpResponse
([
'abc'
])
conditional_content_removal
(
req
,
res
)
self
.
assertEqual
(
b
''
.
join
(
res
),
b
''
)
def
test_fix_location_without_get_host
(
self
):
"""
Tests that you can return an absolute redirect when the request
host is not in ALLOWED_HOSTS. Issue #20472
"""
request
=
HttpRequest
()
def
bomb
():
self
.
assertTrue
(
False
)
request
.
get_host
=
bomb
fix_location_header
(
request
,
HttpResponseRedirect
(
'http://example.com'
))
tests/i18n/patterns/tests.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -248,7 +248,7 @@ class URLRedirectWithoutTrailingSlashTests(URLTestCaseBase):
def
test_en_redirect
(
self
):
response
=
self
.
client
.
get
(
'/account/register'
,
HTTP_ACCEPT_LANGUAGE
=
'en'
,
follow
=
True
)
# target status code of 301 because of CommonMiddleware redirecting
self
.
assertIn
((
'
http://testserver
/en/account/register/'
,
301
),
response
.
redirect_chain
)
self
.
assertIn
((
'/en/account/register/'
,
301
),
response
.
redirect_chain
)
self
.
assertRedirects
(
response
,
'/en/account/register/'
,
302
)
response
=
self
.
client
.
get
(
'/prefixed.xml'
,
HTTP_ACCEPT_LANGUAGE
=
'en'
,
follow
=
True
)
...
...
tests/middleware/tests.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -64,7 +64,7 @@ class CommonMiddlewareTest(TestCase):
request
=
self
.
rf
.
get
(
'/slash'
)
r
=
CommonMiddleware
()
.
process_request
(
request
)
self
.
assertEqual
(
r
.
status_code
,
301
)
self
.
assertEqual
(
r
.
url
,
'
http://testserver
/slash/'
)
self
.
assertEqual
(
r
.
url
,
'/slash/'
)
@override_settings
(
APPEND_SLASH
=
True
,
DEBUG
=
True
)
def
test_append_slash_no_redirect_on_POST_in_DEBUG
(
self
):
...
...
@@ -106,7 +106,7 @@ class CommonMiddlewareTest(TestCase):
self
.
assertEqual
(
r
.
status_code
,
301
)
self
.
assertEqual
(
r
.
url
,
'
http://testserver
/needsquoting
%23
/'
)
'/needsquoting
%23
/'
)
@override_settings
(
APPEND_SLASH
=
False
,
PREPEND_WWW
=
True
)
def
test_prepend_www
(
self
):
...
...
@@ -174,7 +174,7 @@ class CommonMiddlewareTest(TestCase):
self
.
assertIsNotNone
(
r
,
"CommonMiddlware failed to return APPEND_SLASH redirect using request.urlconf"
)
self
.
assertEqual
(
r
.
status_code
,
301
)
self
.
assertEqual
(
r
.
url
,
'
http://testserver
/customurlconf/slash/'
)
self
.
assertEqual
(
r
.
url
,
'/customurlconf/slash/'
)
@override_settings
(
APPEND_SLASH
=
True
,
DEBUG
=
True
)
def
test_append_slash_no_redirect_on_POST_in_DEBUG_custom_urlconf
(
self
):
...
...
@@ -212,7 +212,7 @@ class CommonMiddlewareTest(TestCase):
self
.
assertEqual
(
r
.
status_code
,
301
)
self
.
assertEqual
(
r
.
url
,
'
http://testserver
/customurlconf/needsquoting
%23
/'
)
'/customurlconf/needsquoting
%23
/'
)
@override_settings
(
APPEND_SLASH
=
False
,
PREPEND_WWW
=
True
)
def
test_prepend_www_custom_urlconf
(
self
):
...
...
@@ -264,7 +264,7 @@ class CommonMiddlewareTest(TestCase):
request
=
self
.
rf
.
get
(
'/slash'
)
r
=
CommonMiddleware
()
.
process_request
(
request
)
self
.
assertEqual
(
r
.
status_code
,
301
)
self
.
assertEqual
(
r
.
url
,
'
http://testserver
/slash/'
)
self
.
assertEqual
(
r
.
url
,
'/slash/'
)
self
.
assertIsInstance
(
r
,
HttpResponsePermanentRedirect
)
def
test_response_redirect_class_subclass
(
self
):
...
...
@@ -274,7 +274,7 @@ class CommonMiddlewareTest(TestCase):
request
=
self
.
rf
.
get
(
'/slash'
)
r
=
MyCommonMiddleware
()
.
process_request
(
request
)
self
.
assertEqual
(
r
.
status_code
,
302
)
self
.
assertEqual
(
r
.
url
,
'
http://testserver
/slash/'
)
self
.
assertEqual
(
r
.
url
,
'/slash/'
)
self
.
assertIsInstance
(
r
,
HttpResponseRedirect
)
...
...
tests/test_client/tests.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -176,40 +176,27 @@ class ClientTest(TestCase):
def
test_redirect
(
self
):
"GET a URL that redirects elsewhere"
response
=
self
.
client
.
get
(
'/redirect_view/'
)
# Check that the response was a 302 (redirect) and that
# assertRedirect() understands to put an implicit http://testserver/ in
# front of non-absolute URLs.
# Check that the response was a 302 (redirect)
self
.
assertRedirects
(
response
,
'/get_view/'
)
host
=
'django.testserver'
client_providing_host
=
Client
(
HTTP_HOST
=
host
)
response
=
client_providing_host
.
get
(
'/redirect_view/'
)
# Check that the response was a 302 (redirect) with absolute URI
self
.
assertRedirects
(
response
,
'/get_view/'
,
host
=
host
)
def
test_redirect_with_query
(
self
):
"GET a URL that redirects with given GET parameters"
response
=
self
.
client
.
get
(
'/redirect_view/'
,
{
'var'
:
'value'
})
# Check if parameters are intact
self
.
assertRedirects
(
response
,
'
http://testserver
/get_view/?var=value'
)
self
.
assertRedirects
(
response
,
'/get_view/?var=value'
)
def
test_permanent_redirect
(
self
):
"GET a URL that redirects permanently elsewhere"
response
=
self
.
client
.
get
(
'/permanent_redirect_view/'
)
# Check that the response was a 301 (permanent redirect)
self
.
assertRedirects
(
response
,
'http://testserver/get_view/'
,
status_code
=
301
)
client_providing_host
=
Client
(
HTTP_HOST
=
'django.testserver'
)
response
=
client_providing_host
.
get
(
'/permanent_redirect_view/'
)
# Check that the response was a 301 (permanent redirect) with absolute URI
self
.
assertRedirects
(
response
,
'http://django.testserver/get_view/'
,
status_code
=
301
)
self
.
assertRedirects
(
response
,
'/get_view/'
,
status_code
=
301
)
def
test_temporary_redirect
(
self
):
"GET a URL that does a non-permanent redirect"
response
=
self
.
client
.
get
(
'/temporary_redirect_view/'
)
# Check that the response was a 302 (non-permanent redirect)
self
.
assertRedirects
(
response
,
'
http://testserver
/get_view/'
,
status_code
=
302
)
self
.
assertRedirects
(
response
,
'/get_view/'
,
status_code
=
302
)
def
test_redirect_to_strange_location
(
self
):
"GET a URL that redirects to a non-200 page"
...
...
@@ -217,12 +204,12 @@ class ClientTest(TestCase):
# Check that the response was a 302, and that
# the attempt to get the redirection location returned 301 when retrieved
self
.
assertRedirects
(
response
,
'
http://testserver
/permanent_redirect_view/'
,
target_status_code
=
301
)
self
.
assertRedirects
(
response
,
'/permanent_redirect_view/'
,
target_status_code
=
301
)
def
test_follow_redirect
(
self
):
"A URL that redirects can be followed to termination."
response
=
self
.
client
.
get
(
'/double_redirect_view/'
,
follow
=
True
)
self
.
assertRedirects
(
response
,
'
http://testserver
/get_view/'
,
status_code
=
302
,
target_status_code
=
200
)
self
.
assertRedirects
(
response
,
'/get_view/'
,
status_code
=
302
,
target_status_code
=
200
)
self
.
assertEqual
(
len
(
response
.
redirect_chain
),
2
)
def
test_redirect_http
(
self
):
...
...
@@ -364,7 +351,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response
=
self
.
client
.
get
(
'/login_protected_view/'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/accounts/login/?next=/login_protected_view/'
)
self
.
assertRedirects
(
response
,
'/accounts/login/?next=/login_protected_view/'
)
# Log in
login
=
self
.
client
.
login
(
username
=
'testclient'
,
password
=
'password'
)
...
...
@@ -380,7 +367,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response
=
self
.
client
.
get
(
'/login_protected_method_view/'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/accounts/login/?next=/login_protected_method_view/'
)
self
.
assertRedirects
(
response
,
'/accounts/login/?next=/login_protected_method_view/'
)
# Log in
login
=
self
.
client
.
login
(
username
=
'testclient'
,
password
=
'password'
)
...
...
@@ -396,7 +383,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response
=
self
.
client
.
get
(
'/login_protected_view_custom_redirect/'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/accounts/login/?redirect_to=/login_protected_view_custom_redirect/'
)
self
.
assertRedirects
(
response
,
'/accounts/login/?redirect_to=/login_protected_view_custom_redirect/'
)
# Log in
login
=
self
.
client
.
login
(
username
=
'testclient'
,
password
=
'password'
)
...
...
@@ -434,7 +421,7 @@ class ClientTest(TestCase):
# Request a page that requires a login
response
=
self
.
client
.
get
(
'/login_protected_view/'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/accounts/login/?next=/login_protected_view/'
)
self
.
assertRedirects
(
response
,
'/accounts/login/?next=/login_protected_view/'
)
@override_settings
(
SESSION_ENGINE
=
"django.contrib.sessions.backends.signed_cookies"
)
def
test_logout_cookie_sessions
(
self
):
...
...
@@ -445,7 +432,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response
=
self
.
client
.
get
(
'/permission_protected_view/'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/accounts/login/?next=/permission_protected_view/'
)
self
.
assertRedirects
(
response
,
'/accounts/login/?next=/permission_protected_view/'
)
# Log in
login
=
self
.
client
.
login
(
username
=
'testclient'
,
password
=
'password'
)
...
...
@@ -453,7 +440,7 @@ class ClientTest(TestCase):
# Log in with wrong permissions. Should result in 302.
response
=
self
.
client
.
get
(
'/permission_protected_view/'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/accounts/login/?next=/permission_protected_view/'
)
self
.
assertRedirects
(
response
,
'/accounts/login/?next=/permission_protected_view/'
)
# TODO: Log in with right permissions and request the page again
...
...
@@ -477,7 +464,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response
=
self
.
client
.
get
(
'/permission_protected_method_view/'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/accounts/login/?next=/permission_protected_method_view/'
)
self
.
assertRedirects
(
response
,
'/accounts/login/?next=/permission_protected_method_view/'
)
# Log in
login
=
self
.
client
.
login
(
username
=
'testclient'
,
password
=
'password'
)
...
...
@@ -485,7 +472,7 @@ class ClientTest(TestCase):
# Log in with wrong permissions. Should result in 302.
response
=
self
.
client
.
get
(
'/permission_protected_method_view/'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/accounts/login/?next=/permission_protected_method_view/'
)
self
.
assertRedirects
(
response
,
'/accounts/login/?next=/permission_protected_method_view/'
)
# TODO: Log in with right permissions and request the page again
...
...
tests/test_client_regress/tests.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -18,7 +18,9 @@ from django.test import Client, TestCase, ignore_warnings, override_settings
from
django.test.client
import
RedirectCycleError
,
RequestFactory
,
encode_file
from
django.test.utils
import
ContextList
,
str_prefix
from
django.utils._os
import
upath
from
django.utils.deprecation
import
RemovedInDjango20Warning
from
django.utils.deprecation
import
(
RemovedInDjango20Warning
,
RemovedInDjango21Warning
,
)
from
django.utils.translation
import
ugettext_lazy
from
.models
import
CustomUser
...
...
@@ -342,12 +344,12 @@ class AssertRedirectsTests(TestCase):
try
:
self
.
assertRedirects
(
response
,
'/get_view/'
)
except
AssertionError
as
e
:
self
.
assertIn
(
"Response redirected to '
http://testserver/get_view/?var=value', expected 'http://testserver
/get_view/'"
,
str
(
e
))
self
.
assertIn
(
"Response redirected to '
/get_view/?var=value', expected '
/get_view/'"
,
str
(
e
))
try
:
self
.
assertRedirects
(
response
,
'/get_view/'
,
msg_prefix
=
'abc'
)
except
AssertionError
as
e
:
self
.
assertIn
(
"abc: Response redirected to '
http://testserver/get_view/?var=value', expected 'http://testserver
/get_view/'"
,
str
(
e
))
self
.
assertIn
(
"abc: Response redirected to '
/get_view/?var=value', expected '
/get_view/'"
,
str
(
e
))
def
test_incorrect_target
(
self
):
"An assertion is raised if the response redirects to another target"
...
...
@@ -380,7 +382,7 @@ class AssertRedirectsTests(TestCase):
status_code
=
302
,
target_status_code
=
200
)
self
.
assertEqual
(
len
(
response
.
redirect_chain
),
1
)
self
.
assertEqual
(
response
.
redirect_chain
[
0
],
(
'
http://testserver
/no_template_view/'
,
302
))
self
.
assertEqual
(
response
.
redirect_chain
[
0
],
(
'/no_template_view/'
,
302
))
def
test_multiple_redirect_chain
(
self
):
"You can follow a redirect chain of multiple redirects"
...
...
@@ -389,9 +391,9 @@ class AssertRedirectsTests(TestCase):
status_code
=
302
,
target_status_code
=
200
)
self
.
assertEqual
(
len
(
response
.
redirect_chain
),
3
)
self
.
assertEqual
(
response
.
redirect_chain
[
0
],
(
'
http://testserver
/redirects/further/'
,
302
))
self
.
assertEqual
(
response
.
redirect_chain
[
1
],
(
'
http://testserver
/redirects/further/more/'
,
302
))
self
.
assertEqual
(
response
.
redirect_chain
[
2
],
(
'
http://testserver
/no_template_view/'
,
302
))
self
.
assertEqual
(
response
.
redirect_chain
[
0
],
(
'/redirects/further/'
,
302
))
self
.
assertEqual
(
response
.
redirect_chain
[
1
],
(
'/redirects/further/more/'
,
302
))
self
.
assertEqual
(
response
.
redirect_chain
[
2
],
(
'/no_template_view/'
,
302
))
def
test_redirect_chain_to_non_existent
(
self
):
"You can follow a chain to a non-existent view"
...
...
@@ -507,21 +509,24 @@ class AssertRedirectsTests(TestCase):
def
test_redirect_scheme
(
self
):
"An assertion is raised if the response doesn't have the scheme specified in expected_url"
# Assure that original request scheme is preserved if no scheme specified in the redirect location
response
=
self
.
client
.
get
(
'/redirect_view/'
,
secure
=
True
)
self
.
assertRedirects
(
response
,
'https://testserver/get_view/'
)
# For all possible True/False combinations of follow and secure
for
follow
,
secure
in
itertools
.
product
([
True
,
False
],
repeat
=
2
):
# always redirects to https
response
=
self
.
client
.
get
(
'/https_redirect_view/'
,
follow
=
follow
,
secure
=
secure
)
# no scheme to compare too, always succeeds
self
.
assertRedirects
(
response
,
'/secure_view/'
,
status_code
=
302
)
# the goal scheme is https
self
.
assertRedirects
(
response
,
'https://testserver/secure_view/'
,
status_code
=
302
)
with
self
.
assertRaises
(
AssertionError
):
self
.
assertRedirects
(
response
,
'http://testserver/secure_view/'
,
status_code
=
302
)
@ignore_warnings
(
category
=
RemovedInDjango21Warning
)
def
test_full_path_in_expected_urls
(
self
):
"""
Test that specifying a full URL as assertRedirects expected_url still
work as backwards compatible behavior until Django 2.1.
"""
response
=
self
.
client
.
get
(
'/redirect_view/'
)
self
.
assertRedirects
(
response
,
'http://testserver/get_view/'
)
@override_settings
(
ROOT_URLCONF
=
'test_client_regress.urls'
)
class
AssertFormErrorTests
(
TestCase
):
...
...
@@ -852,7 +857,7 @@ class LoginTests(TestDataMixin, TestCase):
# At this points, the self.client isn't logged in.
# Check that assertRedirects uses the original client, not the
# default client.
self
.
assertRedirects
(
response
,
"
http://testserver
/get_view/"
)
self
.
assertRedirects
(
response
,
"/get_view/"
)
@override_settings
(
...
...
tests/view_tests/generic_urls.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -32,7 +32,6 @@ urlpatterns = [
url
(
r'^accounts/logout/$'
,
auth_views
.
logout
),
# Special URLs for particular regression cases.
url
(
'^中文/$'
,
views
.
redirect
),
url
(
'^中文/target/$'
,
views
.
index_page
),
]
...
...
tests/view_tests/tests/test_i18n.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -31,7 +31,7 @@ class I18NTests(TestCase):
for
lang_code
,
lang_name
in
settings
.
LANGUAGES
:
post_data
=
dict
(
language
=
lang_code
,
next
=
'/'
)
response
=
self
.
client
.
post
(
'/i18n/setlang/'
,
data
=
post_data
)
self
.
assertRedirects
(
response
,
'
http://testserver
/'
)
self
.
assertRedirects
(
response
,
'/'
)
self
.
assertEqual
(
self
.
client
.
session
[
LANGUAGE_SESSION_KEY
],
lang_code
)
def
test_setlang_unsafe_next
(
self
):
...
...
@@ -42,7 +42,7 @@ class I18NTests(TestCase):
lang_code
,
lang_name
=
settings
.
LANGUAGES
[
0
]
post_data
=
dict
(
language
=
lang_code
,
next
=
'//unsafe/redirection/'
)
response
=
self
.
client
.
post
(
'/i18n/setlang/'
,
data
=
post_data
)
self
.
assertEqual
(
response
.
url
,
'
http://testserver
/'
)
self
.
assertEqual
(
response
.
url
,
'/'
)
self
.
assertEqual
(
self
.
client
.
session
[
LANGUAGE_SESSION_KEY
],
lang_code
)
def
test_setlang_reversal
(
self
):
...
...
@@ -76,13 +76,13 @@ class I18NTests(TestCase):
follow
=
True
,
HTTP_REFERER
=
'/en/translated/'
)
self
.
assertEqual
(
self
.
client
.
session
[
LANGUAGE_SESSION_KEY
],
'nl'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/nl/vertaald/'
)
self
.
assertRedirects
(
response
,
'/nl/vertaald/'
)
# And reverse
response
=
self
.
client
.
post
(
'/i18n/setlang/'
,
data
=
{
'language'
:
'en'
},
follow
=
True
,
HTTP_REFERER
=
'/nl/vertaald/'
)
self
.
assertRedirects
(
response
,
'
http://testserver
/en/translated/'
)
self
.
assertRedirects
(
response
,
'/en/translated/'
)
def
test_jsi18n
(
self
):
"""The javascript_catalog can be deployed with language settings"""
...
...
tests/view_tests/tests/test_specials.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -11,17 +11,6 @@ class URLHandling(TestCase):
"""
redirect_target
=
"/
%
E4
%
B8
%
AD
%
E6
%96%87
/target/"
def
test_combining_redirect
(
self
):
"""
Tests that redirecting to an IRI, requiring encoding before we use it
in an HTTP response, is handled correctly. In this case the arg to
HttpRedirect is ASCII but the current request path contains non-ASCII
characters so this test ensures the creation of the full path with a
base non-ASCII part is handled correctly.
"""
response
=
self
.
client
.
get
(
'/中文/'
)
self
.
assertRedirects
(
response
,
self
.
redirect_target
)
def
test_nonascii_redirect
(
self
):
"""
Tests that a non-ASCII argument to HttpRedirect is handled properly.
...
...
tests/view_tests/views.py
Dosyayı görüntüle @
a0c2eb46
...
...
@@ -6,9 +6,7 @@ import sys
from
django.core.exceptions
import
PermissionDenied
,
SuspiciousOperation
from
django.core.urlresolvers
import
get_resolver
from
django.http
import
(
Http404
,
HttpResponse
,
HttpResponseRedirect
,
JsonResponse
,
)
from
django.http
import
Http404
,
HttpResponse
,
JsonResponse
from
django.shortcuts
import
render
,
render_to_response
from
django.template
import
TemplateDoesNotExist
from
django.utils.log
import
getLogger
...
...
@@ -71,13 +69,6 @@ class Http404View(View):
raise
Http404
(
"Testing class-based technical 404."
)
def
redirect
(
request
):
"""
Forces an HTTP redirect.
"""
return
HttpResponseRedirect
(
"target/"
)
def
view_exception
(
request
,
n
):
raise
BrokenException
(
except_args
[
int
(
n
)])
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment