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:
OzzieIsaacs
2016-11-09 19:24:33 +01:00
parent a6b6700a73
commit bbf6d9b026
1690 changed files with 149106 additions and 35697 deletions
+112 -30
View File
@@ -5,18 +5,20 @@
This module provides mixins and classes with an immutable interface.
: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 re
import sys
import codecs
import mimetypes
from copy import deepcopy
from itertools import repeat
from werkzeug._internal import _missing, _empty_stream
from werkzeug._compat import iterkeys, itervalues, iteritems, iterlists, \
PY2, text_type, integer_types, string_types, make_literal_wrapper
PY2, text_type, integer_types, string_types, make_literal_wrapper, \
to_native
from werkzeug.filesystem import get_filesystem_encoding
_locale_delim_re = re.compile(r'[_-]')
@@ -48,12 +50,13 @@ def iter_multi_items(mapping):
def native_itermethods(names):
if not PY2:
return lambda x: x
def setmethod(cls, name):
itermethod = getattr(cls, name)
setattr(cls, 'iter%s' % name, itermethod)
listmethod = lambda self, *a, **kw: list(itermethod(self, *a, **kw))
listmethod.__doc__ = \
'Like :py:meth:`iter%s`, but returns a list.' % name
'Like :py:meth:`iter%s`, but returns a list.' % name
setattr(cls, name, listmethod)
def wrap(cls):
@@ -64,6 +67,7 @@ def native_itermethods(names):
class ImmutableListMixin(object):
"""Makes a :class:`list` immutable.
.. versionadded:: 0.5
@@ -119,6 +123,7 @@ class ImmutableListMixin(object):
class ImmutableList(ImmutableListMixin, list):
"""An immutable :class:`list`.
.. versionadded:: 0.5
@@ -129,11 +134,12 @@ class ImmutableList(ImmutableListMixin, list):
def __repr__(self):
return '%s(%s)' % (
self.__class__.__name__,
dict.__repr__(self),
list.__repr__(self),
)
class ImmutableDictMixin(object):
"""Makes a :class:`dict` immutable.
.. versionadded:: 0.5
@@ -183,6 +189,7 @@ class ImmutableDictMixin(object):
class ImmutableMultiDictMixin(ImmutableDictMixin):
"""Makes a :class:`MultiDict` immutable.
.. versionadded:: 0.5
@@ -213,6 +220,7 @@ class ImmutableMultiDictMixin(ImmutableDictMixin):
class UpdateDictMixin(object):
"""Makes dicts call `self.on_update` on modifications.
.. versionadded:: 0.5
@@ -257,6 +265,7 @@ class UpdateDictMixin(object):
class TypeConversionDict(dict):
"""Works like a regular dict but the :meth:`get` method can perform
type conversions. :class:`MultiDict` and :class:`CombinedMultiDict`
are subclasses of this class and provide the same feature.
@@ -295,6 +304,7 @@ class TypeConversionDict(dict):
class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict):
"""Works like a :class:`TypeConversionDict` but does not support
modifications.
@@ -314,6 +324,7 @@ class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict):
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
class MultiDict(TypeConversionDict):
"""A :class:`MultiDict` is a dictionary subclass customized to deal with
multiple values for the same key which is for example used by the parsing
functions in the wrappers. This is necessary because some HTML form
@@ -361,6 +372,8 @@ class MultiDict(TypeConversionDict):
tmp = {}
for key, value in iteritems(mapping):
if isinstance(value, (tuple, list)):
if len(value) == 0:
continue
value = list(value)
else:
value = [value]
@@ -387,7 +400,9 @@ class MultiDict(TypeConversionDict):
:raise KeyError: if the key does not exist.
"""
if key in self:
return dict.__getitem__(self, key)[0]
lst = dict.__getitem__(self, key)
if len(lst) > 0:
return lst[0]
raise exceptions.BadRequestKeyError(key)
def __setitem__(self, key, value):
@@ -537,6 +552,10 @@ class MultiDict(TypeConversionDict):
"""Return a shallow copy of this object."""
return self.__class__(self)
def deepcopy(self, memo=None):
"""Return a deep copy of this object."""
return self.__class__(deepcopy(self.to_dict(flat=False), memo))
def to_dict(self, flat=True):
"""Return the contents as regular dict. If `flat` is `True` the
returned dict will only have the first item present, if `flat` is
@@ -552,7 +571,23 @@ class MultiDict(TypeConversionDict):
return dict(self.lists())
def update(self, other_dict):
"""update() extends rather than replaces existing key lists."""
"""update() extends rather than replaces existing key lists:
>>> a = MultiDict({'x': 1})
>>> b = MultiDict({'x': 2, 'y': 3})
>>> a.update(b)
>>> a
MultiDict([('y', 3), ('x', 1), ('x', 2)])
If the value list for a key in ``other_dict`` is empty, no new values
will be added to the dict and the key will not be created:
>>> x = {'empty_list': []}
>>> y = MultiDict()
>>> y.update(x)
>>> y
MultiDict([])
"""
for key, value in iter_multi_items(other_dict):
MultiDict.add(self, key, value)
@@ -605,11 +640,15 @@ class MultiDict(TypeConversionDict):
def __copy__(self):
return self.copy()
def __deepcopy__(self, memo):
return self.deepcopy(memo=memo)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, list(iteritems(self, multi=True)))
class _omd_bucket(object):
"""Wraps values in the :class:`OrderedMultiDict`. This makes it
possible to keep an order over multiple different keys. It requires
a lot of extra memory and slows down access a lot, but makes it
@@ -642,6 +681,7 @@ class _omd_bucket(object):
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
class OrderedMultiDict(MultiDict):
"""Works like a regular :class:`MultiDict` but preserves the
order of the fields. To convert the ordered multi dict into a
list you can use the :meth:`items` method and pass it ``multi=True``.
@@ -818,7 +858,7 @@ class OrderedMultiDict(MultiDict):
def _options_header_vkw(value, kw):
return dump_options_header(value, dict((k.replace('_', '-'), v)
for k, v in kw.items()))
for k, v in kw.items()))
def _unicodify_header_value(value):
@@ -831,6 +871,7 @@ def _unicodify_header_value(value):
@native_itermethods(['keys', 'values', 'items'])
class Headers(object):
"""An object that stores some headers. It has a dict-like interface
but is ordered and can store the same keys multiple times.
@@ -892,7 +933,7 @@ class Headers(object):
def __eq__(self, other):
return other.__class__ is self.__class__ and \
set(other._list) == set(self._list)
set(other._list) == set(self._list)
def __ne__(self, other):
return not self.__eq__(other)
@@ -1091,7 +1132,7 @@ class Headers(object):
raise TypeError('Value should be unicode.')
if u'\n' in value or u'\r' in value:
raise ValueError('Detected newline in header value. This is '
'a potential security problem')
'a potential security problem')
def add_header(self, _key, _value, **_kw):
"""Add a new header tuple to the list.
@@ -1182,7 +1223,7 @@ class Headers(object):
:return: list
"""
if PY2:
return [(k, v.encode('latin1')) for k, v in self]
return [(to_native(k), v.encode('latin1')) for k, v in self]
return list(self)
def copy(self):
@@ -1207,6 +1248,7 @@ class Headers(object):
class ImmutableHeadersMixin(object):
"""Makes a :class:`Headers` immutable. We do not mark them as
hashable though since the only usecase for this datastructure
in Werkzeug is a view on a mutable structure.
@@ -1244,6 +1286,7 @@ class ImmutableHeadersMixin(object):
class EnvironHeaders(ImmutableHeadersMixin, Headers):
"""Read only version of the headers from a WSGI environment. This
provides the same interface as `Headers` and is constructed from
a WSGI environment.
@@ -1289,6 +1332,7 @@ class EnvironHeaders(ImmutableHeadersMixin, Headers):
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
"""A read only :class:`MultiDict` that you can pass multiple :class:`MultiDict`
instances as sequence and it will combine the return values of all wrapped
dicts:
@@ -1345,11 +1389,20 @@ class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
rv.extend(d.getlist(key, type))
return rv
def keys(self):
def _keys_impl(self):
"""This function exists so __len__ can be implemented more efficiently,
saving one list creation from an iterator.
Using this for Python 2's ``dict.keys`` behavior would be useless since
`dict.keys` in Python 2 returns a list, while we have a set here.
"""
rv = set()
for d in self.dicts:
rv.update(d.keys())
return iter(rv)
rv.update(iterkeys(d))
return rv
def keys(self):
return iter(self._keys_impl())
__iter__ = keys
@@ -1397,7 +1450,7 @@ class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
return rv
def __len__(self):
return len(self.keys())
return len(self._keys_impl())
def __contains__(self, key):
for d in self.dicts:
@@ -1412,6 +1465,7 @@ class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
class FileMultiDict(MultiDict):
"""A special :class:`MultiDict` that has convenience methods to add
files to it. This is used for :class:`EnvironBuilder` and generally
useful for unittesting.
@@ -1437,13 +1491,14 @@ class FileMultiDict(MultiDict):
file = open(file, 'rb')
if filename and content_type is None:
content_type = mimetypes.guess_type(filename)[0] or \
'application/octet-stream'
'application/octet-stream'
value = FileStorage(file, filename, name, content_type)
self.add(name, value)
class ImmutableDict(ImmutableDictMixin, dict):
"""An immutable :class:`dict`.
.. versionadded:: 0.5
@@ -1467,6 +1522,7 @@ class ImmutableDict(ImmutableDictMixin, dict):
class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict):
"""An immutable :class:`MultiDict`.
.. versionadded:: 0.5
@@ -1484,6 +1540,7 @@ class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict):
class ImmutableOrderedMultiDict(ImmutableMultiDictMixin, OrderedMultiDict):
"""An immutable :class:`OrderedMultiDict`.
.. versionadded:: 0.6
@@ -1505,6 +1562,7 @@ class ImmutableOrderedMultiDict(ImmutableMultiDictMixin, OrderedMultiDict):
@native_itermethods(['values'])
class Accept(ImmutableList):
"""An :class:`Accept` object is just a list subclass for lists of
``(value, quality)`` tuples. It is automatically sorted by quality.
@@ -1641,7 +1699,8 @@ class Accept(ImmutableList):
for client_item, quality in self:
if quality <= best_quality:
break
if self._value_matches(server_item, client_item):
if self._value_matches(server_item, client_item) \
and quality > 0:
best_quality = quality
result = server_item
return result
@@ -1654,6 +1713,7 @@ class Accept(ImmutableList):
class MIMEAccept(Accept):
"""Like :class:`Accept` but with special methods and behavior for
mimetypes.
"""
@@ -1708,6 +1768,7 @@ class MIMEAccept(Accept):
class LanguageAccept(Accept):
"""Like :class:`Accept` but with normalization for languages."""
def _value_matches(self, value, item):
@@ -1717,6 +1778,7 @@ class LanguageAccept(Accept):
class CharsetAccept(Accept):
"""Like :class:`Accept` but with normalization for charsets."""
def _value_matches(self, value, item):
@@ -1738,6 +1800,7 @@ def cache_property(key, empty, type):
class _CacheControl(UpdateDictMixin, dict):
"""Subclass of a dict that stores values for a Cache-Control header. It
has accessors for all the cache-control directives specified in RFC 2616.
The class does not differentiate between request and response directives.
@@ -1822,13 +1885,16 @@ class _CacheControl(UpdateDictMixin, dict):
return self.to_header()
def __repr__(self):
return '<%s %r>' % (
return '<%s %s>' % (
self.__class__.__name__,
self.to_header()
" ".join(
"%s=%r" % (k, v) for k, v in sorted(self.items())
),
)
class RequestCacheControl(ImmutableDictMixin, _CacheControl):
"""A cache control for requests. This is immutable and gives access
to all the request-relevant cache control headers.
@@ -1849,6 +1915,7 @@ class RequestCacheControl(ImmutableDictMixin, _CacheControl):
class ResponseCacheControl(_CacheControl):
"""A cache control for responses. Unlike :class:`RequestCacheControl`
this is mutable and gives access to response-relevant cache control
headers.
@@ -1876,6 +1943,7 @@ _CacheControl.cache_property = staticmethod(cache_property)
class CallbackDict(UpdateDictMixin, dict):
"""A dict that calls a function passed every time something is changed.
The function is passed the dict instance.
"""
@@ -1892,6 +1960,7 @@ class CallbackDict(UpdateDictMixin, dict):
class HeaderSet(object):
"""Similar to the :class:`ETags` class this implements a set-like structure.
Unlike :class:`ETags` this is case insensitive and used for vary, allow, and
content-language headers.
@@ -2045,6 +2114,7 @@ class HeaderSet(object):
class ETags(object):
"""A set that can be used to check if one etag is present in a collection
of etags.
"""
@@ -2094,7 +2164,7 @@ class ETags(object):
return '*'
return ', '.join(
['"%s"' % x for x in self._strong] +
['w/"%s"' % x for x in self._weak]
['W/"%s"' % x for x in self._weak]
)
def __call__(self, etag=None, data=None, include_weak=False):
@@ -2107,9 +2177,11 @@ class ETags(object):
return True
return etag in self._strong
def __nonzero__(self):
def __bool__(self):
return bool(self.star_tag or self._strong or self._weak)
__nonzero__ = __bool__
def __str__(self):
return self.to_header()
@@ -2124,6 +2196,7 @@ class ETags(object):
class IfRange(object):
"""Very simple object that represents the `If-Range` header in parsed
form. It will either have neither a etag or date or one of either but
never both.
@@ -2154,6 +2227,7 @@ class IfRange(object):
class Range(object):
"""Represents a range header. All the methods are only supporting bytes
as unit. It does store multiple ranges but :meth:`range_for_length` will
only work if only one range is provided.
@@ -2209,6 +2283,7 @@ class Range(object):
class ContentRange(object):
"""Represents the content range header.
.. versionadded:: 0.7
@@ -2223,6 +2298,7 @@ class ContentRange(object):
def _callback_property(name):
def fget(self):
return getattr(self, name)
def fset(self, value):
setattr(self, name, value)
if self.on_update is not None:
@@ -2285,6 +2361,7 @@ class ContentRange(object):
class Authorization(ImmutableDictMixin, dict):
"""Represents an `Authorization` header sent by the client. You should
not create this kind of object yourself but use it when it's returned by
the `parse_authorization_header` function.
@@ -2345,10 +2422,11 @@ class Authorization(ImmutableDictMixin, dict):
class WWWAuthenticate(UpdateDictMixin, dict):
"""Provides simple access to `WWW-Authenticate` headers."""
#: list of keys that require quoting in the generated header
_require_quoting = frozenset(['domain', 'nonce', 'opaque', 'realm'])
_require_quoting = frozenset(['domain', 'nonce', 'opaque', 'realm', 'qop'])
def __init__(self, auth_type=None, values=None, on_update=None):
dict.__init__(self, values or ())
@@ -2389,7 +2467,7 @@ class WWWAuthenticate(UpdateDictMixin, dict):
auth_type = d.pop('__auth_type__', None) or 'basic'
return '%s %s' % (auth_type.title(), ', '.join([
'%s=%s' % (key, quote_header_value(value,
allow_token=key not in self._require_quoting))
allow_token=key not in self._require_quoting))
for key, value in iteritems(d)
]))
@@ -2412,6 +2490,7 @@ class WWWAuthenticate(UpdateDictMixin, dict):
For more information have a look at the sourcecode to see how the
regular properties (:attr:`realm` etc.) are implemented.
"""
def _set_value(self, value):
if value is None:
self.pop(name, None)
@@ -2462,6 +2541,7 @@ class WWWAuthenticate(UpdateDictMixin, dict):
val = self.get('stale')
if val is not None:
return val.lower() == 'true'
def _set_stale(self, value):
if value is None:
self.pop('stale', None)
@@ -2479,6 +2559,7 @@ class WWWAuthenticate(UpdateDictMixin, dict):
class FileStorage(object):
"""The :class:`FileStorage` class is a thin wrapper over incoming files.
It is used by the request object to represent uploaded files. All the
attributes of the wrapper stream are proxied by the file storage so
@@ -2506,7 +2587,7 @@ class FileStorage(object):
# This might not be if the name attribute is bytes due to the
# file being opened from the bytes API.
if not PY2 and isinstance(filename, bytes):
filename = filename.decode(sys.getfilesystemencoding(),
filename = filename.decode(get_filesystem_encoding(),
'replace')
self.filename = filename
@@ -2535,15 +2616,15 @@ class FileStorage(object):
@property
def mimetype(self):
"""Like :attr:`content_type` but without parameters (eg, without
charset, type etc.). For example if the content
type is ``text/html; charset=utf-8`` the mimetype would be
"""Like :attr:`content_type`, but without parameters (eg, without
charset, type etc.) and always lowercase. For example if the content
type is ``text/HTML; charset=utf-8`` the mimetype would be
``'text/html'``.
.. versionadded:: 0.7
"""
self._parse_content_type()
return self._parsed_content_type[0]
return self._parsed_content_type[0].lower()
@property
def mimetype_params(self):
@@ -2590,6 +2671,7 @@ class FileStorage(object):
def __nonzero__(self):
return bool(self.filename)
__bool__ = __nonzero__
def __getattr__(self, name):
return getattr(self.stream, name)
@@ -2607,6 +2689,6 @@ class FileStorage(object):
# circular dependencies
from werkzeug.http import dump_options_header, dump_header, generate_etag, \
quote_header_value, parse_set_header, unquote_etag, quote_etag, \
parse_options_header, http_date, is_byte_range_valid
quote_header_value, parse_set_header, unquote_etag, quote_etag, \
parse_options_header, http_date, is_byte_range_valid
from werkzeug import exceptions