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
+147
-42
@@ -34,16 +34,29 @@ See the individual service classes below for complete documentation.
|
||||
|
||||
Example usage for Google OpenID::
|
||||
|
||||
class GoogleLoginHandler(tornado.web.RequestHandler,
|
||||
tornado.auth.GoogleMixin):
|
||||
@tornado.web.asynchronous
|
||||
class GoogleOAuth2LoginHandler(tornado.web.RequestHandler,
|
||||
tornado.auth.GoogleOAuth2Mixin):
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
if self.get_argument("openid.mode", None):
|
||||
user = yield self.get_authenticated_user()
|
||||
# Save the user with e.g. set_secure_cookie()
|
||||
if self.get_argument('code', False):
|
||||
user = yield self.get_authenticated_user(
|
||||
redirect_uri='http://your.site.com/auth/google',
|
||||
code=self.get_argument('code'))
|
||||
# Save the user with e.g. set_secure_cookie
|
||||
else:
|
||||
yield self.authenticate_redirect()
|
||||
yield self.authorize_redirect(
|
||||
redirect_uri='http://your.site.com/auth/google',
|
||||
client_id=self.settings['google_oauth']['key'],
|
||||
scope=['profile', 'email'],
|
||||
response_type='code',
|
||||
extra_params={'approval_prompt': 'auto'})
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
All of the callback interfaces in this module are now guaranteed
|
||||
to run their callback with an argument of ``None`` on error.
|
||||
Previously some functions would do this while others would simply
|
||||
terminate the request on their own. This change also ensures that
|
||||
errors are more consistently reported through the ``Future`` interfaces.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function, with_statement
|
||||
@@ -56,13 +69,14 @@ import hmac
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from tornado.concurrent import Future, chain_future, return_future
|
||||
from tornado.concurrent import TracebackFuture, chain_future, return_future
|
||||
from tornado import gen
|
||||
from tornado import httpclient
|
||||
from tornado import escape
|
||||
from tornado.httputil import url_concat
|
||||
from tornado.log import gen_log
|
||||
from tornado.util import bytes_type, u, unicode_type, ArgReplacer
|
||||
from tornado.stack_context import ExceptionStackContext
|
||||
from tornado.util import u, unicode_type, ArgReplacer
|
||||
|
||||
try:
|
||||
import urlparse # py2
|
||||
@@ -74,6 +88,11 @@ try:
|
||||
except ImportError:
|
||||
import urllib as urllib_parse # py2
|
||||
|
||||
try:
|
||||
long # py2
|
||||
except NameError:
|
||||
long = int # py3
|
||||
|
||||
|
||||
class AuthError(Exception):
|
||||
pass
|
||||
@@ -99,12 +118,19 @@ def _auth_return_future(f):
|
||||
|
||||
@functools.wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
future = Future()
|
||||
future = TracebackFuture()
|
||||
callback, args, kwargs = replacer.replace(future, args, kwargs)
|
||||
if callback is not None:
|
||||
future.add_done_callback(
|
||||
functools.partial(_auth_future_to_callback, callback))
|
||||
f(*args, **kwargs)
|
||||
def handle_exception(typ, value, tb):
|
||||
if future.done():
|
||||
return False
|
||||
else:
|
||||
future.set_exc_info((typ, value, tb))
|
||||
return True
|
||||
with ExceptionStackContext(handle_exception):
|
||||
f(*args, **kwargs)
|
||||
return future
|
||||
return wrapper
|
||||
|
||||
@@ -162,7 +188,7 @@ class OpenIdMixin(object):
|
||||
url = self._OPENID_ENDPOINT
|
||||
if http_client is None:
|
||||
http_client = self.get_auth_http_client()
|
||||
http_client.fetch(url, self.async_callback(
|
||||
http_client.fetch(url, functools.partial(
|
||||
self._on_authentication_verified, callback),
|
||||
method="POST", body=urllib_parse.urlencode(args))
|
||||
|
||||
@@ -307,7 +333,7 @@ class OAuthMixin(object):
|
||||
|
||||
The ``callback_uri`` may be omitted if you have previously
|
||||
registered a callback URI with the third-party service. For
|
||||
some sevices (including Friendfeed), you must use a
|
||||
some services (including Friendfeed), you must use a
|
||||
previously-registered callback URI and cannot specify a
|
||||
callback via this method.
|
||||
|
||||
@@ -334,7 +360,7 @@ class OAuthMixin(object):
|
||||
http_client.fetch(
|
||||
self._oauth_request_token_url(callback_uri=callback_uri,
|
||||
extra_params=extra_params),
|
||||
self.async_callback(
|
||||
functools.partial(
|
||||
self._on_request_token,
|
||||
self._OAUTH_AUTHORIZE_URL,
|
||||
callback_uri,
|
||||
@@ -342,7 +368,7 @@ class OAuthMixin(object):
|
||||
else:
|
||||
http_client.fetch(
|
||||
self._oauth_request_token_url(),
|
||||
self.async_callback(
|
||||
functools.partial(
|
||||
self._on_request_token, self._OAUTH_AUTHORIZE_URL,
|
||||
callback_uri,
|
||||
callback))
|
||||
@@ -379,7 +405,7 @@ class OAuthMixin(object):
|
||||
if http_client is None:
|
||||
http_client = self.get_auth_http_client()
|
||||
http_client.fetch(self._oauth_access_token_url(token),
|
||||
self.async_callback(self._on_access_token, callback))
|
||||
functools.partial(self._on_access_token, callback))
|
||||
|
||||
def _oauth_request_token_url(self, callback_uri=None, extra_params=None):
|
||||
consumer_token = self._oauth_consumer_token()
|
||||
@@ -456,7 +482,7 @@ class OAuthMixin(object):
|
||||
|
||||
access_token = _oauth_parse_response(response.body)
|
||||
self._oauth_get_user_future(access_token).add_done_callback(
|
||||
self.async_callback(self._on_oauth_get_user, access_token, future))
|
||||
functools.partial(self._on_oauth_get_user, access_token, future))
|
||||
|
||||
def _oauth_consumer_token(self):
|
||||
"""Subclasses must override this to return their OAuth consumer keys.
|
||||
@@ -549,7 +575,7 @@ class OAuth2Mixin(object):
|
||||
@return_future
|
||||
def authorize_redirect(self, redirect_uri=None, client_id=None,
|
||||
client_secret=None, extra_params=None,
|
||||
callback=None):
|
||||
callback=None, scope=None, response_type="code"):
|
||||
"""Redirects the user to obtain OAuth authorization for this service.
|
||||
|
||||
Some providers require that you register a redirect URL with
|
||||
@@ -566,10 +592,13 @@ class OAuth2Mixin(object):
|
||||
"""
|
||||
args = {
|
||||
"redirect_uri": redirect_uri,
|
||||
"client_id": client_id
|
||||
"client_id": client_id,
|
||||
"response_type": response_type
|
||||
}
|
||||
if extra_params:
|
||||
args.update(extra_params)
|
||||
if scope:
|
||||
args['scope'] = ' '.join(scope)
|
||||
self.redirect(
|
||||
url_concat(self._OAUTH_AUTHORIZE_URL, args))
|
||||
callback()
|
||||
@@ -604,7 +633,6 @@ class TwitterMixin(OAuthMixin):
|
||||
|
||||
class TwitterLoginHandler(tornado.web.RequestHandler,
|
||||
tornado.auth.TwitterMixin):
|
||||
@tornado.web.asynchronous
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
if self.get_argument("oauth_token", None):
|
||||
@@ -639,7 +667,7 @@ class TwitterMixin(OAuthMixin):
|
||||
"""
|
||||
http = self.get_auth_http_client()
|
||||
http.fetch(self._oauth_request_token_url(callback_uri=callback_uri),
|
||||
self.async_callback(
|
||||
functools.partial(
|
||||
self._on_request_token, self._OAUTH_AUTHENTICATE_URL,
|
||||
None, callback))
|
||||
|
||||
@@ -666,7 +694,6 @@ class TwitterMixin(OAuthMixin):
|
||||
class MainHandler(tornado.web.RequestHandler,
|
||||
tornado.auth.TwitterMixin):
|
||||
@tornado.web.authenticated
|
||||
@tornado.web.asynchronous
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
new_entry = yield self.twitter_request(
|
||||
@@ -698,7 +725,7 @@ class TwitterMixin(OAuthMixin):
|
||||
if args:
|
||||
url += "?" + urllib_parse.urlencode(args)
|
||||
http = self.get_auth_http_client()
|
||||
http_callback = self.async_callback(self._on_twitter_request, callback)
|
||||
http_callback = functools.partial(self._on_twitter_request, callback)
|
||||
if post_args is not None:
|
||||
http.fetch(url, method="POST", body=urllib_parse.urlencode(post_args),
|
||||
callback=http_callback)
|
||||
@@ -745,7 +772,6 @@ class FriendFeedMixin(OAuthMixin):
|
||||
|
||||
class FriendFeedLoginHandler(tornado.web.RequestHandler,
|
||||
tornado.auth.FriendFeedMixin):
|
||||
@tornado.web.asynchronous
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
if self.get_argument("oauth_token", None):
|
||||
@@ -790,7 +816,6 @@ class FriendFeedMixin(OAuthMixin):
|
||||
class MainHandler(tornado.web.RequestHandler,
|
||||
tornado.auth.FriendFeedMixin):
|
||||
@tornado.web.authenticated
|
||||
@tornado.web.asynchronous
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
new_entry = yield self.friendfeed_request(
|
||||
@@ -817,7 +842,7 @@ class FriendFeedMixin(OAuthMixin):
|
||||
args.update(oauth)
|
||||
if args:
|
||||
url += "?" + urllib_parse.urlencode(args)
|
||||
callback = self.async_callback(self._on_friendfeed_request, callback)
|
||||
callback = functools.partial(self._on_friendfeed_request, callback)
|
||||
http = self.get_auth_http_client()
|
||||
if post_args is not None:
|
||||
http.fetch(url, method="POST", body=urllib_parse.urlencode(post_args),
|
||||
@@ -858,6 +883,11 @@ class FriendFeedMixin(OAuthMixin):
|
||||
class GoogleMixin(OpenIdMixin, OAuthMixin):
|
||||
"""Google Open ID / OAuth authentication.
|
||||
|
||||
.. deprecated:: 4.0
|
||||
New applications should use `GoogleOAuth2Mixin`
|
||||
below instead of this class. As of May 19, 2014, Google has stopped
|
||||
supporting registration-free authentication.
|
||||
|
||||
No application registration is necessary to use Google for
|
||||
authentication or to access Google resources on behalf of a user.
|
||||
|
||||
@@ -874,7 +904,6 @@ class GoogleMixin(OpenIdMixin, OAuthMixin):
|
||||
|
||||
class GoogleLoginHandler(tornado.web.RequestHandler,
|
||||
tornado.auth.GoogleMixin):
|
||||
@tornado.web.asynchronous
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
if self.get_argument("openid.mode", None):
|
||||
@@ -929,7 +958,7 @@ class GoogleMixin(OpenIdMixin, OAuthMixin):
|
||||
http = self.get_auth_http_client()
|
||||
token = dict(key=token, secret="")
|
||||
http.fetch(self._oauth_access_token_url(token),
|
||||
self.async_callback(self._on_access_token, callback))
|
||||
functools.partial(self._on_access_token, callback))
|
||||
else:
|
||||
chain_future(OpenIdMixin.get_authenticated_user(self),
|
||||
callback)
|
||||
@@ -945,12 +974,90 @@ class GoogleMixin(OpenIdMixin, OAuthMixin):
|
||||
return OpenIdMixin.get_authenticated_user(self)
|
||||
|
||||
|
||||
class GoogleOAuth2Mixin(OAuth2Mixin):
|
||||
"""Google authentication using OAuth2.
|
||||
|
||||
In order to use, register your application with Google and copy the
|
||||
relevant parameters to your application settings.
|
||||
|
||||
* Go to the Google Dev Console at http://console.developers.google.com
|
||||
* Select a project, or create a new one.
|
||||
* In the sidebar on the left, select APIs & Auth.
|
||||
* In the list of APIs, find the Google+ API service and set it to ON.
|
||||
* In the sidebar on the left, select Credentials.
|
||||
* In the OAuth section of the page, select Create New Client ID.
|
||||
* Set the Redirect URI to point to your auth handler
|
||||
* Copy the "Client secret" and "Client ID" to the application settings as
|
||||
{"google_oauth": {"key": CLIENT_ID, "secret": CLIENT_SECRET}}
|
||||
|
||||
.. versionadded:: 3.2
|
||||
"""
|
||||
_OAUTH_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/auth"
|
||||
_OAUTH_ACCESS_TOKEN_URL = "https://accounts.google.com/o/oauth2/token"
|
||||
_OAUTH_NO_CALLBACKS = False
|
||||
_OAUTH_SETTINGS_KEY = 'google_oauth'
|
||||
|
||||
@_auth_return_future
|
||||
def get_authenticated_user(self, redirect_uri, code, callback):
|
||||
"""Handles the login for the Google user, returning a user object.
|
||||
|
||||
Example usage::
|
||||
|
||||
class GoogleOAuth2LoginHandler(tornado.web.RequestHandler,
|
||||
tornado.auth.GoogleOAuth2Mixin):
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
if self.get_argument('code', False):
|
||||
user = yield self.get_authenticated_user(
|
||||
redirect_uri='http://your.site.com/auth/google',
|
||||
code=self.get_argument('code'))
|
||||
# Save the user with e.g. set_secure_cookie
|
||||
else:
|
||||
yield self.authorize_redirect(
|
||||
redirect_uri='http://your.site.com/auth/google',
|
||||
client_id=self.settings['google_oauth']['key'],
|
||||
scope=['profile', 'email'],
|
||||
response_type='code',
|
||||
extra_params={'approval_prompt': 'auto'})
|
||||
"""
|
||||
http = self.get_auth_http_client()
|
||||
body = urllib_parse.urlencode({
|
||||
"redirect_uri": redirect_uri,
|
||||
"code": code,
|
||||
"client_id": self.settings[self._OAUTH_SETTINGS_KEY]['key'],
|
||||
"client_secret": self.settings[self._OAUTH_SETTINGS_KEY]['secret'],
|
||||
"grant_type": "authorization_code",
|
||||
})
|
||||
|
||||
http.fetch(self._OAUTH_ACCESS_TOKEN_URL,
|
||||
functools.partial(self._on_access_token, callback),
|
||||
method="POST", headers={'Content-Type': 'application/x-www-form-urlencoded'}, body=body)
|
||||
|
||||
def _on_access_token(self, future, response):
|
||||
"""Callback function for the exchange to the access token."""
|
||||
if response.error:
|
||||
future.set_exception(AuthError('Google auth error: %s' % str(response)))
|
||||
return
|
||||
|
||||
args = escape.json_decode(response.body)
|
||||
future.set_result(args)
|
||||
|
||||
def get_auth_http_client(self):
|
||||
"""Returns the `.AsyncHTTPClient` instance to be used for auth requests.
|
||||
|
||||
May be overridden by subclasses to use an HTTP client other than
|
||||
the default.
|
||||
"""
|
||||
return httpclient.AsyncHTTPClient()
|
||||
|
||||
|
||||
class FacebookMixin(object):
|
||||
"""Facebook Connect authentication.
|
||||
|
||||
*Deprecated:* New applications should use `FacebookGraphMixin`
|
||||
below instead of this class. This class does not support the
|
||||
Future-based interface seen on other classes in this module.
|
||||
.. deprecated:: 1.1
|
||||
New applications should use `FacebookGraphMixin`
|
||||
below instead of this class. This class does not support the
|
||||
Future-based interface seen on other classes in this module.
|
||||
|
||||
To authenticate with Facebook, register your application with
|
||||
Facebook at http://www.facebook.com/developers/apps.php. Then
|
||||
@@ -965,7 +1072,7 @@ class FacebookMixin(object):
|
||||
@tornado.web.asynchronous
|
||||
def get(self):
|
||||
if self.get_argument("session", None):
|
||||
self.get_authenticated_user(self.async_callback(self._on_auth))
|
||||
self.get_authenticated_user(self._on_auth)
|
||||
return
|
||||
yield self.authenticate_redirect()
|
||||
|
||||
@@ -1005,7 +1112,7 @@ class FacebookMixin(object):
|
||||
args["cancel_url"] = urlparse.urljoin(
|
||||
self.request.full_url(), cancel_uri)
|
||||
if extended_permissions:
|
||||
if isinstance(extended_permissions, (unicode_type, bytes_type)):
|
||||
if isinstance(extended_permissions, (unicode_type, bytes)):
|
||||
extended_permissions = [extended_permissions]
|
||||
args["req_perms"] = ",".join(extended_permissions)
|
||||
self.redirect("http://www.facebook.com/login.php?" +
|
||||
@@ -1051,7 +1158,7 @@ class FacebookMixin(object):
|
||||
session = escape.json_decode(self.get_argument("session"))
|
||||
self.facebook_request(
|
||||
method="facebook.users.getInfo",
|
||||
callback=self.async_callback(
|
||||
callback=functools.partial(
|
||||
self._on_get_user_info, callback, session),
|
||||
session_key=session["session_key"],
|
||||
uids=session["uid"],
|
||||
@@ -1077,7 +1184,7 @@ class FacebookMixin(object):
|
||||
def get(self):
|
||||
self.facebook_request(
|
||||
method="stream.get",
|
||||
callback=self.async_callback(self._on_stream),
|
||||
callback=self._on_stream,
|
||||
session_key=self.current_user["session_key"])
|
||||
|
||||
def _on_stream(self, stream):
|
||||
@@ -1101,7 +1208,7 @@ class FacebookMixin(object):
|
||||
url = "http://api.facebook.com/restserver.php?" + \
|
||||
urllib_parse.urlencode(args)
|
||||
http = self.get_auth_http_client()
|
||||
http.fetch(url, callback=self.async_callback(
|
||||
http.fetch(url, callback=functools.partial(
|
||||
self._parse_response, callback))
|
||||
|
||||
def _on_get_user_info(self, callback, session, users):
|
||||
@@ -1158,7 +1265,7 @@ class FacebookMixin(object):
|
||||
class FacebookGraphMixin(OAuth2Mixin):
|
||||
"""Facebook authentication using the new Graph API and OAuth2."""
|
||||
_OAUTH_ACCESS_TOKEN_URL = "https://graph.facebook.com/oauth/access_token?"
|
||||
_OAUTH_AUTHORIZE_URL = "https://graph.facebook.com/oauth/authorize?"
|
||||
_OAUTH_AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?"
|
||||
_OAUTH_NO_CALLBACKS = False
|
||||
_FACEBOOK_BASE_URL = "https://graph.facebook.com"
|
||||
|
||||
@@ -1170,7 +1277,6 @@ class FacebookGraphMixin(OAuth2Mixin):
|
||||
Example usage::
|
||||
|
||||
class FacebookGraphLoginHandler(LoginHandler, tornado.auth.FacebookGraphMixin):
|
||||
@tornado.web.asynchronous
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
if self.get_argument("code", False):
|
||||
@@ -1200,7 +1306,7 @@ class FacebookGraphMixin(OAuth2Mixin):
|
||||
fields.update(extra_fields)
|
||||
|
||||
http.fetch(self._oauth_request_token_url(**args),
|
||||
self.async_callback(self._on_access_token, redirect_uri, client_id,
|
||||
functools.partial(self._on_access_token, redirect_uri, client_id,
|
||||
client_secret, callback, fields))
|
||||
|
||||
def _on_access_token(self, redirect_uri, client_id, client_secret,
|
||||
@@ -1217,7 +1323,7 @@ class FacebookGraphMixin(OAuth2Mixin):
|
||||
|
||||
self.facebook_request(
|
||||
path="/me",
|
||||
callback=self.async_callback(
|
||||
callback=functools.partial(
|
||||
self._on_get_user_info, future, session, fields),
|
||||
access_token=session["access_token"],
|
||||
fields=",".join(fields)
|
||||
@@ -1257,7 +1363,6 @@ class FacebookGraphMixin(OAuth2Mixin):
|
||||
class MainHandler(tornado.web.RequestHandler,
|
||||
tornado.auth.FacebookGraphMixin):
|
||||
@tornado.web.authenticated
|
||||
@tornado.web.asynchronous
|
||||
@tornado.gen.coroutine
|
||||
def get(self):
|
||||
new_entry = yield self.facebook_request(
|
||||
@@ -1285,7 +1390,7 @@ class FacebookGraphMixin(OAuth2Mixin):
|
||||
|
||||
if all_args:
|
||||
url += "?" + urllib_parse.urlencode(all_args)
|
||||
callback = self.async_callback(self._on_facebook_request, callback)
|
||||
callback = functools.partial(self._on_facebook_request, callback)
|
||||
http = self.get_auth_http_client()
|
||||
if post_args is not None:
|
||||
http.fetch(url, method="POST", body=urllib_parse.urlencode(post_args),
|
||||
|
||||
Reference in New Issue
Block a user