Translation of UI (german and english)
Bugfix for feeds
- removed categories related and up
- load new books now working
- category random now working
login page is free of non accessible elements
boolean custom column is vivible in UI
books with only with certain languages can be shown
book shelfs can be deleted from UI
Anonymous user view is more resticted
Added browse of series in sidebar
Dependencys in vendor folder are updated to newer versions (licencs files are now present)
Bugfix editing Authors names
Made upload on windows working
This commit is contained in:
Vendored
+155
-28
@@ -3,16 +3,24 @@
|
||||
werkzeug.urls
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
This module implements various URL related functions.
|
||||
``werkzeug.urls`` used to provide several wrapper functions for Python 2
|
||||
urlparse, whose main purpose were to work around the behavior of the Py2
|
||||
stdlib and its lack of unicode support. While this was already a somewhat
|
||||
inconvenient situation, it got even more complicated because Python 3's
|
||||
``urllib.parse`` actually does handle unicode properly. In other words,
|
||||
this module would wrap two libraries with completely different behavior. So
|
||||
now this module contains a 2-and-3-compatible backport of Python 3's
|
||||
``urllib.parse``, which is mostly API-compatible.
|
||||
|
||||
:copyright: (c) 2013 by the Werkzeug Team, see AUTHORS for more details.
|
||||
:copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
from werkzeug._compat import text_type, PY2, to_unicode, \
|
||||
to_native, implements_to_string, try_coerce_native, \
|
||||
normalize_string_tuple, make_literal_wrapper, \
|
||||
fix_tuple_repr
|
||||
to_native, implements_to_string, try_coerce_native, \
|
||||
normalize_string_tuple, make_literal_wrapper, \
|
||||
fix_tuple_repr
|
||||
from werkzeug._internal import _encode_idna, _decode_idna
|
||||
from werkzeug.datastructures import MultiDict, iter_multi_items
|
||||
from collections import namedtuple
|
||||
@@ -32,11 +40,15 @@ _hextobyte = dict(
|
||||
)
|
||||
|
||||
|
||||
_URLTuple = fix_tuple_repr(namedtuple('_URLTuple',
|
||||
['scheme', 'netloc', 'path', 'query', 'fragment']))
|
||||
_URLTuple = fix_tuple_repr(namedtuple(
|
||||
'_URLTuple',
|
||||
['scheme', 'netloc', 'path', 'query', 'fragment']
|
||||
))
|
||||
|
||||
|
||||
class _URLMixin(object):
|
||||
class BaseURL(_URLTuple):
|
||||
|
||||
'''Superclass of :py:class:`URL` and :py:class:`BytesURL`.'''
|
||||
__slots__ = ()
|
||||
|
||||
def replace(self, **kwargs):
|
||||
@@ -61,7 +73,10 @@ class _URLMixin(object):
|
||||
"""
|
||||
rv = self.host
|
||||
if rv is not None and isinstance(rv, text_type):
|
||||
rv = _encode_idna(rv)
|
||||
try:
|
||||
rv = _encode_idna(rv)
|
||||
except UnicodeError:
|
||||
rv = rv.encode('ascii', 'ignore')
|
||||
return to_native(rv, 'ascii', 'ignore')
|
||||
|
||||
@property
|
||||
@@ -174,6 +189,64 @@ class _URLMixin(object):
|
||||
"""
|
||||
return url_parse(uri_to_iri(self))
|
||||
|
||||
def get_file_location(self, pathformat=None):
|
||||
"""Returns a tuple with the location of the file in the form
|
||||
``(server, location)``. If the netloc is empty in the URL or
|
||||
points to localhost, it's represented as ``None``.
|
||||
|
||||
The `pathformat` by default is autodetection but needs to be set
|
||||
when working with URLs of a specific system. The supported values
|
||||
are ``'windows'`` when working with Windows or DOS paths and
|
||||
``'posix'`` when working with posix paths.
|
||||
|
||||
If the URL does not point to to a local file, the server and location
|
||||
are both represented as ``None``.
|
||||
|
||||
:param pathformat: The expected format of the path component.
|
||||
Currently ``'windows'`` and ``'posix'`` are
|
||||
supported. Defaults to ``None`` which is
|
||||
autodetect.
|
||||
"""
|
||||
if self.scheme != 'file':
|
||||
return None, None
|
||||
|
||||
path = url_unquote(self.path)
|
||||
host = self.netloc or None
|
||||
|
||||
if pathformat is None:
|
||||
if os.name == 'nt':
|
||||
pathformat = 'windows'
|
||||
else:
|
||||
pathformat = 'posix'
|
||||
|
||||
if pathformat == 'windows':
|
||||
if path[:1] == '/' and path[1:2].isalpha() and path[2:3] in '|:':
|
||||
path = path[1:2] + ':' + path[3:]
|
||||
windows_share = path[:3] in ('\\' * 3, '/' * 3)
|
||||
import ntpath
|
||||
path = ntpath.normpath(path)
|
||||
# Windows shared drives are represented as ``\\host\\directory``.
|
||||
# That results in a URL like ``file://///host/directory``, and a
|
||||
# path like ``///host/directory``. We need to special-case this
|
||||
# because the path contains the hostname.
|
||||
if windows_share and host is None:
|
||||
parts = path.lstrip('\\').split('\\', 1)
|
||||
if len(parts) == 2:
|
||||
host, path = parts
|
||||
else:
|
||||
host = parts[0]
|
||||
path = ''
|
||||
elif pathformat == 'posix':
|
||||
import posixpath
|
||||
path = posixpath.normpath(path)
|
||||
else:
|
||||
raise TypeError('Invalid path format %s' % repr(pathformat))
|
||||
|
||||
if host in ('127.0.0.1', '::1', 'localhost'):
|
||||
host = None
|
||||
|
||||
return host, path
|
||||
|
||||
def _split_netloc(self):
|
||||
if self._at in self.netloc:
|
||||
return self.netloc.split(self._at, 1)
|
||||
@@ -209,7 +282,8 @@ class _URLMixin(object):
|
||||
|
||||
|
||||
@implements_to_string
|
||||
class URL(_URLTuple, _URLMixin):
|
||||
class URL(BaseURL):
|
||||
|
||||
"""Represents a parsed URL. This behaves like a regular tuple but
|
||||
also has some extra attributes that give further insight into the
|
||||
URL.
|
||||
@@ -237,7 +311,7 @@ class URL(_URLTuple, _URLMixin):
|
||||
]))
|
||||
if auth:
|
||||
rv = '%s@%s' % (auth, rv)
|
||||
return rv.encode('ascii')
|
||||
return to_native(rv)
|
||||
|
||||
def encode(self, charset='utf-8', errors='replace'):
|
||||
"""Encodes the URL to a tuple made out of bytes. The charset is
|
||||
@@ -252,7 +326,8 @@ class URL(_URLTuple, _URLMixin):
|
||||
)
|
||||
|
||||
|
||||
class BytesURL(_URLTuple, _URLMixin):
|
||||
class BytesURL(BaseURL):
|
||||
|
||||
"""Represents a parsed URL in bytes."""
|
||||
__slots__ = ()
|
||||
_at = b'@'
|
||||
@@ -312,7 +387,7 @@ def _url_encode_impl(obj, charset, encode_keys, sort, key):
|
||||
key = text_type(key).encode(charset)
|
||||
if not isinstance(value, bytes):
|
||||
value = text_type(value).encode(charset)
|
||||
yield url_quote(key) + '=' + url_quote_plus(value)
|
||||
yield url_quote_plus(key) + '=' + url_quote_plus(value)
|
||||
|
||||
|
||||
def _url_unquote_legacy(value, unsafe=''):
|
||||
@@ -358,8 +433,8 @@ def url_parse(url, scheme=None, allow_fragments=True):
|
||||
if wdelim >= 0:
|
||||
delim = min(delim, wdelim)
|
||||
netloc, url = url[2:delim], url[delim:]
|
||||
if ((s('[') in netloc and s(']') not in netloc) or
|
||||
(s(']') in netloc and s('[') not in netloc)):
|
||||
if (s('[') in netloc and s(']') not in netloc) or \
|
||||
(s(']') in netloc and s('[') not in netloc):
|
||||
raise ValueError('Invalid IPv6 URL')
|
||||
|
||||
if allow_fragments and s('#') in url:
|
||||
@@ -371,12 +446,16 @@ def url_parse(url, scheme=None, allow_fragments=True):
|
||||
return result_type(scheme, netloc, url, query, fragment)
|
||||
|
||||
|
||||
def url_quote(string, charset='utf-8', errors='strict', safe='/:'):
|
||||
def url_quote(string, charset='utf-8', errors='strict', safe='/:', unsafe=''):
|
||||
"""URL encode a single string with a given encoding.
|
||||
|
||||
:param s: the string to quote.
|
||||
:param charset: the charset to be used.
|
||||
:param safe: an optional sequence of safe characters.
|
||||
:param unsafe: an optional sequence of unsafe characters.
|
||||
|
||||
.. versionadded:: 0.9.2
|
||||
The `unsafe` parameter was added.
|
||||
"""
|
||||
if not isinstance(string, (text_type, bytes, bytearray)):
|
||||
string = text_type(string)
|
||||
@@ -384,7 +463,9 @@ def url_quote(string, charset='utf-8', errors='strict', safe='/:'):
|
||||
string = string.encode(charset, errors)
|
||||
if isinstance(safe, text_type):
|
||||
safe = safe.encode(charset, errors)
|
||||
safe = frozenset(bytearray(safe) + _always_safe)
|
||||
if isinstance(unsafe, text_type):
|
||||
unsafe = unsafe.encode(charset, errors)
|
||||
safe = frozenset(bytearray(safe) + _always_safe) - frozenset(bytearray(unsafe))
|
||||
rv = bytearray()
|
||||
for char in bytearray(string):
|
||||
if char in safe:
|
||||
@@ -402,7 +483,7 @@ def url_quote_plus(string, charset='utf-8', errors='strict', safe=''):
|
||||
:param charset: The charset to be used.
|
||||
:param safe: An optional sequence of safe characters.
|
||||
"""
|
||||
return url_quote(string, charset, errors, safe + ' ').replace(' ', '+')
|
||||
return url_quote(string, charset, errors, safe + ' ', '+').replace(' ', '+')
|
||||
|
||||
|
||||
def url_unparse(components):
|
||||
@@ -485,10 +566,22 @@ def url_fix(s, charset='utf-8'):
|
||||
:param charset: The target charset for the URL if the url was given as
|
||||
unicode string.
|
||||
"""
|
||||
scheme, netloc, path, qs, anchor = url_parse(to_unicode(s, charset, 'replace'))
|
||||
path = url_quote(path, charset, safe='/%+$!*\'(),')
|
||||
qs = url_quote_plus(qs, charset, safe=':&%=+$!*\'(),')
|
||||
return to_native(url_unparse((scheme, netloc, path, qs, anchor)))
|
||||
# First step is to switch to unicode processing and to convert
|
||||
# backslashes (which are invalid in URLs anyways) to slashes. This is
|
||||
# consistent with what Chrome does.
|
||||
s = to_unicode(s, charset, 'replace').replace('\\', '/')
|
||||
|
||||
# For the specific case that we look like a malformed windows URL
|
||||
# we want to fix this up manually:
|
||||
if s.startswith('file://') and s[7:8].isalpha() and s[8:10] in (':/', '|/'):
|
||||
s = 'file:///' + s[7:]
|
||||
|
||||
url = url_parse(s)
|
||||
path = url_quote(url.path, charset, safe='/%+$!*\'(),')
|
||||
qs = url_quote_plus(url.query, charset, safe=':&%=+$!*\'(),')
|
||||
anchor = url_quote_plus(url.fragment, charset, safe=':&%=+$!*\'(),')
|
||||
return to_native(url_unparse((url.scheme, url.encode_netloc(),
|
||||
path, qs, anchor)))
|
||||
|
||||
|
||||
def uri_to_iri(uri, charset='utf-8', errors='replace'):
|
||||
@@ -516,14 +609,14 @@ def uri_to_iri(uri, charset='utf-8', errors='replace'):
|
||||
if isinstance(uri, tuple):
|
||||
uri = url_unparse(uri)
|
||||
uri = url_parse(to_unicode(uri, charset))
|
||||
path = url_unquote(uri.path, charset, errors, '/;?')
|
||||
query = url_unquote(uri.query, charset, errors, ';/?:@&=+,$')
|
||||
fragment = url_unquote(uri.fragment, charset, errors, ';/?:@&=+,$')
|
||||
path = url_unquote(uri.path, charset, errors, '%/;?')
|
||||
query = url_unquote(uri.query, charset, errors, '%;/?:@&=+,$#')
|
||||
fragment = url_unquote(uri.fragment, charset, errors, '%;/?:@&=+,$#')
|
||||
return url_unparse((uri.scheme, uri.decode_netloc(),
|
||||
path, query, fragment))
|
||||
|
||||
|
||||
def iri_to_uri(iri, charset='utf-8', errors='strict'):
|
||||
def iri_to_uri(iri, charset='utf-8', errors='strict', safe_conversion=False):
|
||||
r"""
|
||||
Converts any unicode based IRI to an acceptable ASCII URI. Werkzeug always
|
||||
uses utf-8 URLs internally because this is what browsers and HTTP do as
|
||||
@@ -537,16 +630,49 @@ def iri_to_uri(iri, charset='utf-8', errors='strict'):
|
||||
>>> iri_to_uri(u'http://üser:pässword@☃.net/påth')
|
||||
'http://%C3%BCser:p%C3%A4ssword@xn--n3h.net/p%C3%A5th'
|
||||
|
||||
There is a general problem with IRI and URI conversion with some
|
||||
protocols that appear in the wild that are in violation of the URI
|
||||
specification. In places where Werkzeug goes through a forced IRI to
|
||||
URI conversion it will set the `safe_conversion` flag which will
|
||||
not perform a conversion if the end result is already ASCII. This
|
||||
can mean that the return value is not an entirely correct URI but
|
||||
it will not destroy such invalid URLs in the process.
|
||||
|
||||
As an example consider the following two IRIs::
|
||||
|
||||
magnet:?xt=uri:whatever
|
||||
itms-services://?action=download-manifest
|
||||
|
||||
The internal representation after parsing of those URLs is the same
|
||||
and there is no way to reconstruct the original one. If safe
|
||||
conversion is enabled however this function becomes a noop for both of
|
||||
those strings as they both can be considered URIs.
|
||||
|
||||
.. versionadded:: 0.6
|
||||
|
||||
.. versionchanged:: 0.9.6
|
||||
The `safe_conversion` parameter was added.
|
||||
|
||||
:param iri: The IRI to convert.
|
||||
:param charset: The charset for the URI.
|
||||
:param safe_conversion: indicates if a safe conversion should take place.
|
||||
For more information see the explanation above.
|
||||
"""
|
||||
if isinstance(iri, tuple):
|
||||
iri = url_unparse(iri)
|
||||
|
||||
if safe_conversion:
|
||||
try:
|
||||
native_iri = to_native(iri)
|
||||
ascii_iri = to_native(iri).encode('ascii')
|
||||
if ascii_iri.split() == [ascii_iri]:
|
||||
return native_iri
|
||||
except UnicodeError:
|
||||
pass
|
||||
|
||||
iri = url_parse(to_unicode(iri, charset, errors))
|
||||
|
||||
netloc = iri.encode_netloc().decode('ascii')
|
||||
netloc = iri.encode_netloc()
|
||||
path = url_quote(iri.path, charset, errors, '/:~+%')
|
||||
query = url_quote(iri.query, charset, errors, '%&[]:;$*()+,!?*/=')
|
||||
fragment = url_quote(iri.fragment, charset, errors, '=%&[]:;$()+,!?*/')
|
||||
@@ -789,6 +915,7 @@ def url_join(base, url, allow_fragments=True):
|
||||
|
||||
|
||||
class Href(object):
|
||||
|
||||
"""Implements a callable that constructs URLs with the given base. The
|
||||
function can be called with any number of positional and keyword
|
||||
arguments which than are used to assemble the URL. Works with URLs
|
||||
@@ -865,7 +992,7 @@ class Href(object):
|
||||
query = dict([(k.endswith('_') and k[:-1] or k, v)
|
||||
for k, v in query.items()])
|
||||
path = '/'.join([to_unicode(url_quote(x, self.charset), 'ascii')
|
||||
for x in path if x is not None]).lstrip('/')
|
||||
for x in path if x is not None]).lstrip('/')
|
||||
rv = self.base
|
||||
if path:
|
||||
if not rv.endswith('/'):
|
||||
|
||||
Reference in New Issue
Block a user