diff --git a/CHANGELOG.md b/CHANGELOG.md index c16a9aab0..213820206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ ## [Unreleased](https://github.com/omab/python-social-auth/tree/HEAD) -[Full Changelog](https://github.com/omab/python-social-auth/compare/v0.2.21...HEAD) +[Full Changelog](https://github.com/omab/python-social-auth/compare/v0.3.0...HEAD) + +## [v0.3.0](https://github.com/omab/python-social-auth/tree/v0.3.0) (2016-12-03) + +Deprecated in favor of [python-social-auth organization](https://github.com/python-social-auth) ## [v0.2.21](https://github.com/omab/python-social-auth/tree/v0.2.21) (2016-08-15) diff --git a/Makefile b/Makefile index 7b91f4d55..264ec46d8 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,3 @@ -docs: - sphinx-build docs/ docs/_build/ - -site: docs - rsync -avkz site/ tarf:sites/psa/ - build: python setup.py sdist python setup.py bdist_wheel --python-tag py2 @@ -14,9 +8,6 @@ publish: python setup.py bdist_wheel --python-tag py2 upload BUILD_VERSION=3 python setup.py bdist_wheel --python-tag py3 upload -run-tox: - @ tox - docker-tox-build: @ docker build -t omab/psa-legacy . @@ -26,16 +17,7 @@ docker-tox: docker-tox-build -v "`pwd`:/code" \ -w /code omab/psa-legacy tox -docker-shell: docker-tox-build - @ docker run -it --rm \ - --name psa-legacy-test \ - -v "`pwd`:/code" \ - -w /code omab/psa-legacy bash - clean: @ find . -name '*.py[co]' -delete @ find . -name '__pycache__' -delete @ rm -rf *.egg-info dist build - - -.PHONY: site docs publish diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 525f59e5e..000000000 --- a/docs/Makefile +++ /dev/null @@ -1,130 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/DjangoSocialAuth.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DjangoSocialAuth.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/DjangoSocialAuth" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/DjangoSocialAuth" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/backends/amazon.rst b/docs/backends/amazon.rst deleted file mode 100644 index 72ccd0a95..000000000 --- a/docs/backends/amazon.rst +++ /dev/null @@ -1,29 +0,0 @@ -Amazon -====== - -Amazon implemented OAuth2 protocol for their authentication mechanism. To -enable ``python-social-auth`` support follow this steps: - -1. Go to `Amazon App Console`_ and create an application. - -2. Fill App Id and Secret in your project settings:: - - SOCIAL_AUTH_AMAZON_KEY = '...' - SOCIAL_AUTH_AMAZON_SECRET = '...' - -3. Enable the backend:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.amazon.AmazonOAuth2', - ... - ) - -Further documentation at `Website Developer Guide`_ and `Getting Started for Web`_. - -**Note:** This backend supports TLSv1 protocol since SSL will be deprecated - from May 25, 2015 - -.. _Amazon App Console: http://login.amazon.com/manageApps -.. _Website Developer Guide: https://images-na.ssl-images-amazon.com/images/G/01/lwa/dev/docs/website-developer-guide._TTH_.pdf -.. _Getting Started for Web: http://login.amazon.com/website diff --git a/docs/backends/angel.rst b/docs/backends/angel.rst deleted file mode 100644 index 76f243a78..000000000 --- a/docs/backends/angel.rst +++ /dev/null @@ -1,21 +0,0 @@ -Angel List -========== - -Angel uses OAuth v2 for Authentication. - -- Register a new application at the `Angel List API`_, and - -- fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_ANGEL_KEY = '' - SOCIAL_AUTH_ANGEL_SECRET = '' - -- extra scopes can be defined by using:: - - SOCIAL_AUTH_ANGEL_AUTH_EXTRA_ARGUMENTS = {'scope': 'email messages'} - -**Note:** -Angel List does not currently support returning ``state`` parameter used to -validate the auth process. - -.. _Angel List API: https://angel.co/api/oauth/faq diff --git a/docs/backends/aol.rst b/docs/backends/aol.rst deleted file mode 100644 index 86893c54e..000000000 --- a/docs/backends/aol.rst +++ /dev/null @@ -1,11 +0,0 @@ -AOL -=== - -AOL OpenId doesn't require major settings beside being defined on -``AUTHENTICATION_BACKENDS```:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.aol.AOLOpenId', - ... - ) diff --git a/docs/backends/appsfuel.rst b/docs/backends/appsfuel.rst deleted file mode 100644 index 79957fc32..000000000 --- a/docs/backends/appsfuel.rst +++ /dev/null @@ -1,46 +0,0 @@ -Appsfuel -======== - -Appsfuel uses OAuth v2 for Authentication check the `official docs`_ too. - -- Sign up at the `Appsfuel Developer Program`_ - -- Create and verify a new app - -- On the dashboard click on **Show API keys** - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_APPSFUEL_KEY = '' - SOCIAL_AUTH_APPSFUEL_SECRET = '' - -Appsfuel gives you the chance to integrate with **Live** or **Sandbox** env. - - -Appsfuel Live -------------- - -- Add 'social.backends.contrib.appsfuel.AppsfuelBackend' into your - ``AUTHENTICATION_BACKENDS``. - -- Then you can start using ``{% url social:begin 'appsfuel' %}`` in your - templates - - -Appsfuel Sandbox ----------------- - -- Add ``'social.backends.appsfuel.AppsfuelOAuth2Sandbox'`` into your - ``AUTHENTICATION_BACKENDS``. - -- Then you can start using ``{% url social:begin 'appsfuel-sandbox' %}`` in - your templates - -- Define the settings:: - - SOCIAL_AUTH_APPSFUEL_SANDBOX_KEY = '' - SOCIAL_AUTH_APPSFUEL_SANDBOX_SECRET = '' - - -.. _official docs: http://docs.appsfuel.com/api_reference#api_integration -.. _Appsfuel Developer Program: https://developer.appsfuel.com diff --git a/docs/backends/arcgis.rst b/docs/backends/arcgis.rst deleted file mode 100644 index b32578138..000000000 --- a/docs/backends/arcgis.rst +++ /dev/null @@ -1,25 +0,0 @@ -ArcGIS -====== - -ArcGIS uses OAuth2 for authentication. - -- Register a new application at `ArcGIS Developer Center`_. - - -OAuth2 ------- - -1. Add the OAuth2 backend to your settings page:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.arcgis.ArcGISOAuth2', - ... - ) - -2. Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_ARCGIS_KEY = '' - SOCIAL_AUTH_ARCGIS_SECRET = '' - -.. _ArcGIS Developer Center: https://developers.arcgis.com/ diff --git a/docs/backends/azuread.rst b/docs/backends/azuread.rst deleted file mode 100644 index 6c84c5cc3..000000000 --- a/docs/backends/azuread.rst +++ /dev/null @@ -1,20 +0,0 @@ -Microsoft Azure Active Directory -================================ - -To enable OAuth2 support: - -- Fill in ``Client ID`` and ``Client Secret`` settings. These values can be - obtained easily as described in `Azure AD Application Registration`_ doc:: - - SOCIAL_AUTH_AZUREAD_OAUTH2_KEY = '' - SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_AZUREAD_OAUTH2_RESOURCE = '' - - This is the resource you would like to access after authentication succeeds. - Some of the possible values are: ``https://graph.windows.net`` or - ``https://-my.sharepoint.com``. - -.. _Azure AD Application Registration: https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx diff --git a/docs/backends/battlenet.rst b/docs/backends/battlenet.rst deleted file mode 100644 index db6a842ee..000000000 --- a/docs/backends/battlenet.rst +++ /dev/null @@ -1,34 +0,0 @@ -Battle.net -========== - -Blizzard implemented OAuth2 protocol for their authentication mechanism. To -enable ``python-social-auth`` support follow this steps: - -1. Go to `Battlenet Developer Portal`_ and create an application. - -2. Fill App Id and Secret in your project settings:: - - SOCIAL_AUTH_BATTLENET_OAUTH2_KEY = '...' - SOCIAL_AUTH_BATTLENET_OAUTH2_SECRET = '...' - -3. Enable the backend:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.battlenet.BattleNetOAuth2', - ... - ) - -Note: If you want to allow the user to choose a username from his own -characters, some further steps are required, see the use cases part of the -documentation. To get the account id and battletag use the user_data function, as -`account id is no longer passed inherently`_. - -Another note: If you get a 500 response "Internal Server Error" the API now requires `https on callback endpoints`_. - -Further documentation at `Developer Guide`_. - -.. _Battlenet Developer Portal: https://dev.battle.net/ -.. _Developer Guide: https://dev.battle.net/docs/read/oauth -.. _https on callback endpoints: http://us.battle.net/en/forum/topic/17085510584 -.. _account id is no longer passed inherently: http://us.battle.net/en/forum/topic/18300183303 diff --git a/docs/backends/beats.rst b/docs/backends/beats.rst deleted file mode 100644 index 27fece0dc..000000000 --- a/docs/backends/beats.rst +++ /dev/null @@ -1,25 +0,0 @@ -Beats -===== - -Beats supports OAuth 2. - -- Register a new application at `Beats Music API`_, and follow the - instructions below. - -OAuth2 ------- - -Add the Beats OAuth2 backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.beats.BeatsOAuth2', - ... - ) - -- Fill ``App Key`` and ``App Secret`` values in the settings:: - - SOCIAL_AUTH_BEATS_OAUTH2_KEY = '' - SOCIAL_AUTH_BEATS_OAUTH2_SECRET = '' - -.. _Beats Music API: https://developer.beatsmusic.com/docs diff --git a/docs/backends/behance.rst b/docs/backends/behance.rst deleted file mode 100644 index 0ce8fe832..000000000 --- a/docs/backends/behance.rst +++ /dev/null @@ -1,31 +0,0 @@ -Behance -======= - -DEPRECATED NOTICE ------------------ - -**NOTE:** IT SEEMS THAT BEHANCE HAS DROPPED THEIR OAUTH2 SUPPORT WITHOUT MUCH -NOTICE BESIDE A `BLOG POST`_ ON SEPTEMBER 2014 MENTIONING THAT IT WILL BE -INTRODUCED "SOON". THIS BACKEND IS IN DEPRECATED STATE FOR NOW. - -Behance uses OAuth2 for its auth mechanism. - -- Register a new application at `Behance App Registration`_, set your - application name, website and redirect URI. - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_BEHANCE_KEY = '' - SOCIAL_AUTH_BEHANCE_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_BEHANCE_SCOPE = [...] - -Check available permissions at `Possible Scopes`_. Also check the rest of their -doc at `Behance Developer Documentation`_. - -.. _Behance App Registration: http://www.behance.net/dev/register -.. _Possible Scopes: http://www.behance.net/dev/authentication#scopes -.. _Behance Developer Documentation: http://www.behance.net/dev -.. _BLOG POST: http://blog.behance.net/dev/introducing-the-behance-api diff --git a/docs/backends/belgium_eid.rst b/docs/backends/belgium_eid.rst deleted file mode 100644 index a62aca5bb..000000000 --- a/docs/backends/belgium_eid.rst +++ /dev/null @@ -1,11 +0,0 @@ -Belgium EID -=========== - -Belgium EID OpenId doesn't require major settings beside being defined on -``AUTHENTICATION_BACKENDS```:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.belgiumeid.BelgiumEIDOpenId', - ... - ) diff --git a/docs/backends/bitbucket.rst b/docs/backends/bitbucket.rst deleted file mode 100644 index 1cb69dd8e..000000000 --- a/docs/backends/bitbucket.rst +++ /dev/null @@ -1,56 +0,0 @@ -Bitbucket -========= - -Bitbucket supports both OAuth2 and OAuth1 logins. - -1. Register a new OAuth Consumer by following the instructions in the - Bitbucket documentation: `OAuth on Bitbucket`_ - - Note: For OAuth2, your consumer MUST have the "account" scope otherwise - the user profile information (username, name, etc.) won't be accessible. - -2. Configure the appropriate settings for OAuth2 or OAuth1 (see below). - - -OAuth2 ------- - -- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings:: - - SOCIAL_AUTH_BITBUCKET_OAUTH2_KEY = '' - SOCIAL_AUTH_BITBUCKET_OAUTH2_SECRET = '' - -- If you would like to restrict access to only users with verified e-mail - addresses, set ``SOCIAL_AUTH_BITBUCKET_OAUTH2_VERIFIED_EMAILS_ONLY = True`` - By default the setting is set to ``False`` since it's possible for a - project to gather this information by other methods. - - -OAuth1 ------- - -- OAuth1 works similarly to OAuth2, but you must fill in the following settings - instead:: - - SOCIAL_AUTH_BITBUCKET_KEY = '' - SOCIAL_AUTH_BITBUCKET_SECRET = '' - -- If you would like to restrict access to only users with verified e-mail - addresses, set ``SOCIAL_AUTH_BITBUCKET_VERIFIED_EMAILS_ONLY = True``. - By default the setting is set to ``False`` since it's possible for a - project to gather this information by other methods. - - -User ID -------- - -Bitbucket recommends the use of UUID_ as the user identifier instead -of ``username`` since they can change and impose a security risk. For -that reason ``UUID`` is used by default, but for backward -compatibility reasons, it's possible to get the old behavior again by -defining this setting:: - - SOCIAL_AUTH_BITBUCKET_USERNAME_AS_ID = True - -.. _UUID: https://confluence.atlassian.com/display/BITBUCKET/Use+the+Bitbucket+REST+APIs -.. _OAuth on Bitbucket: https://confluence.atlassian.com/display/BITBUCKET/OAuth+on+Bitbucket diff --git a/docs/backends/box.rst b/docs/backends/box.rst deleted file mode 100644 index d22d2d409..000000000 --- a/docs/backends/box.rst +++ /dev/null @@ -1,23 +0,0 @@ -Box.net -======= - -Box works similar to Facebook (OAuth2). - -- Register an application at `Manage Box Applications`_ - -- Fill the **Consumer Key** and **Consumer Secret** values in your settings:: - - SOCIAL_AUTH_BOX_KEY = '' - SOCIAL_AUTH_BOX_SECRET = '' - -- By default the token is not permanent, it will last an hour. To refresh the - access token just do:: - - from social.apps.django_app.utils import load_strategy - - strategy = load_strategy(backend='box') - user = User.objects.get(pk=foo) - social = user.social_auth.filter(provider='box')[0] - social.refresh_token(strategy=strategy) - -.. _Manage Box Applications: https://app.box.com/developers/services diff --git a/docs/backends/changetip.rst b/docs/backends/changetip.rst deleted file mode 100644 index 44f97c28b..000000000 --- a/docs/backends/changetip.rst +++ /dev/null @@ -1,22 +0,0 @@ -ChangeTip -========= - -ChangeTip - -- Register a new application at ChangeTip_, set the callback URL to - ``http://example.com/complete/changetip/`` replacing ``example.com`` with your - domain. - -- Fill ``Client ID`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_CHANGETIP_KEY = '' - SOCIAL_AUTH_CHANGETIP_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_CHANGETIP_SCOPE = [...] - - See auth scopes at `ChangeTip OAuth docs`_. - -.. _ChangeTip: https://www.changetip.com/api -.. _ChangeTip OAuth docs: https://www.changetip.com/api/auth/#!#scopes diff --git a/docs/backends/clef.rst b/docs/backends/clef.rst deleted file mode 100644 index cfdc6393a..000000000 --- a/docs/backends/clef.rst +++ /dev/null @@ -1,15 +0,0 @@ -Clef -====== - -Clef works similar to Facebook (OAuth). - -- Register a new application at `Clef Developers`_, set the callback URL to - ``http://example.com/complete/clef/`` replacing ``example.com`` with your - domain. - -- Fill ``App Id`` and ``App Secret`` values in the settings:: - - SOCIAL_AUTH_CLEF_KEY = '' - SOCIAL_AUTH_CLEF_SECRET = '' - -.. _Clef Developers: https://getclef.com/developer \ No newline at end of file diff --git a/docs/backends/coinbase.rst b/docs/backends/coinbase.rst deleted file mode 100644 index b90cdf336..000000000 --- a/docs/backends/coinbase.rst +++ /dev/null @@ -1,22 +0,0 @@ -Coinbase -======== - -Coinbase uses OAuth2. - -- Register an application at Coinbase_ - -- Fill in the **Client Id** and **Client Secret** values in your settings:: - - SOCIAL_AUTH_COINBASE_KEY = '' - SOCIAL_AUTH_COINBASE_SECRET = '' - -- Set the ``redirect_url`` on coinbase. Make sure to include the trailing - slash, eg. ``http://hostname/complete/coinbase/`` - -- Specify scopes with:: - - SOCIAL_AUTH_COINBASE_SCOPE = [...] - - By default the scope is set to ``balance``. - -.. _Coinbase: https://coinbase.com/oauth/applications diff --git a/docs/backends/coursera.rst b/docs/backends/coursera.rst deleted file mode 100644 index 5e23a7a3c..000000000 --- a/docs/backends/coursera.rst +++ /dev/null @@ -1,26 +0,0 @@ -Coursera -============ - -Coursera uses a variant of OAuth2 authentication. The details of the API -can be found at `OAuth2-based APIs - Coursera Technology`_. - -Take the following steps in order to use the backend: - -1. Create an account at `Coursera`_. - -2. Open `Developer Console`_, create an organisation and application. - -3. Set **Client ID** as a ``SOCIAL_AUTH_COURSERA_KEY`` and -**Secret Key** as a ``SOCIAL_AUTH_COURSERA_SECRET`` in your local settings. - -4. Add the backend to ``AUTHENTICATION_BACKENDS`` setting:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.coursera.CourseraOAuth2', - ... - ) - -.. _OAuth2-based APIs - Coursera Technology: https://tech.coursera.org/app-platform/oauth2/ -.. _Coursera: https://accounts.coursera.org/console -.. _Developer Console: https://accounts.coursera.org/console diff --git a/docs/backends/dailymotion.rst b/docs/backends/dailymotion.rst deleted file mode 100644 index c8198c456..000000000 --- a/docs/backends/dailymotion.rst +++ /dev/null @@ -1,23 +0,0 @@ -DailyMotion -=========== - -DailyMotion uses OAuth2. In order to enable the backend follow: - -- Register an application at `DailyMotion Developer Portal`_ - -- Fill in the **Client Id** and **Client Secret** values in your settings:: - - SOCIAL_AUTH_DAILYMOTION_KEY = '' - SOCIAL_AUTH_DAILYMOTION_SECRET = '' - -- Set the ``Callback URL`` to ``http:///complete/dailymotion/`` - -- Specify scopes with:: - - SOCIAL_AUTH_DAILYMOTION_SCOPE = [...] - - Available scopes are listed in the `Requesting Extended Permissions`_ - section. - -.. _DailyMotion Developer Portal: http://www.dailymotion.com/profile/developer/new -.. _Requesting Extended Permissions: http://www.dailymotion.com/doc/api/authentication.html#requesting-extended-permissions diff --git a/docs/backends/digitalocean.rst b/docs/backends/digitalocean.rst deleted file mode 100644 index 5f72cfe02..000000000 --- a/docs/backends/digitalocean.rst +++ /dev/null @@ -1,24 +0,0 @@ -DigitalOcean -============ - -DigitalOcean uses OAuth2 for its auth process. See the full `DigitalOcean -developer's documentation`_ for more information. - -- Register a new application in the `Apps & API page`_ in the DigitalOcean - control panel, setting the callback URL to ``http://example.com/complete/digitalocean/`` - replacing ``example.com`` with your domain. - -- Fill the ``Client ID`` and ``Client Secret`` values from GitHub in the settings:: - - SOCIAL_AUTH_DIGITALOCEAN_KEY = '' - SOCIAL_AUTH_DIGITALOCEAN_SECRET = '' - -- By default, only ``read`` permissions are granted. In order to create, - destroy, and take other actions on the user's resources, you must request - ``read write`` permissions like so:: - - SOCIAL_AUTH_DIGITALOCEAN_AUTH_EXTRA_ARGUMENTS = {'scope': 'read write'} - - -.. _DigitalOcean developer's documentation: https://developers.digitalocean.com/documentation/ -.. _Apps & API page: https://cloud.digitalocean.com/settings/applications diff --git a/docs/backends/disqus.rst b/docs/backends/disqus.rst deleted file mode 100644 index e7fec760c..000000000 --- a/docs/backends/disqus.rst +++ /dev/null @@ -1,20 +0,0 @@ -Disqus -====== - -Disqus uses OAuth v2 for Authentication. - -- Register a new application at the `Disqus API`_, and - -- fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_DISQUS_KEY = '' - SOCIAL_AUTH_DISQUS_SECRET = '' - -- extra scopes can be defined by using:: - - SOCIAL_AUTH_DISQUS_AUTH_EXTRA_ARGUMENTS = {'scope': 'likes comments relationships'} - - Check `Disqus Auth API`_ for details. - -.. _Disqus Auth API: http://disqus.com/api/docs/auth/ -.. _Disqus API: http://disqus.com/api/applications/ diff --git a/docs/backends/docker.rst b/docs/backends/docker.rst deleted file mode 100644 index 7e104d777..000000000 --- a/docs/backends/docker.rst +++ /dev/null @@ -1,20 +0,0 @@ -Docker -====== - -Docker.io OAuth2 ----------------- - -Docker.io now supports OAuth2 for their API. In order to set it up: - -- Register a new application by following the instructions in their website: - `Register Your Application`_ - -- Fill **Consumer Key** and **Consumer Secret** values in settings:: - - SOCIAL_AUTH_DOCKER_KEY = '' - SOCIAL_AUTH_DOCKER_SECRET = '' - -- Add ``'social.backends.docker.DockerOAuth2'`` into your - ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``. - -.. _Register Your Application: http://docs.docker.io/en/latest/reference/api/docker_io_oauth_api/#register-your-application diff --git a/docs/backends/douban.rst b/docs/backends/douban.rst deleted file mode 100644 index d75d9a2fc..000000000 --- a/docs/backends/douban.rst +++ /dev/null @@ -1,47 +0,0 @@ -Douban -====== - -Douban supports OAuth 1 and 2. - -Douban OAuth1 -------------- - -Douban OAuth 1 works similar to Twitter OAuth. - -Douban offers per application keys named ``Consumer Key`` and ``Consumer -Secret``. To enable Douban OAuth these two keys are needed. Further -documentation at `Douban Services & API`_: - -- Register a new application at `Douban API Key`_, make sure to mark the **web - application** checkbox. - -- Fill **Consumer Key** and **Consumer Secret** values in settings:: - - SOCIAL_AUTH_DOUBAN_KEY = '' - SOCIAL_AUTH_DOUBAN_SECRET = '' - -- Add ``'social.backends.douban.DoubanOAuth'`` into your - ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``. - - -Douban OAuth2 -------------- - -Recently Douban launched their OAuth2 support and the new developer site, you -can find documentation at `Douban Developers`_. To setup OAuth2 follow: - -- Register a new application at `Create A Douban App`_, make sure to mark the - **web application** checkbox. - -- Fill **Consumer Key** and **Consumer Secret** values in settings:: - - SOCIAL_AUTH_DOUBAN_OAUTH2_KEY = '' - SOCIAL_AUTH_DOUBAN_OAUTH2_SECRET = '' - -- Add ``'social.backends.douban.DoubanOAuth2'`` into your - ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``. - -.. _Douban Services & API: http://www.douban.com/service/ -.. _Douban API Key: http://www.douban.com/service/apikey/apply -.. _Douban Developers: http://developers.douban.com/ -.. _Create A Douban App : http://developers.douban.com/apikey/apply diff --git a/docs/backends/dribbble.rst b/docs/backends/dribbble.rst deleted file mode 100644 index 64333e9f3..000000000 --- a/docs/backends/dribbble.rst +++ /dev/null @@ -1,23 +0,0 @@ -Dribbble -======== - -Dribbble - -- Register a new application at Dribbble_, set the callback URL - to ``http://example.com/complete/dribbble/`` replacing - ``example.com`` with your domain. - -- Fill ``Client ID`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_DRIBBBLE_KEY = '' - SOCIAL_AUTH_DRIBBBLE_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_DRIBBBLE_SCOPE = [...] - - See auth scopes at `Dribbble Developer docs`_. - - -.. _Dribbble: https://dribbble.com/account/applications/new -.. _Dribbble Developer docs: http://developer.dribbble.com/v1/oauth/ diff --git a/docs/backends/drip.rst b/docs/backends/drip.rst deleted file mode 100644 index 88f09a2ed..000000000 --- a/docs/backends/drip.rst +++ /dev/null @@ -1,14 +0,0 @@ -Drip -==== - -Drip uses OAuth v2 for Authentication. - -- Register a new application with `Drip`_, and - -- fill ``Client ID`` and ``Client Secret`` from getdrip.com values in - the settings:: - - SOCIAL_AUTH_DRIP_KEY = '' - SOCIAL_AUTH_DRIP_SECRET = '' - -.. _Drip: https://www.getdrip.com/user/applications diff --git a/docs/backends/dropbox.rst b/docs/backends/dropbox.rst deleted file mode 100644 index a8aa62b78..000000000 --- a/docs/backends/dropbox.rst +++ /dev/null @@ -1,42 +0,0 @@ -Dropbox -======= - -Dropbox supports both OAuth 1 and 2. - -- Register a new application at `Dropbox Developers`_, and follow the - instructions below for the version of OAuth for which you are adding - support. - -OAuth1 ------- - -Add the Dropbox OAuth backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.dropbox.DropboxOAuth', - ... - ) - -- Fill ``App Key`` and ``App Secret`` values in the settings:: - - SOCIAL_AUTH_DROPBOX_KEY = '' - SOCIAL_AUTH_DROPBOX_SECRET = '' - -OAuth2 ------- - -Add the Dropbox OAuth2 backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.dropbox.DropboxOAuth2', - ... - ) - -- Fill ``App Key`` and ``App Secret`` values in the settings:: - - SOCIAL_AUTH_DROPBOX_OAUTH2_KEY = '' - SOCIAL_AUTH_DROPBOX_OAUTH2_SECRET = '' - -.. _Dropbox Developers: https://www.dropbox.com/developers/apps diff --git a/docs/backends/edmodo.rst b/docs/backends/edmodo.rst deleted file mode 100644 index 095c45627..000000000 --- a/docs/backends/edmodo.rst +++ /dev/null @@ -1,22 +0,0 @@ -Edmodo -====== - -Edmodo supports OAuth 2. - -- Register a new application at `Edmodo Connect API`_, and follow the - instructions below. -- Add the Edmodo OAuth2 backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.edmodo.EdmodoOAuth2', - ... - ) - -- Fill ``App Key``, ``App Secret`` and ``App Scope`` values in the settings:: - - SOCIAL_AUTH_EDMODO_OAUTH2_KEY = '' - SOCIAL_AUTH_EDMODO_OAUTH2_SECRET = '' - SOCIAL_AUTH_EDMODO_SCOPE = ['basic'] - -.. _Edmodo Connect API: https://developers.edmodo.com/edmodo-connect/edmodo-connect-overview-getting-started/ diff --git a/docs/backends/email.rst b/docs/backends/email.rst deleted file mode 100644 index 9e11b3d6c..000000000 --- a/docs/backends/email.rst +++ /dev/null @@ -1,58 +0,0 @@ -Email Auth -========== - -python-social-auth_ comes with an EmailAuth_ backend which comes handy when -your site uses requires the plain old email and password authentication -mechanism. - -Actually that's a lie since the backend doesn't handle password at all, that's -up to the developer to validate the password in and the proper place to do it -is the pipeline, right after the user instance was retrieved or created. - -The reason to leave password handling to the developer is because too many -things are really tied to the project, like the field where the password is -stored, salt handling, password hashing algorithm and validation. So just add -the pipeline functions that will do that following the needs of your project. - - -Backend settings ----------------- - -``SOCIAL_AUTH_EMAIL_FORM_URL = '/login-form/'`` - Used to redirect the user to the login/signup form, it must have at least - one field named ``email``. Form submit should go to ``/complete/email``, - or if it goes to your view, then your view should complete the process - calling ``social.actions.do_complete``. - -``SOCIAL_AUTH_EMAIL_FORM_HTML = 'login_form.html'`` - The template will be used to render the login/signup form to the user, it - must have at least one field named ``email``. Form submit should go to - ``/complete/email``, or if it goes to your view, then your view should - complete the process calling ``social.actions.do_complete``. - - -Email validation ----------------- - -Check *Email validation* pipeline in the `pipeline docs`_. - -Password handling ------------------ - -Here's an example of password handling to add to the pipeline:: - - def user_password(strategy, backend, user, is_new=False, *args, **kwargs): - if backend.name != 'email': - return - - password = strategy.request_data()['password'] - if is_new: - user.set_password(password) - user.save() - elif not user.validate_password(password): - # return {'user': None, 'social': None} - raise AuthForbidden(backend) - -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _EmailAuth: https://github.com/omab/python-social-auth/blob/master/social/backends/email.py#L5 -.. _pipeline docs: ../pipeline.html#email-validation diff --git a/docs/backends/eveonline.rst b/docs/backends/eveonline.rst deleted file mode 100644 index 7c0503746..000000000 --- a/docs/backends/eveonline.rst +++ /dev/null @@ -1,23 +0,0 @@ -EVE Online Single Sign-On (SSO) -=============================== - -The EVE Single Sign-On (SSO) works similar to GitHub (OAuth2). - -- Register a new application at `EVE Developers`_, set the callback URL to - ``http://example.com/complete/eveonline/`` replacing ``example.com`` with your - domain. - -- Fill the ``Client ID`` and ``Secret Key`` values from EVE Developers in the settings:: - - SOCIAL_AUTH_EVEONLINE_KEY = '' - SOCIAL_AUTH_EVEONLINE_SECRET = '' - -- If you want to use EVE Character names as user names, use this setting:: - - SOCIAL_AUTH_CLEAN_USERNAMES = False - -- If you want to access EVE Online's CREST API, use:: - - SOCIAL_AUTH_EVEONLINE_SCOPE = ['publicData'] - -.. _EVE Developers: https://developers.eveonline.com/ diff --git a/docs/backends/evernote.rst b/docs/backends/evernote.rst deleted file mode 100644 index a432326b6..000000000 --- a/docs/backends/evernote.rst +++ /dev/null @@ -1,24 +0,0 @@ -Evernote OAuth -============== - -Evernote OAuth 1.0 for its authentication workflow. - -- Register a new application at `Evernote API Key form`_. - -- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings:: - - SOCIAL_AUTH_EVERNOTE_KEY = '' - SOCIAL_AUTH_EVERNOTE_SECRET = '' - - -Sandbox -------- - -Evernote supports a sandbox mode for testing, there's a custom backend for it -which name is ``evernote-sandbox`` instead of ``evernote``. Same settings apply -but use these instead:: - - SOCIAL_AUTH_EVERNOTE_SANDBOX_KEY = '' - SOCIAL_AUTH_EVERNOTE_SANDBOX_SECRET = '' - -.. _Evernote API Key form: http://dev.evernote.com/support/api_key.php diff --git a/docs/backends/facebook.rst b/docs/backends/facebook.rst deleted file mode 100644 index 894070b3c..000000000 --- a/docs/backends/facebook.rst +++ /dev/null @@ -1,91 +0,0 @@ -Facebook -======== - -OAuth2 ------- - -Facebook uses OAuth2 for its auth process. Further documentation at `Facebook -development resources`_: - -- Register a new application at `Facebook App Creation`_, don't use - ``localhost`` as ``App Domains`` and ``Site URL`` since Facebook won't allow - them. Use a placeholder like ``myapp.com`` and define that domain in your - ``/etc/hosts`` or similar file. - -- fill ``App Id`` and ``App Secret`` values in values:: - - SOCIAL_AUTH_FACEBOOK_KEY = '' - SOCIAL_AUTH_FACEBOOK_SECRET = '' - -- Define ``SOCIAL_AUTH_FACEBOOK_SCOPE`` to get extra permissions - from facebook. Email is not sent by default, to get it, you must request the - ``email`` permission:: - - SOCIAL_AUTH_FACEBOOK_SCOPE = ['email'] - -- Define ``SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS`` to pass extra parameters - to https://graph.facebook.com/me when gathering the user profile data (you need - to explicitly ask for fields like ``email`` using ``fields`` key):: - - SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = { - 'locale': 'ru_RU', - 'fields': 'id, name, email, age_range' - } - -If you define a redirect URL in Facebook setup page, be sure to not define -http://127.0.0.1:8000 or http://localhost:8000 because it won't work when -testing. Instead I define http://myapp.com and setup a mapping on ``/etc/hosts``. - - -Canvas Application ------------------- - -If you need to perform authentication from Facebook Canvas application: - -- Create your canvas application at http://developers.facebook.com/apps - -- In Facebook application settings specify your canvas URL ``mysite.com/fb`` - (current default) - -- Setup your Python Social Auth settings and your application namespace:: - - SOCIAL_AUTH_FACEBOOK_APP_KEY = '' - SOCIAL_AUTH_FACEBOOK_APP_SECRET = '' - SOCIAL_AUTH_FACEBOOK_APP_NAMESPACE = '' - -- Launch your testing server on port 80 (use sudo or nginx or apache) for - browser to be able to load it when Facebook calls canvas URL - -- Open your Facebook page via http://apps.facebook.com/app_namespace or - better via http://www.facebook.com/pages/user-name/user-id?sk=app_app-id - -- After that you will see this page in a right way and will able to connect - to application and login automatically after connection - -- Provide a template to be rendered, it must have this JavaScript snippet (or - similar) in it:: - - - - -More info on the topic at `Facebook Canvas Application Authentication`_. - - -Graph 2.0 ---------- - -If looking for `Graph 2.0`_ support, use the backends ``Facebook2OAuth2`` -(OAuth2) and/or ``Facebook2AppOAuth2`` (Canvas application). - -.. _Facebook development resources: http://developers.facebook.com/docs/authentication/ -.. _Facebook App Creation: http://developers.facebook.com/setup/ -.. _Facebook Canvas Application Authentication: http://www.ikrvss.ru/2011/09/22/django-social-auth-and-facebook-canvas-applications/ -.. _Graph 2.0: https://developers.facebook.com/blog/post/2014/04/30/the-new-facebook-login/ diff --git a/docs/backends/fedora.rst b/docs/backends/fedora.rst deleted file mode 100644 index eb6486111..000000000 --- a/docs/backends/fedora.rst +++ /dev/null @@ -1,11 +0,0 @@ -Fedora -====== - -Fedora OpenId doesn't require major settings beside being defined on -``AUTHENTICATION_BACKENDS```:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.fedora.FedoraOpenId', - ... - ) diff --git a/docs/backends/fitbit.rst b/docs/backends/fitbit.rst deleted file mode 100644 index 057a84c85..000000000 --- a/docs/backends/fitbit.rst +++ /dev/null @@ -1,42 +0,0 @@ -Fitbit -====== - -Fitbit supports both OAuth 2.0 and OAuth 1.0a logins. OAuth 2 is -preferred for new integrations, as OAuth 1.0a does not support getting -heartrate or location and will be deprecated in the future. - -1. Register a new OAuth Consumer `here`_ - -2. Configure the appropriate settings for OAuth 2.0 or OAuth 1.0a (see - below). - -OAuth 2.0 or OAuth 1.0a ------------------------ - -- Fill ``Consumer Key`` and ``Consumer Secret`` values in the - settings:: - - SOCIAL_AUTH_FITBIT_KEY = '' - SOCIAL_AUTH_FITBIT_SECRET = '' - -OAuth 2.0 specific settings ---------------------------- - -By default, only the ``profile`` scope is requested. To request more -scopes, set SOCIAL_AUTH_FITBIT_SCOPE:: - - SOCIAL_AUTH_FITBIT_SCOPE = [ - 'activity', - 'heartrate', - 'location', - 'nutrition', - 'profile', - 'settings', - 'sleep', - 'social', - 'weight' - ] - -The above will request all permissions from the user. - -.. _here: https://dev.fitbit.com/apps/new diff --git a/docs/backends/flickr.rst b/docs/backends/flickr.rst deleted file mode 100644 index 43f8859da..000000000 --- a/docs/backends/flickr.rst +++ /dev/null @@ -1,19 +0,0 @@ -Flickr -====== - -Flickr uses OAuth v1.0 for authentication. - -- Register a new application at the `Flickr App Garden`_, and - -- fill ``Key`` and ``Secret`` values in the settings:: - - SOCIAL_AUTH_FLICKR_KEY = '' - SOCIAL_AUTH_FLICKR_SECRET = '' - -- Flickr might show a messages saying "Oops! Flickr doesn't recognise the - permission set.", if encountered with this error, just define this setting:: - - SOCIAL_AUTH_FLICKR_AUTH_EXTRA_ARGUMENTS = {'perms': 'read'} - - -.. _Flickr App Garden: http://www.flickr.com/services/apps/create/ diff --git a/docs/backends/foursquare.rst b/docs/backends/foursquare.rst deleted file mode 100644 index 9dacca2f4..000000000 --- a/docs/backends/foursquare.rst +++ /dev/null @@ -1,14 +0,0 @@ -Foursquare -========== - -Foursquare uses OAuth2. In order to enable the backend follow: - -- Register an application at `Foursquare Developers Portal`_, - set the ``Redirect URI`` to ``http:///complete/foursquare/`` - -- Fill in the **Client Id** and **Client Secret** values in your settings:: - - SOCIAL_AUTH_FOURSQUARE_KEY = '' - SOCIAL_AUTH_FOURSQUARE_SECRET = '' - -.. _Foursquare Developers Portal: https://foursquare.com/developers/register diff --git a/docs/backends/github.rst b/docs/backends/github.rst deleted file mode 100644 index d96427568..000000000 --- a/docs/backends/github.rst +++ /dev/null @@ -1,61 +0,0 @@ -GitHub -====== - -GitHub works similar to Facebook (OAuth). - -- Register a new application at `GitHub Developers`_, set the callback URL to - ``http://example.com/complete/github/`` replacing ``example.com`` with your - domain. - -- Fill the ``Client ID`` and ``Client Secret`` values from GitHub in the settings:: - - SOCIAL_AUTH_GITHUB_KEY = '' - SOCIAL_AUTH_GITHUB_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_GITHUB_SCOPE = [...] - - -GitHub for Organizations ------------------------- - -When defining authentication for organizations, use the -``GithubOrganizationOAuth2`` backend instead. The settings are the same as -the non-organization backend, but the names must be:: - - SOCIAL_AUTH_GITHUB_ORG_* - -Be sure to define the organization name using the setting:: - - SOCIAL_AUTH_GITHUB_ORG_NAME = '' - -This name will be used to check that the user really belongs to the given -organization and discard it if they're not part of it. - - -GitHub for Teams ----------------- - -Similar to ``GitHub for Organizations``, there's a GitHub for Teams backend, -use the backend ``GithubTeamOAuth2``. The settings are the same as -the basic backend, but the names must be:: - - SOCIAL_AUTH_GITHUB_TEAM_* - -Be sure to define the ``Team ID`` using the setting:: - - SOCIAL_AUTH_GITHUB_TEAM_ID = '' - -This ``id`` will be used to check that the user really belongs to the given -team and discard it if they're not part of it. - - -Github for Enterprises ----------------------- - -Check the docs :ref:`github-enterprise` if planning to use Github -Enterprises. - - -.. _GitHub Developers: https://github.com/settings/applications/new diff --git a/docs/backends/github_enterprise.rst b/docs/backends/github_enterprise.rst deleted file mode 100644 index 29f5d6d83..000000000 --- a/docs/backends/github_enterprise.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. _github-enterprise: - -GitHub Enterprise -================= - -GitHub Enterprise works similar to regular Github, which is in turn based on Facebook (OAuth). - -- Register a new application on your instance of `GitHub Enterprise Developers`_, - set the callback URL to ``http://example.com/complete/github/`` replacing ``example.com`` - with your domain. - -- Set the API URL for your Github Enterprise appliance: - - SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL = 'https://git.example.com/api/v3/' - -- Fill the ``Client ID`` and ``Client Secret`` values from GitHub in the settings: - - SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY = '' - SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_GITHUB_ENTERPRISE_SCOPE = [...] - - -GitHub Enterprise for Organizations ------------------------------------ - -When defining authentication for organizations, use the -``GithubEnterpriseOrganizationOAuth2`` backend instead. The settings are the same as -the non-organization backend, but the names must be:: - - SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_* - -Be sure to define the organization name using the setting:: - - SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME = '' - -This name will be used to check that the user really belongs to the given -organization and discard it if they're not part of it. - - -GitHub Enterprise for Teams ---------------------------- - -Similar to ``GitHub Enterprise for Organizations``, there's a GitHub for Teams backend, -use the backend ``GithubEnterpriseTeamOAuth2``. The settings are the same as -the basic backend, but the names must be:: - - SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_* - -Be sure to define the ``Team ID`` using the setting:: - - SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID = '' - -This ``id`` will be used to check that the user really belongs to the given -team and discard it if they're not part of it. - -.. _GitHub Enterprise Developers: https:///settings/applications/new diff --git a/docs/backends/google.rst b/docs/backends/google.rst deleted file mode 100644 index e252d8895..000000000 --- a/docs/backends/google.rst +++ /dev/null @@ -1,252 +0,0 @@ -Google -====== - -This section describes how to setup the different services provided by Google. - -Google OAuth ------------- - -.. attention:: **Google OAuth deprecation** - Important: OAuth 1.0 was officially deprecated on April 20, 2012, and will be - shut down on April 20, 2015. We encourage you to migrate to any of the other - protocols. - -Google provides ``Consumer Key`` and ``Consumer Secret`` keys to registered -applications, but also allows unregistered application to use their authorization -system with, but beware that this method will display a security banner to the -user telling that the application is not trusted. - -Check `Google OAuth`_ and make your choice. - -- fill ``Consumer Key`` and ``Consumer Secret`` values:: - - SOCIAL_AUTH_GOOGLE_OAUTH_KEY = '' - SOCIAL_AUTH_GOOGLE_OAUTH_SECRET = '' - -anonymous values will be used if not configured as described in their -`OAuth reference`_ - -- setup any needed extra scope in:: - - SOCIAL_AUTH_GOOGLE_OAUTH_SCOPE = [...] - - -Google OAuth2 -------------- - -Recently Google launched OAuth2 support following the definition at `OAuth2 draft`. -It works in a similar way to plain OAuth mechanism, but developers **must** register -an application and apply for a set of keys. Check `Google OAuth2`_ document for details. - -When creating the application in the Google Console be sure to fill the -``PRODUCT NAME`` at ``API & auth -> Consent screen`` form. - -To enable OAuth2 support: - -- fill ``Client ID`` and ``Client Secret`` settings, these values can be obtained - easily as described on `OAuth2 Registering`_ doc:: - - SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '' - SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '' - -- setup any needed extra scope:: - - SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [...] - -Check which applications can be included in their `Google Data Protocol Directory`_ - - -Google+ Sign-In ---------------- - -`Google+ Sign In`_ works a lot like OAuth2, but most of the initial work is -done by their Javascript which thens calls a defined handler to complete the -auth process. - -* To enable the backend create an application using the `Google - console`_ and following the steps from the `official guide`_. Make - sure to enable the Google+ API in the console. - -* Fill in the key settings looking inside the Google console the subsection - ``Credentials`` inside ``API & auth``:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.google.GooglePlusAuth', - ) - - SOCIAL_AUTH_GOOGLE_PLUS_KEY = '...' - SOCIAL_AUTH_GOOGLE_PLUS_SECRET = '...' - - ``SOCIAL_AUTH_GOOGLE_PLUS_KEY`` corresponds to the variable ``CLIENT ID``. - ``SOCIAL_AUTH_GOOGLE_PLUS_SECRET`` corresponds to the variable - ``CLIENT SECRET``. - -* Add the sign-in button to your template, you can use the SDK button - or add your own and attach the click handler to it (check `Google+ Identity Sign-In`_ - documentation about it):: - -
Google+ Sign In
- -* Add the Javascript snippet in the same template as above:: - - - - - -* Logging out - - Logging-out can be tricky when using the the platform SDK because it - can trigger an automatic sign-in when listening to the user status - change. With the method show above, that won't happen, but if the UI - depends more in the SDK values than the backend, then things can get - out of sync easilly. To prevent this, the user should be logged-out - from Google+ platform too. This can be accomplished by doing:: - - - - -Google OpenId -------------- - -Google OpenId works straightforward, not settings are needed. Domains or emails -whitelists can be applied too, check the whitelists_ settings for details. - - -Orkut ------ - -As of September 30, 2014, Orkut has been `shut down`_. - -User identification -------------------- - -Optional support for static and unique Google Profile ID identifiers instead of -using the e-mail address for account association can be enabled with:: - - SOCIAL_AUTH_GOOGLE_OAUTH_USE_UNIQUE_USER_ID = True - -or:: - - SOCIAL_AUTH_GOOGLE_OAUTH2_USE_UNIQUE_USER_ID = True - -depending on the backends in use. - - -Refresh Tokens --------------- - -To get an OAuth2 refresh token along with the access token, you must pass an extra argument: ``access_type=offline``. -To do this with Google+ sign-in:: - - SOCIAL_AUTH_GOOGLE_PLUS_AUTH_EXTRA_ARGUMENTS = { - 'access_type': 'offline' - } - - -Scopes deprecation ------------------- - -Google is deprecating the full-url scopes from `Sept 1, 2014`_ in favor of -``Google+ API`` and the recently introduced shorter scopes names. But -``python-social-auth`` already introduced the scopes change at e3525187_ which -was released at ``v0.1.24``. - -But, to enable the new scopes the application requires ``Google+ API`` to be -enabled in the `Google console`_ dashboard, the change is quick and quite -simple, but if any developer desires to keep using the old scopes, it's -possible with the following settings:: - - # Google OAuth2 (google-oauth2) - SOCIAL_AUTH_GOOGLE_OAUTH2_IGNORE_DEFAULT_SCOPE = True - SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [ - 'https://www.googleapis.com/auth/userinfo.email', - 'https://www.googleapis.com/auth/userinfo.profile' - ] - - # Google+ SignIn (google-plus) - SOCIAL_AUTH_GOOGLE_PLUS_IGNORE_DEFAULT_SCOPE = True - SOCIAL_AUTH_GOOGLE_PLUS_SCOPE = [ - 'https://www.googleapis.com/auth/plus.login', - 'https://www.googleapis.com/auth/userinfo.email', - 'https://www.googleapis.com/auth/userinfo.profile' - ] - -To ease the change, the old API and scopes is still supported by the -application, the new values are the default option but if having troubles -supporting them you can default to the old values by defining this setting:: - - SOCIAL_AUTH_GOOGLE_OAUTH2_USE_DEPRECATED_API = True - SOCIAL_AUTH_GOOGLE_PLUS_USE_DEPRECATED_API = True - -.. _Google support: http://www.google.com/support/a/bin/answer.py?hl=en&answer=162105 -.. _Google OpenID: http://code.google.com/apis/accounts/docs/OpenID.html -.. _Google OAuth: http://code.google.com/apis/accounts/docs/OAuth.html -.. _Google OAuth2: http://code.google.com/apis/accounts/docs/OAuth2.html -.. _OAuth2 Registering: http://code.google.com/apis/accounts/docs/OAuth2.html#Registering -.. _OAuth2 draft: http://tools.ietf.org/html/draft-ietf-oauth-v2-10 -.. _OAuth reference: http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth -.. _shut down: https://support.google.com/orkut/?csw=1#Authenticating -.. _Google Data Protocol Directory: http://code.google.com/apis/gdata/docs/directory.html -.. _whitelists: ../configuration/settings.html#whitelists -.. _Google+ Sign In: https://developers.google.com/+/web/signin/ -.. _Google console: https://code.google.com/apis/console -.. _official guide: https://developers.google.com/+/web/signin/#step_1_create_a_client_id_and_client_secret -.. _Sept 1, 2014: https://developers.google.com/+/api/auth-migration#timetable -.. _e3525187: https://github.com/omab/python-social-auth/commit/e35251878a88954cecf8e575eca27c63164b9f67 -.. _Google+ Identity Sign-In: https://developers.google.com/identity/sign-in/web/sign-in diff --git a/docs/backends/implementation.rst b/docs/backends/implementation.rst deleted file mode 100644 index 8687b9446..000000000 --- a/docs/backends/implementation.rst +++ /dev/null @@ -1,308 +0,0 @@ -Adding a new backend -==================== - -Add new backends is quite easy, usually adding just a ``class`` with a couple -settings and methods overrides to retrieve user data from services API. Follow -the details below. - - -Common attributes ------------------ - -First, lets check the common attributes for all backend types. - -``name = ''`` - Any backend needs a name, usually the popular name of the service is used, - like ``facebook``, ``twitter``, etc. It must be unique, otherwise another - backend can take precedence if it's listed before in - ``AUTHENTICATION_BACKENDS`` setting. - -``ID_KEY = None`` - Defines the attribute in the service response that identifies the user as - unique in the service, the value is later stored in the ``uid`` attribute - in the ``UserSocialAuth`` instance. - -``REQUIRES_EMAIL_VALIDATION = False`` - Flags the backend to enforce email validation during the pipeline (if the - corresponding pipeline ``social.pipeline.mail.mail_validation`` was - enabled). - -``EXTRA_DATA = None`` - During the auth process some basic user data is returned by the provider or - retrieved by ``user_data()`` method which usually is used to call some API - on the provider to retrieve it. This data will be stored under - ``UserSocialAuth.extra_data`` attribute, but to make it accessible under - some common names on different providers, this attribute defines a list of - tuples in the form ``(name, alias)`` where ``name`` is the key in the user - data (which should be a ``dict`` instance) and ``alias`` is the name to - store it on ``extra_data``. - - -OAuth ------ - -OAuth1 and OAuth2 provide share some common definitions based on the shared -behavior during the auth process, like a successful API response from -``AUTHORIZATION_URL`` usually returns some basic user data like a user Id. - - -Shared attributes -***************** - -``name`` - This defines the backend name and identifies it during the auth process. - The name is used in the URLs ``/login/`` and - ``/complete/``. - -``ID_KEY = 'id'`` - Default key name where user identification field is defined, it's used on - auth process when some basic user data is returned. This Id is stored in - ``UserSocialAuth.uid`` field, this together the ``UserSocialAuth.provider`` - field is used to unique identify a user association. - -``SCOPE_PARAMETER_NAME = 'scope'`` - Scope argument is used to tell the provider the API endpoints you want to - call later, it's a permissions request granted over the ``access_token`` - later retrieved. Default value is ``scope`` since that's usually the name - used in the URL parameter, but can be overridden if needed. - -``DEFAULT_SCOPE = None`` - Some providers give nothing about the user but some basic data in required - like the user Id or an email address. Default scope attribute is used to - specify a default value for ``scope`` argument to request those extra used - bits. - -``SCOPE_SEPARATOR = ' '`` - The ``scope`` argument is usually a list of permissions to request, the - list is joined used a separator, usually just a blank space, but differ - from provider to provider, override the default value with this attribute - if it differs. - - -OAuth2 -****** - -OAuth2 backends are fairly simple to implement; just a few settings, a method -override and it's mostly ready to go. - -The key points on this backends are: - -``AUTHORIZATION_URL`` - This is the entry point for the authorization mechanism, users must be - redirected to this URL, used on ``auth_url`` method which builds the - redirect address with ``AUTHORIZATION_URL`` plus some arguments - (``client_id``, ``redirect_uri``, ``response_type``, and ``state``). - -``ACCESS_TOKEN_URL`` - Must point to the API endpoint that provides an ``access_token`` needed to - authenticate in users behalf on future API calls. - -``REFRESH_TOKEN_URL`` - Some providers give the option to renew the ``access_token`` since they are - usually limited in time, once that time runs out, the token is invalidated - and cannot be used any more. This attribute should point to that API - endpoint. - -``RESPONSE_TYPE`` - The response type expected on the auth process, default value is ``code`` - as dictated by OAuth2 definition. Override it if default value doesn't fit - the provider implementation. - -``STATE_PARAMETER`` - OAuth2 defines that an ``state`` parameter can be passed in order to - validate the process, it's kind of a CSRF check to avoid man in the middle - attacks. Some don't recognise it or don't return it which will make the - auth process invalid. Set this attribute to ``False`` in that case. - -``REDIRECT_STATE`` - For those providers that don't recognise the ``state`` parameter, the app - can add a ``redirect_state`` argument to the ``redirect_uri`` to mimic it. - Set this value to ``False`` if the provider likes to verify the - ``redirect_uri`` value and this parameter invalidates that check. - - -Example code:: - - from social.backends.oauth import BaseOAuth2 - - class GithubOAuth2(BaseOAuth2): - """Github OAuth authentication backend""" - name = 'github' - AUTHORIZATION_URL = 'https://github.com/login/oauth/authorize' - ACCESS_TOKEN_URL = 'https://github.com/login/oauth/access_token' - SCOPE_SEPARATOR = ',' - EXTRA_DATA = [ - ('id', 'id'), - ('expires', 'expires') - ] - - def get_user_details(self, response): - """Return user details from Github account""" - return {'username': response.get('login'), - 'email': response.get('email') or '', - 'first_name': response.get('name')} - - def user_data(self, access_token, *args, **kwargs): - """Loads user data from service""" - url = 'https://api.github.com/user?' + urlencode({ - 'access_token': access_token - }) - try: - return json.load(self.urlopen(url)) - except ValueError: - return None - - -OAuth1 -****** - -OAuth1 process is a bit more trickier, `Twitter Docs`_ explains it quite well. -Beside the ``AUTHORIZATION_URL`` and ``ACCESS_TOKEN_URL`` attributes, a third -one is needed used when starting the process. - -``REQUEST_TOKEN_URL = ''`` - During the auth process an unauthorized token is needed to start the - process, later this token is exchanged for an ``access_token``. This - setting points to the API endpoint where that unauthorized token can be - retrieved. - -Example code:: - - from xml.dom import minidom - - from social.backends.oauth import ConsumerBasedOAuth - - - class TripItOAuth(ConsumerBasedOAuth): - """TripIt OAuth authentication backend""" - name = 'tripit' - AUTHORIZATION_URL = 'https://www.tripit.com/oauth/authorize' - REQUEST_TOKEN_URL = 'https://api.tripit.com/oauth/request_token' - ACCESS_TOKEN_URL = 'https://api.tripit.com/oauth/access_token' - EXTRA_DATA = [('screen_name', 'screen_name')] - - def get_user_details(self, response): - """Return user details from TripIt account""" - try: - first_name, last_name = response['name'].split(' ', 1) - except ValueError: - first_name = response['name'] - last_name = '' - return {'username': response['screen_name'], - 'email': response['email'], - 'fullname': response['name'], - 'first_name': first_name, - 'last_name': last_name} - - def user_data(self, access_token, *args, **kwargs): - """Return user data provided""" - url = 'https://api.tripit.com/v1/get/profile' - request = self.oauth_request(access_token, url) - content = self.fetch_response(request) - try: - dom = minidom.parseString(content) - except ValueError: - return None - - return { - 'id': dom.getElementsByTagName('Profile')[0].getAttribute('ref'), - 'name': dom.getElementsByTagName( - 'public_display_name')[0].childNodes[0].data, - 'screen_name': dom.getElementsByTagName( - 'screen_name')[0].childNodes[0].data, - 'email': dom.getElementsByTagName( - 'is_primary')[0].parentNode.getElementsByTagName( - 'address')[0].childNodes[0].data, - } - - -OpenId ------- - -OpenId is fair simpler that OAuth since it's used for authentication rather -than authorization (regardless it's used for authorization too). - -A single attribute is usually needed, the authentication URL endpoint. - -``URL = ''`` - OpenId endpoint where to redirect the user. - -Sometimes the URL is user dependant, like in myOpenId_ where the URL is -``https://.myopenid.com``. For those cases where the user must -input it's handle (or full URL). The backend must override the ``openid_url()`` -method to retrieve it and return a full URL to where the user will be -redirected. - -Example code:: - - from social.backends.open_id import OpenIdAuth - from social.exceptions import AuthMissingParameter - - - class LiveJournalOpenId(OpenIdAuth): - """LiveJournal OpenID authentication backend""" - name = 'livejournal' - - def get_user_details(self, response): - """Generate username from identity url""" - values = super(LiveJournalOpenId, self).get_user_details(response) - values['username'] = values.get('username') or \ - urlparse.urlsplit(response.identity_url)\ - .netloc.split('.', 1)[0] - return values - - def openid_url(self): - """Returns LiveJournal authentication URL""" - if not self.data.get('openid_lj_user'): - raise AuthMissingParameter(self, 'openid_lj_user') - return 'http://%s.livejournal.com' % self.data['openid_lj_user'] - - -Auth APIs ---------- - -For others authentication types, a ``BaseAuth`` class is defined to help. Those -custom auth methods must override the ``auth_url()`` and ``auth_complete()`` -methods. - -Example code:: - - from google.appengine.api import users - - from social.backends.base import BaseAuth - from social.exceptions import AuthException - - - class GoogleAppEngineAuth(BaseAuth): - """GoogleAppengine authentication backend""" - name = 'google-appengine' - - def get_user_id(self, details, response): - """Return current user id.""" - user = users.get_current_user() - if user: - return user.user_id() - - def get_user_details(self, response): - """Return user basic information (id and email only).""" - user = users.get_current_user() - return {'username': user.user_id(), - 'email': user.email(), - 'fullname': '', - 'first_name': '', - 'last_name': ''} - - def auth_url(self): - """Build and return complete URL.""" - return users.create_login_url(self.redirect_uri) - - def auth_complete(self, *args, **kwargs): - """Completes login process, must return user instance.""" - if not users.get_current_user(): - raise AuthException('Authentication error') - kwargs.update({'response': '', 'backend': self}) - return self.strategy.authenticate(*args, **kwargs) - - -.. _Twitter Docs: https://dev.twitter.com/docs/auth/implementing-sign-twitter -.. _myOpenId: https://www.myopenid.com/ diff --git a/docs/backends/index.rst b/docs/backends/index.rst deleted file mode 100644 index 37c29bbec..000000000 --- a/docs/backends/index.rst +++ /dev/null @@ -1,156 +0,0 @@ -Backends -======== - -Here's a list and detailed instruction on how to setup the support for each -backend. - -Adding new backend support --------------------------- - -Add new backends is quite easy, usually adding just a ``class`` with a couple -methods overrides to retrieve user data from services API. Follow the details -in the *Implementation* docs. - -.. toctree:: - :maxdepth: 2 - - implementation - - -Supported backends ------------------- - -Here's the list of currently supported backends. - -Non-social backends -******************* - -.. toctree:: - :maxdepth: 2 - - email - username - -Base OAuth and OpenId classes -***************************** - -.. toctree:: - :maxdepth: 2 - - oauth - openid - saml - -Social backends -*************** - -.. toctree:: - :maxdepth: 2 - - amazon - angel - aol - appsfuel - arcgis - azuread - battlenet - beats - behance - belgium_eid - bitbucket - box - changetip - clef - coinbase - coursera - dailymotion - digitalocean - disqus - docker - douban - dribbble - drip - dropbox - edmodo - eveonline - evernote - facebook - fedora - fitbit - flickr - foursquare - github - github_enterprise - google - instagram - itembase - jawbone - justgiving - kakao - khanacademy - lastfm - launchpad - line - linkedin - livejournal - live - loginradius - mailru - mapmyfitness - meetup - mendeley - mineid - mixcloud - moves - naszaklasa - nationbuilder - naver - ngpvan_actionid - odnoklassnikiru - openstreetmap - orbi - persona - pinterest - pixelpin - pocket - podio - qiita - qq - rdio - readability - reddit - runkeeper - salesforce - shopify - sketchfab - skyrock - slack - soundcloud - spotify - suse - stackoverflow - steam - stocktwits - strava - stripe - taobao - thisismyjam - trello - tripit - tumblr - twilio - twitch - twitter - uber - untappd - upwork - vend - vimeo - vk - weibo - withings - wunderlist - xing - yahoo - yammer - zotero diff --git a/docs/backends/instagram.rst b/docs/backends/instagram.rst deleted file mode 100644 index dbaf86e1f..000000000 --- a/docs/backends/instagram.rst +++ /dev/null @@ -1,25 +0,0 @@ -Instagram -========= - -Instagram uses OAuth v2 for Authentication. - -- Register a new application at the `Instagram API`_, and - -- Add instagram backend to ``AUTHENTICATION_SETTINGS``:: - - AUTHENTICATION_SETTINGS = ( - ... - 'social.backends.instagram.InstagramOAuth2', - ... - ) - -- fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_INSTAGRAM_KEY = '' - SOCIAL_AUTH_INSTAGRAM_SECRET = '' - -- extra scopes can be defined by using:: - - SOCIAL_AUTH_INSTAGRAM_AUTH_EXTRA_ARGUMENTS = {'scope': 'likes comments relationships'} - -.. _Instagram API: http://instagr.am/developer/ diff --git a/docs/backends/itembase.rst b/docs/backends/itembase.rst deleted file mode 100644 index 715d1b427..000000000 --- a/docs/backends/itembase.rst +++ /dev/null @@ -1,51 +0,0 @@ -Itembase -========= - -Itembase uses OAuth2 for authentication. - -- Register a new application for the `Itembase API`_, and - -- Add itembase live backend and/or sandbox backend to ``AUTHENTICATION_BACKENDS``:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.itembase.ItembaseOAuth2', - 'social.backends.itembase.ItembaseOAuth2Sandbox', - ... - ) - -- fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_ITEMBASE_KEY = '' - SOCIAL_AUTH_ITEMBASE_SECRET = '' - - SOCIAL_AUTH_ITEMBASE_SANDBOX_KEY = '' - SOCIAL_AUTH_ITEMBASE_SANDBOX_SECRET = '' - - -- extra scopes can be defined by using:: - - SOCIAL_AUTH_ITEMBASE_SCOPE = ['connection.transaction', - 'connection.product', - 'connection.profile', - 'connection.buyer'] - SOCIAL_AUTH_ITEMBASE_SANDBOX_SCOPE = SOCIAL_AUTH_ITEMBASE_SCOPE - -To use data from the extra scopes, you need to do an extra activation step -that is not in the usual OAuth flow. For that you can extend your pipeline and -add a function that sends the user to an activation URL that Itembase provides. -The method to retrieve the activation data is included in the backend:: - - @partial - def activation(strategy, backend, response, *args, **kwargs): - if backend.name.startswith("itembase"): - - if strategy.session_pop('itembase_activation_in_progress'): - strategy.session_set('itembase_activated', True) - - if not strategy.session_get('itembase_activated'): - activation_data = backend.activation_data(response) - strategy.session_set('itembase_activation_in_progress', True) - return HttpResponseRedirect(activation_data['activation_url']) - -.. _Itembase API: http://developers.itembase.com/authentication/index diff --git a/docs/backends/jawbone.rst b/docs/backends/jawbone.rst deleted file mode 100644 index 64d9ec206..000000000 --- a/docs/backends/jawbone.rst +++ /dev/null @@ -1,22 +0,0 @@ -Jawbone -======= - -Jawbone uses OAuth2. In order to enable the backend follow: - -- Register an application at `Jawbone Developer Portal`_, set the ``OAuth - redirect URIs`` to ``http:///complete/jawbone/`` - -- Fill in the **Client Id** and **Client Secret** values in your settings:: - - SOCIAL_AUTH_JAWBONE_KEY = '' - SOCIAL_AUTH_JAWBONE_SECRET = '' - -- Specify scopes with:: - - SOCIAL_AUTH_JAWBONE_SCOPE = [...] - - Available scopes are listed in the `Jawbone Authentication Reference`_, - "socpes" section. - -.. _Jawbone Developer Portal: https://jawbone.com/up/developer/account/ -.. _Jawbone Authentication Reference: https://jawbone.com/up/developer/authentication diff --git a/docs/backends/justgiving.rst b/docs/backends/justgiving.rst deleted file mode 100644 index 9a5fd6ea6..000000000 --- a/docs/backends/justgiving.rst +++ /dev/null @@ -1,23 +0,0 @@ -Just Giving -=========== - -OAuth2 ------- - -Follow the steps at `Just Giving API Docs`_ to register your -application and get the needed keys. - -- Add the Just Giving OAuth2 backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.justgiving.JustGivingOAuth2', - ... - ) - -- Fill ``App Key`` and ``App Secret`` values in the settings:: - - SOCIAL_AUTH_JUSTGIVING_KEY = '' - SOCIAL_AUTH_JUSTGIVING_SECRET = '' - -.. _Just Giving API Docs: https://api.justgiving.com/docs diff --git a/docs/backends/kakao.rst b/docs/backends/kakao.rst deleted file mode 100644 index 4a2fbaa16..000000000 --- a/docs/backends/kakao.rst +++ /dev/null @@ -1,17 +0,0 @@ -Kakao -====== - -Kakao uses OAuth v2 for Authentication. - -- Register a new applicationat the `Kakao API`_, and - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_KAKAO_KEY = '' - SOCIAL_AUTH_KAKAO_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_KAKAO_SCOPE = [...] - -.. _Kakao API: https://developers.kakao.com/docs/restapi diff --git a/docs/backends/khanacademy.rst b/docs/backends/khanacademy.rst deleted file mode 100644 index 79e2f618c..000000000 --- a/docs/backends/khanacademy.rst +++ /dev/null @@ -1,25 +0,0 @@ -Khan Academy -============ - -Khan Academy uses a variant of OAuth1 authentication flow. Check the API -details at `Khan Academy API Authentication`_. - -Follow this steps in order to use the backend: - -- Register a new application at `Khan Academy API Apps`_, - -- Fill **Consumer Key** and **Consumer Secret** values:: - - SOCIAL_AUTH_KHANACADEMY_OAUTH1_KEY = '' - SOCIAL_AUTH_KHANACADEMY_OAUTH1_SECRET = '' - -- Add the backend to ``AUTHENTICATION_BACKENDS`` setting:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.khanacademy.KhanAcademyOAuth1', - ... - ) - -.. _Khan Academy API Authentication: https://github.com/Khan/khan-api/wiki/Khan-Academy-API-Authentication -.. _Khan Academy API Apps: http://www.khanacademy.org/api-apps/register diff --git a/docs/backends/lastfm.rst b/docs/backends/lastfm.rst deleted file mode 100644 index 0dc7e1b30..000000000 --- a/docs/backends/lastfm.rst +++ /dev/null @@ -1,17 +0,0 @@ -Last.fm -======= - -Last.fm uses a similar authentication process than OAuth2 but it's not. In -order to enable the support for it just: - -- Register an application at `Get an API Account`_, set the Last.fm callback to - something sensible like http://your.site/complete/lastfm - -- Fill in the **API Key** and **API Secret** values in your settings:: - - SOCIAL_AUTH_LASTFM_KEY = '' - SOCIAL_AUTH_LASTFM_SECRET = '' - -- Enable the backend in ``AUTHENTICATION_BACKENDS`` setting. - -.. _Get an API Account: http://www.last.fm/api/account/create diff --git a/docs/backends/launchpad.rst b/docs/backends/launchpad.rst deleted file mode 100644 index 7f12f35fe..000000000 --- a/docs/backends/launchpad.rst +++ /dev/null @@ -1,11 +0,0 @@ -Launchpad -========= - -`Ubuntu Launchpad `_ OpenId doesn't require -major settings beside being defined on ``AUTHENTICATION_BACKENDS```:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.launchpad.LaunchpadOpenId', - ... - ) diff --git a/docs/backends/line.rst b/docs/backends/line.rst deleted file mode 100644 index f63c611a1..000000000 --- a/docs/backends/line.rst +++ /dev/null @@ -1,7 +0,0 @@ -Line.me -======= - -Fill App Id and Secret in your project settings:: - - SOCIAL_AUTH_LINE_KEY = '...' - SOCIAL_AUTH_LINE_SECRET = '...' diff --git a/docs/backends/linkedin.rst b/docs/backends/linkedin.rst deleted file mode 100644 index a7f9ccc87..000000000 --- a/docs/backends/linkedin.rst +++ /dev/null @@ -1,68 +0,0 @@ -LinkedIn -======== - -LinkedIn supports OAuth1 and OAuth2. Migration between each type is fair simple -since the same Key / Secret pair is used for both authentication types. - -LinkedIn OAuth setup is similar to any other OAuth service. The auth flow is -explained on `LinkedIn Developers`_ docs. First you will need to register an -app att `LinkedIn Developer Network`_. - - -OAuth1 ------- - -- Fill the application key and secret in your settings:: - - SOCIAL_AUTH_LINKEDIN_KEY = '' - SOCIAL_AUTH_LINKEDIN_SECRET = '' - -- Application scopes can be specified by:: - - SOCIAL_AUTH_LINKEDIN_SCOPE = [...] - - Check the available options at `LinkedIn Scopes`_. If you want to request - a user's email address, you'll need specify that your application needs - access to the email address use the ``r_emailaddress`` scope. - -- To request extra fields using `LinkedIn fields selectors`_ just define this - setting:: - - SOCIAL_AUTH_LINKEDIN_FIELD_SELECTORS = [...] - - with the needed fields selectors, also define ``SOCIAL_AUTH_LINKEDIN_EXTRA_DATA`` - properly as described in `OAuth `_, that way the values will be - stored in ``UserSocialAuth.extra_data`` field. By default ``id``, - ``first-name`` and ``last-name`` are requested and stored. - -For example, to request a user's email, headline, and industry from the -Linkedin API and store the information in ``UserSocialAuth.extra_data``, you -would add these settings:: - - # Add email to requested authorizations. - SOCIAL_AUTH_LINKEDIN_SCOPE = ['r_basicprofile', 'r_emailaddress', ...] - # Add the fields so they will be requested from linkedin. - SOCIAL_AUTH_LINKEDIN_FIELD_SELECTORS = ['email-address', 'headline', 'industry'] - # Arrange to add the fields to UserSocialAuth.extra_data - SOCIAL_AUTH_LINKEDIN_EXTRA_DATA = [('id', 'id'), - ('firstName', 'first_name'), - ('lastName', 'last_name'), - ('emailAddress', 'email_address'), - ('headline', 'headline'), - ('industry', 'industry')] - -OAuth2 ------- - -OAuth2 works exacly the same than OAuth1, but the settings must be named as:: - - SOCIAL_AUTH_LINKEDIN_OAUTH2_* - -Looks like LinkedIn is forcing the definition of the callback URL in the -application when OAuth2 is used. Be sure to set the proper values, otherwise -a ``(400) Client Error: Bad Request`` might be returned by their service. - -.. _LinkedIn fields selectors: http://developer.linkedin.com/docs/DOC-1014 -.. _LinkedIn Scopes: https://developer.linkedin.com/documents/authentication#granting -.. _LinkedIn Developer Network: https://www.linkedin.com/secure/developer -.. _LinkedIn Developers: http://developer.linkedin.com/documents/authentication diff --git a/docs/backends/live.rst b/docs/backends/live.rst deleted file mode 100644 index 0ede6c3af..000000000 --- a/docs/backends/live.rst +++ /dev/null @@ -1,24 +0,0 @@ -MSN Live Connect -================ - -Live uses OAuth2 for its connect workflow, notice that it isn't OAuth WRAP. - -- Register a new application at `Live Connect Developer Center`_, set your site - domain as redirect domain, - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_LIVE_KEY = '' - SOCIAL_AUTH_LIVE_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_LIVE_SCOPE = [...] - - Defaults are ``wl.basic`` and ``wl.emails``. Latter one is necessary to - retrieve user email. - -- Ensure to have a valid ``Redirect URL`` (``http://your-domain/complete/live``) - defined in the application if ``Enhanced security redirection`` is enabled. - -.. _Live Connect Developer Center: https://account.live.com/developers/applications/create diff --git a/docs/backends/livejournal.rst b/docs/backends/livejournal.rst deleted file mode 100644 index 683ef639a..000000000 --- a/docs/backends/livejournal.rst +++ /dev/null @@ -1,16 +0,0 @@ -LiveJournal -=========== - -LiveJournal provides OpenId, it doesn't require any major settings in order to -work, beside being defined on ``AUTHENTICATION_BACKENDS```:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.aol.AOLOpenId', - ... - ) - -LiveJournal OpenId is provided by URLs in the form ``http://.livejournal.com``, -this application retrieves the ``username`` from the data in the current -request by checking a parameter named ``openid_lj_user`` which can be sent by -``POST`` or ``GET``. diff --git a/docs/backends/loginradius.rst b/docs/backends/loginradius.rst deleted file mode 100644 index f16d57689..000000000 --- a/docs/backends/loginradius.rst +++ /dev/null @@ -1,48 +0,0 @@ -LoginRadius -=========== - -LoginRadius uses OAuth2 for Authentication with other providers with an HTML -widget used to trigger the auth process. - -- Register a new application at the `LoginRadius Website`_, and - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_LOGINRADIUS_KEY = '' - SOCIAL_AUTH_LOGINRADIUS_SECRET = '' - -- Since the auth process is triggered by LoginRadius JS script, you need to - sever such content to the user, all you need to do that is a template with - the following content:: - -
- - - - Put that content in a template named ``loginradius.html`` (accessible to your - framework), or define a name with ``SOCIAL_AUTH_LOGINRADIUS_TEMPLATE`` setting, - like:: - - SOCIAL_AUTH_LOGINRADIUS_LOCAL_HTML = 'loginradius.html' - - The template context will have the current backend instance under the - ``backend`` name, also the application key (``LOGINRADIUS_KEY``) and the - redirect URL (``LOGINRADIUS_REDIRECT_URL``). - -- Further documentation can be found at `LoginRadius API Documentation`_ and - `LoginRadius Datapoints`_ - -.. _LoginRadius Website: https://loginradius.com/ -.. _LoginRadius API Documentation: http://api.loginradius.com/help/ -.. _LoginRadius Datapoints: http://www.loginradius.com/datapoints/ diff --git a/docs/backends/mailru.rst b/docs/backends/mailru.rst deleted file mode 100644 index 9c24dbe60..000000000 --- a/docs/backends/mailru.rst +++ /dev/null @@ -1,7 +0,0 @@ -Mail.ru OAuth -============= - -Mail.ru uses OAuth2 workflow, to use it fill in settings:: - - SOCIAL_AUTH_MAILRU_OAUTH2_KEY = '' - SOCIAL_AUTH_MAILRU_OAUTH2_SECRET = '' diff --git a/docs/backends/mapmyfitness.rst b/docs/backends/mapmyfitness.rst deleted file mode 100644 index 6a5876eb8..000000000 --- a/docs/backends/mapmyfitness.rst +++ /dev/null @@ -1,13 +0,0 @@ -MapMyFitness -============ - -MapMyFitness uses OAuth v2 for authentication. - -- Register a new application at the `MapMyFitness API`_, and - -- fill ``key`` and ``secret`` values in the settings:: - - SOCIAL_AUTH_MAPMYFITNESS_KEY = '' - SOCIAL_AUTH_MAPMYFITNESS_SECRET = '' - -.. _MapMyFitness API: https://www.mapmyapi.com diff --git a/docs/backends/meetup.rst b/docs/backends/meetup.rst deleted file mode 100644 index 558c3ad3c..000000000 --- a/docs/backends/meetup.rst +++ /dev/null @@ -1,14 +0,0 @@ -Meetup -====== - -Meetup.com uses OAuth2 for its auth mechanism. - -- Register a new OAuth Consumer at `Meetup Consumer Registration`_, set your - consumer name, redirect uri. - -- Fill ``key`` and ``secret`` values in the settings:: - - SOCIAL_AUTH_MEETUP_KEY = '' - SOCIAL_AUTH_MEETUP_SECRET = '' - -.. _Meetup Consumer Registration: https://secure.meetup.com/meetup_api/oauth_consumers/create diff --git a/docs/backends/mendeley.rst b/docs/backends/mendeley.rst deleted file mode 100644 index fe2c79da3..000000000 --- a/docs/backends/mendeley.rst +++ /dev/null @@ -1,38 +0,0 @@ -Mendeley -======== - -Mendeley supports OAuth1 and OAuth2, they are in the process of deprecating -OAuth1 API (which should be fully deprecated on April 2014, check their -announcement_). - - -OAuth1 ------- - -In order to support OAuth1 (not recomended, use OAuth2 instead): - -- Register a new application at `Mendeley Application Registration`_ - -- Fill **Consumer Key** and **Consumer Secret** values:: - - SOCIAL_AUTH_MENDELEY_KEY = '' - SOCIAL_AUTH_MENDELEY_SECRET = '' - - -OAuth2 ------- - -In order to support OAuth2: - -- Register a new application at `Mendeley Application Registration`_, or - migrate your OAuth1 application, check their `migration steps here`_. - -- Fill **Application ID** and **Application Secret** values:: - - SOCIAL_AUTH_MENDELEY_OAUTH2_KEY = '' - SOCIAL_AUTH_MENDELEY_OAUTH2_SECRET = '' - - -.. _Mendeley Application Registration: http://dev.mendeley.com/applications/register/ -.. _announcement: https://sites.google.com/site/mendeleyapi/home/authentication -.. _migration steps here: https://groups.google.com/forum/#!topic/mendeley-open-api-developers/KmUQW9I0ST0 diff --git a/docs/backends/mineid.rst b/docs/backends/mineid.rst deleted file mode 100644 index c7b0557c1..000000000 --- a/docs/backends/mineid.rst +++ /dev/null @@ -1,25 +0,0 @@ -MineID -====== - -MineID works similar to Facebook (OAuth). - -- Register a new application at `MineID.org`_, set the callback URL to - ``http://example.com/complete/mineid/`` replacing ``example.com`` with your - domain. - -- Fill ``Client ID`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_MINEID_KEY = '' - SOCIAL_AUTH_MINEID_SECRET = '' - - -Self-hosted MineID ------------------- - -Since MineID is an Open Source software and can be self-hosted, you can -change settings to point to your instance:: - - SOCIAL_AUTH_MINEID_HOST = 'www.your-mineid-instance.com' - SOCIAL_AUTH_MINEID_SCHEME = 'https' # or 'http' - -.. _MineID.org: https://www.mineid.org/ diff --git a/docs/backends/mixcloud.rst b/docs/backends/mixcloud.rst deleted file mode 100644 index 5d3affe3a..000000000 --- a/docs/backends/mixcloud.rst +++ /dev/null @@ -1,31 +0,0 @@ -Mixcloud OAuth2 -=============== - -The `Mixcloud API`_ offers support for authorization. To this backend support: - -- Register a new application at `Mixcloud Developers`_ - -- Add Mixcloud backend to ``AUTHENTICATION_BACKENDS`` in settings:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.mixcloud.MixcloudOAuth2', - ) - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_MIXCLOUD_KEY = '' - SOCIAL_AUTH_MIXCLOUD_SECRET = '' - -- Similar to the other OAuth backends you can define:: - - SOCIAL_AUTH_MIXCLOUD_EXTRA_DATA = [('username', 'username'), - ('name', 'name'), - ('pictures', 'pictures'), - ('url', 'url')] - - as a list of tuples ``(response name, alias)`` to store user profile data on - the ``UserSocialAuth.extra_data``. - -.. _Mixcloud API: http://www.mixcloud.com/developers/documentation -.. _Mixcloud Developers: http://www.mixcloud.com/developers diff --git a/docs/backends/moves.rst b/docs/backends/moves.rst deleted file mode 100644 index d5d7ad924..000000000 --- a/docs/backends/moves.rst +++ /dev/null @@ -1,31 +0,0 @@ -Moves -===== - -Moves_ provides an OAuth2 authentication flow. In order to enable it: - -- Register an application at `Manage Your Apps`_, remember to fill the - ``Redirect URI`` once the application was created. - -- Fill **Client ID** and **Client secret** in the settings:: - - SOCIAL_AUTH_MOVES_KEY = '' - SOCIAL_AUTH_MOVES_SECRET = '' - -- Define the mandatory scope for your application:: - - SOCIAL_AUTH_MOVES_SCOPE = ['activity', 'location'] - - The scope parameter is required by Moves_ but the backend doesn't set - a default one to minimize the application permissions request, so it's - mandatory for the developer to define this setting. - -- Add the backend to the ``AUTHENTICATION_BACKENDS`` setting:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.moves.MovesOAuth2', - ... - ) - -.. _Moves: http://moves-app.com/ -.. _Manage Your Apps: https://dev.moves-app.com/apps diff --git a/docs/backends/naszaklasa.rst b/docs/backends/naszaklasa.rst deleted file mode 100644 index 01fe78e99..000000000 --- a/docs/backends/naszaklasa.rst +++ /dev/null @@ -1,26 +0,0 @@ -NationBuilder -============= - -`NaszaKlasa supports OAuth2`_ as their authentication mechanism. Follow these -steps in order to use it: - -- Register a new application at your `NK Developers`_ (define the `Callback - URL` to ``http://example.com/complete/nk/`` where ``example.com`` - is your domain). - -- Fill the ``Client ID`` and ``Client Secret`` values from the newly created - application:: - - SOCIAL_AUTH_NK_KEY = '' - SOCIAL_AUTH_NK_SECRET = '' - -- Enable the backend in ``AUTHENTICATION_BACKENDS`` setting:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.nk.NKOAuth2', - ... - ) - -.. _NaszaKlasa supports OAuth2: https://developers.nk.pl -.. _NK Developers: https://developers.nk.pl/developers/oauth2client/form \ No newline at end of file diff --git a/docs/backends/nationbuilder.rst b/docs/backends/nationbuilder.rst deleted file mode 100644 index a27c3eca2..000000000 --- a/docs/backends/nationbuilder.rst +++ /dev/null @@ -1,30 +0,0 @@ -NationBuilder -============= - -`NationBuilder supports OAuth2`_ as their authentication mechanism. Follow these -steps in order to use it: - -- Register a new application at your `Nation Admin panel`_ (define the `Callback - URL` to ``http://example.com/complete/nationbuilder/`` where ``example.com`` - is your domain). - -- Fill the ``Client ID`` and ``Client Secret`` values from the newly created - application:: - - SOCIAL_AUTH_NATIONBUILDER_KEY = '' - SOCIAL_AUTH_NATIONBUILDER_SECRET = '' - -- Also define your NationBuilder slug:: - - SOCIAL_AUTH_NATIONBUILDER_SLUG = 'your-nationbuilder-slug' - -- Enable the backend in ``AUTHENTICATION_BACKENDS`` setting:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.nationbuilder.NationBuilderOAuth2' - ... - ) - -.. _Nation Admin panel: https://psa.nationbuilder.com/admin/apps -.. _NationBuilder supports OAuth2: http://nationbuilder.com/api_quickstart diff --git a/docs/backends/naver.rst b/docs/backends/naver.rst deleted file mode 100644 index 60d21d40f..000000000 --- a/docs/backends/naver.rst +++ /dev/null @@ -1,27 +0,0 @@ -Naver -===== - -Naver uses OAuth v2 for Authentication. - -- Register a new application at the `Naver API`_, and - -- add naver oauth backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.naver.NaverOAuth2', - ... - ) - -- fill ``Client ID`` and ``Client Secret`` from developer.naver.com - values in the settings:: - - SOCIAL_AUTH_NAVER_KEY = '' - SOCIAL_AUTH_NAVER_SECRET = '' - -- you can get EXTRA_DATA:: - - SOCIAL_AUTH_NAVER_EXTRA_DATA = ['nickname', 'gender', 'age', - 'birthday', 'profile_image'] - -.. _Naver API: https://nid.naver.com/devcenter/docs.nhn?menu=API diff --git a/docs/backends/ngpvan_actionid.rst b/docs/backends/ngpvan_actionid.rst deleted file mode 100644 index cc980a70d..000000000 --- a/docs/backends/ngpvan_actionid.rst +++ /dev/null @@ -1,36 +0,0 @@ -NGP VAN ActionID -================ - -`NGP VAN`_'s ActionID_ service provides an OpenID 1.1 endpoint, which provides -first name, last name, email address, and phone number. - -ActionID doesn't require major settings beside being defined on -``AUTHENTICATION_BACKENDS`` - -.. code-block:: python - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.ngpvan.ActionIDOpenID', - ... - ) - - -If you want to be able to access the "phone" attribute offered by NGP VAN -within ``extra_data`` you can add the following to your settings: - -.. code-block:: python - - SOCIAL_AUTH_ACTIONID_OPENID_AX_EXTRA_DATA = [ - ('http://openid.net/schema/contact/phone/business', 'phone') - ] - - -NGP VAN offers the ability to have your domain whitelisted, which will disable -the "{domain} is requesting a link to your ActionID" warning when your app -attempts to login using an ActionID account. Contact -`NGP VAN Developer Support`_ for more information - -.. _NGP VAN: http://www.ngpvan.com/ -.. _ActionID: http://developers.ngpvan.com/action-id -.. _NGP VAN Developer Support: http://developers.ngpvan.com/support/contact diff --git a/docs/backends/oauth.rst b/docs/backends/oauth.rst deleted file mode 100644 index 44b1137f4..000000000 --- a/docs/backends/oauth.rst +++ /dev/null @@ -1,31 +0,0 @@ -OAuth -===== - -OAuth_ communication demands a set of keys exchange to validate the client -authenticity prior to user approbation. Twitter, and Facebook facilitates -these keys by application registration, Google works the same, -but provides the option for unregistered applications. - -Check next sections for details. - -OAuth_ backends also can store extra data in ``UserSocialAuth.extra_data`` -field by defining a set of values names to retrieve from service response. - -Settings is per backend and its name is dynamically checked using uppercase -backend name as prefix:: - - SOCIAL_AUTH__EXTRA_DATA - -Example:: - - SOCIAL_AUTH_FACEBOOK_EXTRA_DATA = [(..., ...)] - -Settings must be a list of tuples mapping value name in response and value -alias used to store. A third value (boolean) is supported, its purpose is -to signal if the value should be discarded if it evaluates to ``False``, this -is to avoid replacing old (needed) values when they don't form part of current -response. If not present, then this check is avoided and the value will replace -any data. - - -.. _OAuth: http://oauth.net/ diff --git a/docs/backends/odnoklassnikiru.rst b/docs/backends/odnoklassnikiru.rst deleted file mode 100644 index 772997566..000000000 --- a/docs/backends/odnoklassnikiru.rst +++ /dev/null @@ -1,56 +0,0 @@ -Odnoklassniki.ru -================ - -There are two options with Odnoklassniki: either you use OAuth2 workflow to -authenticate odnoklassniki users at external site, or you authenticate users -within your IFrame application. - -OAuth2 ------- - -If you use OAuth2 workflow, you need to: - -- register a new application with `OAuth registration form`_ - -- fill out some settings:: - - SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_KEY = '' - SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_SECRET = '' - SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_PUBLIC_NAME = '' - -- add ``'social.backends.odnoklassniki.OdnoklassnikiOAuth2'`` into your - ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``. - - -IFrame applications -------------------- - -If you want to authenticate users in your IFrame application, - -- read `Rules for application developers`_ - -- fill out `Developers registration form`_ - -- get your personal sandbox - -- fill out some settings:: - - SOCIAL_AUTH_ODNOKLASSNIKI_APP_KEY = '' - SOCIAL_AUTH_ODNOKLASSNIKI_APP_SECRET = '' - SOCIAL_AUTH_ODNOKLASSNIKI_APP_PUBLIC_NAME = '' - -- add ``'social.backends.odnoklassniki.OdnoklassnikiApp'`` into your - ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS`` - -- sign a public offer and do some bureaucracy - -You may also use:: - - SOCIAL_AUTH_ODNOKLASSNIKI_APP_EXTRA_USER_DATA_LIST - -Defaults to empty tuple, for the list of available fields see `Documentation on user.getInfo`_ - -.. _OAuth registration form: https://apiok.ru/wiki/pages/viewpage.action?pageId=42476652 -.. _Rules for application developers: https://apiok.ru/wiki/display/ok/Odnoklassniki.ru+Third+Party+Platform -.. _Developers registration form: https://apiok.ru/wiki/pages/viewpage.action?pageId=5668937 -.. _Documentation on user.getInfo: https://apiok.ru/wiki/display/ok/REST+API+-+users.getInfo diff --git a/docs/backends/openid.rst b/docs/backends/openid.rst deleted file mode 100644 index 0ac806188..000000000 --- a/docs/backends/openid.rst +++ /dev/null @@ -1,46 +0,0 @@ -OpenId -====== - -OpenId_ support is simpler to implement than OAuth_. Google and Yahoo -providers are supported by default, others are supported by POST method -providing endpoint URL. - -OpenId_ backends can store extra data in ``UserSocialAuth.extra_data`` field -by defining a set of values names to retrieve from any of the used schemas, -AttributeExchange and SimpleRegistration. As their keywords differ we need -two settings. - -Settings is per backend, so we have two possible values for each one. Name -is dynamically checked using uppercase backend name as prefix:: - - SOCIAL_AUTH__SREG_EXTRA_DATA - SOCIAL_AUTH__AX_EXTRA_DATA - -Example:: - - SOCIAL_AUTH_GOOGLE_SREG_EXTRA_DATA = [(..., ...)] - SOCIAL_AUTH_GOOGLE_AX_EXTRA_DATA = [(..., ...)] - -Settings must be a list of tuples mapping value name in response and value -alias used to store. A third value (boolean) is supported to, it's purpose is -to signal if the value should be discarded if it evaluates to ``False``, this -is to avoid replacing old (needed) values when they don't form part of current -response. If not present, then this check is avoided and the value will replace -any data. - -Username --------- - -The OpenId_ backend will check for a ``username`` key in the values returned by -the server, but default to ``first-name`` + ``last-name`` if that key is -missing. It's possible to indicate the username key in the values If the -username is under a different key with a setting, but backends should have -defined a default value. For example:: - - SOCIAL_AUTH_FEDORA_USERNAME_KEY = 'nickname' - -This setting indicates that the username should be populated by the -``nickname`` value in the Fedora OpenId_ provider. - -.. _OpenId: http://openid.net/ -.. _OAuth: http://oauth.net/ diff --git a/docs/backends/openstreetmap.rst b/docs/backends/openstreetmap.rst deleted file mode 100644 index b837d8d29..000000000 --- a/docs/backends/openstreetmap.rst +++ /dev/null @@ -1,21 +0,0 @@ -OpenStreetMap -============= - -OpenStreetMap supports OAuth 1.0 and 1.0a but 1.0a should be used for the new -applications, as 1.0 is for support of legacy clients only. - -Access tokens currently do not expire automatically. - -More documentation at `OpenStreetMap Wiki`_: - -- Login to your account - -- Register your application as OAuth consumer on your `OpenStreetMap user settings page`_, and - -- Set ``App Key`` and ``App Secret`` values in the settings:: - - SOCIAL_AUTH_OPENSTREETMAP_KEY = '' - SOCIAL_AUTH_OPENSTREETMAP_SECRET = '' - -.. _OpenStreetMap Wiki: http://wiki.openstreetmap.org/wiki/OAuth -.. _OpenStreetMap user settings page: http://www.openstreetmap.org/user/username/oauth_clients/new diff --git a/docs/backends/orbi.rst b/docs/backends/orbi.rst deleted file mode 100644 index 0cc0a7904..000000000 --- a/docs/backends/orbi.rst +++ /dev/null @@ -1,17 +0,0 @@ -Orbi -==== - -Orbi OAuth v2 for Authentication. - -- Register a new applicationat the `Orbi API`_, and - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_ORBI_KEY = '' - SOCIAL_AUTH_ORBI_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_KAKAO_SCOPE = ['all'] - -.. _Orbi API: http://orbi.kr diff --git a/docs/backends/persona.rst b/docs/backends/persona.rst deleted file mode 100644 index 0bfd74bce..000000000 --- a/docs/backends/persona.rst +++ /dev/null @@ -1,43 +0,0 @@ -Mozilla Persona -=============== - -Support for `Mozilla Persona`_ is possible by posting the ``assertion`` code to -``/complete/persona/`` URL. - -The setup doesn't need any setting, just the usual `Mozilla Persona`_ -javascript include in your document and the needed mechanism to trigger the -POST to `python-social-auth`_:: - - - - - -
- - Mozilla Persona -
- - - - -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _Mozilla Persona: http://www.mozilla.org/persona/ diff --git a/docs/backends/pinterest.rst b/docs/backends/pinterest.rst deleted file mode 100644 index 7c18ab004..000000000 --- a/docs/backends/pinterest.rst +++ /dev/null @@ -1,29 +0,0 @@ -Pinterest -========= - -Pinterest implemented OAuth2 protocol for their authentication mechanism. -To enable ``python-social-auth`` support follow this steps: - -1. Go to `Pinterest developers zone`_ and create an application. - -2. Fill App Id and Secret in your project settings:: - - SOCIAL_AUTH_PINTEREST_KEY = '...' - SOCIAL_AUTH_PINTEREST_SECRET = '...' - SOCIAL_AUTH_PINTEREST_SCOPE = [ - 'read_public', - 'write_public', - 'read_relationships', - 'write_relationships' - ] - -3. Enable the backend:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.pinterest.PinterestOAuth2', - ... - ) - -.. _Pinterest developers zone: https://developers.pinterest.com/apps/ -.. _Pinterest Documentation: https://developers.pinterest.com/docs/ diff --git a/docs/backends/pixelpin.rst b/docs/backends/pixelpin.rst deleted file mode 100644 index 8f1ebaf4a..000000000 --- a/docs/backends/pixelpin.rst +++ /dev/null @@ -1,33 +0,0 @@ -PixelPin -======== - -PixelPin only supports OAuth2. - -PixelPin OAuth2 ---------------- - -Developer documentation for PixelPin can be found at -http://developer.pixelpin.co.uk/. To setup OAuth2 do the following: - -- Register a new developer account at `PixelPin Developers`_. - - You require a PixelPin account to create developer accounts. Sign up at - `PixelPin Account Page`_ For the value of redirect uri, use whatever path you - need to return to on your web application. The example code provided with the - plugin uses ``http:///complete/pixelpin-oauth2/``. - - Once verified by email, record the values of client id and secret for the - next step. - -- Fill **Consumer Key** and **Consumer Secret** values in your settings.py - file:: - - SOCIAL_AUTH_PIXELPIN_OAUTH2_KEY = '' - SOCIAL_AUTH_PIXELPIN_OAUTH2_SECRET = '' - -- Add ``'social.backends.pixelpin.PixelPinOAuth2'`` into your - ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``. - -.. _PixelPin homepage: http://pixelpin.co.uk/ -.. _PixelPin Account Page: https://login.pixelpin.co.uk/ -.. _PixelPin Developers: http://developer.pixelpin.co.uk/ diff --git a/docs/backends/pocket.rst b/docs/backends/pocket.rst deleted file mode 100644 index e70708560..000000000 --- a/docs/backends/pocket.rst +++ /dev/null @@ -1,12 +0,0 @@ -Pocket -====== - -Pocket uses a weird variant of OAuth v2 that only defines a consumer key. - -- Register a new application at the `Pocket API`_, and - -- fill ``consumer key`` value in the settings:: - - SOCIAL_AUTH_POCKET_KEY = '' - -.. _Pocket API: http://getpocket.com/developer/ diff --git a/docs/backends/podio.rst b/docs/backends/podio.rst deleted file mode 100644 index 3f92e5e79..000000000 --- a/docs/backends/podio.rst +++ /dev/null @@ -1,13 +0,0 @@ -Podio -===== - -Podio offers OAuth2 as their auth mechanism. In order to enable it, follow: - -- Register a new application at `Podio API Keys`_ - -- Fill **Client Id** and **Client Secret** values:: - - SOCIAL_AUTH_PODIO_KEY = '' - SOCIAL_AUTH_PODIO_SECRET = '' - -.. _Podio API Keys: https://developers.podio.com/api-key diff --git a/docs/backends/qiita.rst b/docs/backends/qiita.rst deleted file mode 100644 index 512ca9d9f..000000000 --- a/docs/backends/qiita.rst +++ /dev/null @@ -1,23 +0,0 @@ -Qiita -===== - -Qiita - -- Register a new application at Qiita_, set the callback URL to - ``http://example.com/complete/qiita/`` replacing ``example.com`` with your - domain. - -- Fill ``Client ID`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_QIITA_KEY = '' - SOCIAL_AUTH_QIITA_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_QIITA_SCOPE = [...] - - See auth scopes at `Qiita Scopes docs`_. - - -.. _Qiita: https://qiita.com/settings/applications -.. _Qiita Scopes docs: https://qiita.com/api/v2/docs#スコープ diff --git a/docs/backends/qq.rst b/docs/backends/qq.rst deleted file mode 100644 index f0c1ef64a..000000000 --- a/docs/backends/qq.rst +++ /dev/null @@ -1,32 +0,0 @@ -QQ -== - -QQ implemented OAuth2 protocol for their authentication mechanism. To enable -``python-social-auth`` support follow this steps: - -1. Go to `QQ`_ and create an application. - -2. Fill App Id and Secret in your project settings:: - - SOCIAL_AUTH_QQ_KEY = '...' - SOCIAL_AUTH_QQ_SECRET = '...' - -3. Enable the backend:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.qq.QQOauth2', - ... - ) - - -The values for ``nickname``, ``figureurl_qq_1`` and ``gender`` will be stored -in the ``extra_data`` field. The ``nickname`` will be used as the account -username. ``figureurl_qq_1`` can be used as the profile image. - -Sometimes nickname will duplicate with another ``qq`` account, to avoid this -issue it's possible to use ``openid`` as ``username`` by define this setting:: - - SOCIAL_AUTH_QQ_USE_OPENID_AS_USERNAME = True - -.. _QQ: http://connect.qq.com/ diff --git a/docs/backends/rdio.rst b/docs/backends/rdio.rst deleted file mode 100644 index fb8437cb1..000000000 --- a/docs/backends/rdio.rst +++ /dev/null @@ -1,46 +0,0 @@ -Rdio -==== - -Rdio provides OAuth 1 and 2 support for their authentication process. - -OAuth 1.0a ----------- - -To setup Rdio OAuth 1.0a, add the following to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.rdio.RdioOAuth1', - ... - ) - - SOCIAL_AUTH_RDIO_OAUTH1_KEY = '' - SOCIAL_AUTH_RDIO_OAUTH1_SECRET = '' - - -OAuth 2.0 ---------- - -To setup Rdio OAuth 2.0, add the following to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.rdio.RdioOAuth2', - ... - ) - - SOCIAL_AUTH_RDIO_OAUTH2_KEY = os.environ['RDIO_OAUTH2_KEY'] - SOCIAL_AUTH_RDIO_OAUTH2_SECRET = os.environ['RDIO_OAUTH2_SECRET'] - SOCIAL_AUTH_RDIO_OAUTH2_SCOPE = [] - - -Extra Fields ------------- - -The following extra fields are automatically requested: - -- rdio_id -- rdio_icon_url -- rdio_profile_url -- rdio_username -- rdio_stream_region diff --git a/docs/backends/readability.rst b/docs/backends/readability.rst deleted file mode 100644 index bb98b0a89..000000000 --- a/docs/backends/readability.rst +++ /dev/null @@ -1,24 +0,0 @@ -Readability -=========== - -Readability works similarly to Twitter, in that you'll need a ``Consumer Key`` -and ``Consumer Secret``. These can be obtained in the ``Connections`` section -of your ``Account`` page. - -- Fill the **Consumer Key** and **Consumer Secret** values in your settings:: - - SOCIAL_AUTH_READABILITY_KEY = '' - SOCIAL_AUTH_READABILITY_SECRET = '' - -That's it! By default you'll get back:: - - username - first_name - last_name - -with EXTRA_DATA, you can get:: - - date_joined - kindle_email_address - avatar_url - email_into_address diff --git a/docs/backends/reddit.rst b/docs/backends/reddit.rst deleted file mode 100644 index 6f15242e8..000000000 --- a/docs/backends/reddit.rst +++ /dev/null @@ -1,33 +0,0 @@ -Reddit -====== - -Reddit implements `OAuth2 authentication workflow`_. To enable it, just follow: - -- Register an application at `Reddit Preferences Apps`_ - -- Fill the **Consumer Key** and **Consumer Secret** values in your settings:: - - SOCIAL_AUTH_REDDIT_KEY = '' - SOCIAL_AUTH_REDDIT_SECRET = '' - -- By default the token is not permanent, it will last an hour. To get - a refresh token just define:: - - SOCIAL_AUTH_REDDIT_AUTH_EXTRA_ARGUMENTS = {'duration': 'permanent'} - - This will store the ``refresh_token`` in ``UserSocialAuth.extra_data`` - attribute, to refresh the access token just do:: - - from social.apps.django_app.utils import load_strategy - - strategy = load_strategy(backend='reddit') - user = User.objects.get(pk=foo) - social = user.social_auth.filter(provider='reddit')[0] - social.refresh_token(strategy=strategy, - redirect_uri='http://localhost:8000/complete/reddit/') - - Reddit requires ``redirect_uri`` when refreshing the token and it must be the - same value used during the auth process. - -.. _Reddit Preferences Apps: https://ssl.reddit.com/prefs/apps/ -.. _OAuth2 authentication workflow: https://github.com/reddit/reddit/wiki/OAuth2 diff --git a/docs/backends/runkeeper.rst b/docs/backends/runkeeper.rst deleted file mode 100644 index 9c35a3859..000000000 --- a/docs/backends/runkeeper.rst +++ /dev/null @@ -1,13 +0,0 @@ -RunKeeper -========= - -RunKeeper uses OAuth v2 for authentication. - -- Register a new application at the `RunKeeper API`_, and - -- fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_RUNKEEPER_KEY = '' - SOCIAL_AUTH_RUNKEEPER_SECRET = '' - -.. _RunKeeper API: http://developer.runkeeper.com/healthgraph diff --git a/docs/backends/salesforce.rst b/docs/backends/salesforce.rst deleted file mode 100644 index 9b440a327..000000000 --- a/docs/backends/salesforce.rst +++ /dev/null @@ -1,44 +0,0 @@ -Salesforce -========== - -Salesforce uses OAuth v2 for Authentication, check the `official docs`_. - -- Create an app following the steps in the `Defining Connected Apps`_ docs. - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_SALESFORCE_OAUTH2_KEY = '' - SOCIAL_AUTH_SALESFORCE_OAUTH2_SECRET = '' - -- Add the backend to the ``AUTHENTICATION_BACKENDS`` setting:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.salesforce.SalesforceOAuth2', - ... - ) - -- Then you can start using ``{% url social:begin 'salesforce-oauth2' %}`` in - your templates - - -If using the sandbox mode: - -- Fill these settings instead:: - - SOCIAL_AUTH_SALESFORCE_OAUTH2_SANDBOX_KEY = '' - SOCIAL_AUTH_SALESFORCE_OAUTH2_SANDBOX_SECRET = '' - -- And this backend:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.salesforce.SalesforceOAuth2Sandbox', - ... - ) - -- Then you can start using ``{% url social:begin 'salesforce-oauth2-sandbox' %}`` - in your templates - -.. _official docs: https://www.salesforce.com/us/developer/docs/api_rest/Content/intro_understanding_web_server_oauth_flow.htm -.. _Defining Connected Apps: https://www.salesforce.com/us/developer/docs/api_rest/Content/intro_defining_remote_access_applications.htm diff --git a/docs/backends/saml.rst b/docs/backends/saml.rst deleted file mode 100644 index e4de6eb5e..000000000 --- a/docs/backends/saml.rst +++ /dev/null @@ -1,169 +0,0 @@ -SAML -==== - -The SAML backend allows users to authenticate with any provider that supports -the SAML 2.0 protocol (commonly used for corporate or academic single sign on). - -The SAML backend for python-social-auth allows your web app to act as a SAML -Service Provider. You can configure one or more SAML Identity Providers that -users can use for authentication. For example, if your users are students, you -could enable Harvard and MIT as identity providers, so that students of either -of those two universities can use their campus login to access your app. - -Required Dependency -------------------- - -You must install python-saml_ 2.1.3 or higher in order to use this backend. - -Required Configuration ----------------------- - -At a minimum, you must add the following to your project's settings: - -- ``SOCIAL_AUTH_SAML_SP_ENTITY_ID``: The SAML Entity ID for your app. This - should be a URL that includes a domain name you own. It doesn't matter what - the URL points to. Example: ``http://saml.yoursite.com`` - -- ``SOCIAL_AUTH_SAML_SP_PUBLIC_CERT``: The X.509 certificate string for the - key pair that your app will use. You can generate a new self-signed key pair - with:: - - openssl req -new -x509 -days 3652 -nodes -out saml.crt -keyout saml.key - - The contents of ``saml.crt`` should then be used as the value of this setting - (you can omit the first and last lines, which aren't required). - -- ``SOCIAL_AUTH_SAML_SP_PRIVATE_KEY``: The private key to be used by your app. - If you used the example openssl command given above, set this to the contents - of ``saml.key`` (again, you can omit the first and last lines). - -- ``SOCIAL_AUTH_SAML_ORG_INFO``: A dictionary that contains information about - your app. You must specify values for English at a minimum. Each language's - entry should specify a ``name`` (not shown to the user), a ``displayname`` - (shown to the user), and a URL. See the following - example:: - - { - "en-US": { - "name": "example", - "displayname": "Example Inc.", - "url": "http://example.com", - } - } - -- ``SOCIAL_AUTH_SAML_TECHNICAL_CONTACT``: A dictionary with two values, - ``givenName`` and ``emailAddress``, describing the name and email of a - technical contact responsible for your app. Example:: - - {"givenName": "Tech Gal", "emailAddress": "technical@example.com"} - -- ``SOCIAL_AUTH_SAML_TECHNICAL_CONTACT``: A dictionary with two values, - ``givenName`` and ``emailAddress``, describing the name and email of a - support contact for your app. Example:: - - SOCIAL_AUTH_SAML_SUPPORT_CONTACT = { - "givenName": "Support Guy", - "emailAddress": "support@example.com", - } - -- ``SOCIAL_AUTH_SAML_ENABLED_IDPS``: The most important setting. List the Entity - ID, SSO URL, and x.509 public key certificate for each provider that your app - wants to support. The SSO URL must support the ``HTTP-Redirect`` binding. - You can get these values from the provider's XML metadata. Here's an example, - for TestShib_ (the values come from TestShib's metadata_):: - - { - "testshib": { - "entity_id": "https://idp.testshib.org/idp/shibboleth", - "url": "https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO", - "x509cert": "MIIEDjCCAvagAwIBAgIBADA ... 8Bbnl+ev0peYzxFyF5sQA==", - } - } - -Basic Usage ------------ - -- Set all of the required configuration variables described above. - -- Generate the SAML XML metadata for your app. The best way to do this is to - create a new view/page/URL in your app that will call the backend's - ``generate_metadata_xml()`` method. Here's an example of how to do this in - Django:: - - def saml_metadata_view(request): - complete_url = reverse('social:complete', args=("saml", )) - saml_backend = load_backend( - load_strategy(request), - "saml", - redirect_uri=complete_url, - ) - metadata, errors = saml_backend.generate_metadata_xml() - if not errors: - return HttpResponse(content=metadata, content_type='text/xml') - -- Download the metadata for your app that was generated by the above method, - and send it to each Identity Provider (IdP) that you wish to use. Each IdP - must install and configure your metadata on their system before it will work. - -- Now everything is set! To allow users to login with any given IdP, you need to - give them a link to the python-social-auth "begin"/"auth" URL and include an - ``idp`` query parameter that specifies the name of the IdP to use. This is - needed since the backend supports multiple IdPs. The names of the IdPs are the - keys used in the ``SOCIAL_AUTH_SAML_ENABLED_IDPS`` setting. - - Django example:: - - # In view: - context['testshib_url'] = u"{base}?{params}".format( - base=reverse('social:begin', kwargs={'backend': 'saml'}), - params=urllib.urlencode({'next': '/home', 'idp': 'testshib'}) - ) - # In template: - TestShib Login - # Result: - TestShib Login - -- Testing with the TestShib_ provider is recommended, as it is known to work - well. - - -Advanced Settings ------------------ - -- ``SOCIAL_AUTH_SAML_SP_EXTRA``: This can be set to a dict, and any key/value - pairs specified here will be passed to the underlying ``python-saml`` library - configuration's ``sp`` setting. Refer to the ``python-saml`` documentation for - details. - -- ``SOCIAL_AUTH_SAML_SECURITY_CONFIG``: This can be set to a dict, and any - key/value pairs specified here will be passed to the underlying - ``python-saml`` library configuration's ``security`` setting. Two useful keys - that you can set are ``metadataCacheDuration`` and ``metadataValidUntil``, - which control the expiry time of your XML metadata. By default, a cache - duration of 10 days will be used, which means that IdPs are allowed to cache - your metadata for up to 10 days, but no longer. ``metadataCacheDuration`` must - be specified as an ISO 8601 duration string (e.g. `P1D` for one day). - - -Advanced Usage --------------- - -You can subclass the ``SAMLAuth`` backend to provide custom functionality. In -particular, there are two methods that are designed for subclasses to override: - -- ``get_idp(self, idp_name)``: Given the name of an IdP, return an instance of - ``SAMLIdentityProvider`` with the details of the IdP. Override this method if - you wish to use some other method for configuring the available identity - providers, such as fetching them at runtime from another server, or using a - list of providers from a Shibboleth federation. - -- ``_check_entitlements(self, idp, attributes)``: This method gets called during - the login process and is where you can decide to accept or reject a user based - on the user's SAML attributes. For example, you can restrict access to your - application to only accept users who belong to a certain department. After - inspecting the passed attributes parameter, do nothing to allow the user to - login, or raise ``social.exceptions.AuthForbidden`` to reject the user. - -.. _python-saml: https://github.com/onelogin/python-saml -.. _TestShib: https://www.testshib.org/ -.. _metadata: https://www.testshib.org/metadata/testshib-providers.xml diff --git a/docs/backends/shopify.rst b/docs/backends/shopify.rst deleted file mode 100644 index fec9f8aa4..000000000 --- a/docs/backends/shopify.rst +++ /dev/null @@ -1,29 +0,0 @@ -Shopify -======= - -Shopify uses OAuth 2 for authentication. - -To use this backend, you must install the package ``shopify`` from the `Github -project`_. Currently supports v2+ - -- Register a new application at `Shopify Partners`_, and - -- Set the Auth Type to OAuth2 in the application settings - -- Set the Application URL to http://[your domain]/login/shopify/ - -- fill ``API Key`` and ``Shared Secret`` values in your django settings:: - - SOCIAL_AUTH_SHOPIFY_KEY = '' - SOCIAL_AUTH_SHOPIFY_SECRET = '' - -- fill the scope permissions that you require into the settings `Shopify API`_:: - - SOCIAL_AUTH_SHOPIFY_SCOPE = ['write_script_tags', - 'read_orders', - 'write_customers', - 'read_products'] - -.. _Shopify Partners: http://www.shopify.com/partners -.. _Shopify API: http://api.shopify.com/authentication.html#scopes -.. _Github project: https://github.com/Shopify/shopify_python_api diff --git a/docs/backends/sketchfab.rst b/docs/backends/sketchfab.rst deleted file mode 100644 index c69a388e2..000000000 --- a/docs/backends/sketchfab.rst +++ /dev/null @@ -1,17 +0,0 @@ -Sketchfab -========= - -Sketchfab uses OAuth 2 for authentication. - -To use: - -- Follow the steps at `Sketchfab Oauth`_, and ask for an - ``Authorization code`` grant type. - -- Fill the ``Client id/key`` and ``Client Secret`` values you received - in your django settings:: - - SOCIAL_AUTH_SKETCHFAB_KEY = '' - SOCIAL_AUTH_SKETCHFAB_SECRET = '' - -.. _Sketchfab Oauth: https://sketchfab.com/developers/oauth diff --git a/docs/backends/skyrock.rst b/docs/backends/skyrock.rst deleted file mode 100644 index 7cd693e7c..000000000 --- a/docs/backends/skyrock.rst +++ /dev/null @@ -1,21 +0,0 @@ -Skyrock -======= - -OAuth based Skyrock Connect. - -Skyrock offers per application keys named ``Consumer Key`` and ``Consumer -Secret``. To enable Skyrock these two keys are needed. Further documentation -at `Skyrock developer resources`_: - -- Register a new application at `Skyrock App Creation`_, - -- Your callback domain should match your application URL in your application - configuration. - -- Fill **Consumer Key** and **Consumer Secret** values:: - - SOCIAL_AUTH_SKYROCK_KEY = '' - SOCIAL_AUTH_SKYROCK_SECRET = '' - -.. _Skyrock developer resources: http://www.skyrock.com/developer/ -.. _Skyrock App Creation: https://wwwskyrock.com/developer/application diff --git a/docs/backends/slack.rst b/docs/backends/slack.rst deleted file mode 100644 index ce3ed29aa..000000000 --- a/docs/backends/slack.rst +++ /dev/null @@ -1,23 +0,0 @@ -Slack -===== - -Slack - -- Register a new application at Slack_, set the callback URL to - ``http://example.com/complete/slack/`` replacing ``example.com`` with your - domain. - -- Fill ``Client ID`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_SLACK_KEY = '' - SOCIAL_AUTH_SLACK_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_SLACK_SCOPE = [...] - - See auth scopes at `Slack OAuth docs`_. - - -.. _Slack: https://api.slack.com/applications -.. _Slack OAuth docs: https://api.slack.com/docs/oauth diff --git a/docs/backends/soundcloud.rst b/docs/backends/soundcloud.rst deleted file mode 100644 index a58b33679..000000000 --- a/docs/backends/soundcloud.rst +++ /dev/null @@ -1,25 +0,0 @@ -SoundCloud -========== - -SoundCloud uses OAuth2 for its auth mechanism. - -- Register a new application at `SoundCloud App Registration`_, set your - application name, website and redirect URI. - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_SOUNDCLOUD_KEY = '' - SOCIAL_AUTH_SOUNDCLOUD_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_SOUNDCLOUD_SCOPE = [...] - -Possible scope values are `*` or `non-expiring` according to their `/connect -documentation`_. - -Check the rest of their doc at `SoundCloud Developer Documentation`_. - -.. _SoundCloud App Registration: http://soundcloud.com/you/apps/new -.. _SoundCloud Developer Documentation: http://developers.soundcloud.com/docs -.. _/connect documentation: http://developers.soundcloud.com/docs/api/reference#connect diff --git a/docs/backends/spotify.rst b/docs/backends/spotify.rst deleted file mode 100644 index ca3ddd1f6..000000000 --- a/docs/backends/spotify.rst +++ /dev/null @@ -1,25 +0,0 @@ -Spotify -======= - -Spotify supports OAuth 2. - -- Register a new application at `Spotify Web API`_, and follow the - instructions below. - -OAuth2 ------- - -Add the Spotify OAuth2 backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.spotify.SpotifyOAuth2', - ... - ) - -- Fill ``App Key`` and ``App Secret`` values in the settings:: - - SOCIAL_AUTH_SPOTIFY_KEY = '' - SOCIAL_AUTH_SPOTIFY_SECRET = '' - -.. _Spotify Web API: https://developer.spotify.com/spotify-web-api diff --git a/docs/backends/stackoverflow.rst b/docs/backends/stackoverflow.rst deleted file mode 100644 index 8c525b909..000000000 --- a/docs/backends/stackoverflow.rst +++ /dev/null @@ -1,19 +0,0 @@ -Stackoverflow -============= - -Stackoverflow uses OAuth 2.0 - -- "Register For An App Key" at the `Stack Exchange API`_ site. Set your OAuth - domain and application website settings. - -- Add the ``Client Id``, ``Client Secret`` and ``API Key`` values in settings:: - - SOCIAL_AUTH_STACKOVERFLOW_KEY = '' - SOCIAL_AUTH_STACKOVERFLOW_SECRET = '' - SOCIAL_AUTH_STACKOVERFLOW_API_KEY = '' - -- You can ask for extra permissions with:: - - SOCIAL_AUTH_STACKOVERFLOW_SCOPE = [...] - -.. _Stack Exchange API: https://api.stackexchange.com/ diff --git a/docs/backends/steam.rst b/docs/backends/steam.rst deleted file mode 100644 index de38c382c..000000000 --- a/docs/backends/steam.rst +++ /dev/null @@ -1,19 +0,0 @@ -Steam OpenId -============ - -Steam OpenId works quite straightforward, but to retrieve some user data (known -as ``player`` on Steam API) a Steam API Key is needed. - -Configurable settings: - -- Supply a Steam API Key from `Steam Dev`_:: - - SOCIAL_AUTH_STEAM_API_KEY = key - - -- To save ``player`` data provided by Steam into ``extra_data``:: - - SOCIAL_AUTH_STEAM_EXTRA_DATA = ['player'] - - -.. _Steam Dev: http://steamcommunity.com/dev/apikey diff --git a/docs/backends/stocktwits.rst b/docs/backends/stocktwits.rst deleted file mode 100644 index d0d668c8c..000000000 --- a/docs/backends/stocktwits.rst +++ /dev/null @@ -1,16 +0,0 @@ -StockTwits -========== - -StockTwits uses OAuth 2 for authentication. - -- Register a new application at https://stocktwits.com/developers/apps - -- Set the Website URL to http://[your domain]/ - -- fill ``Consumer Key`` and ``Consumer Secret`` values in your django settings:: - - SOCIAL_AUTH_STOCKTWITS_KEY = '' - SOCIAL_AUTH_STOCKTWITS_SECRET = '' - -.. _StockTwits authentication docs: http://stocktwits.com/developers/docs/authentication -.. _StockTwits API: http://stocktwits.com/developers/docs/api diff --git a/docs/backends/strava.rst b/docs/backends/strava.rst deleted file mode 100644 index a2086c980..000000000 --- a/docs/backends/strava.rst +++ /dev/null @@ -1,17 +0,0 @@ -Strava -========= - -Strava uses OAuth v2 for Authentication. - -- Register a new application at the `Strava API`_, and - -- fill ``Client ID`` and ``Client Secret`` from strava.com values in the settings:: - - SOCIAL_AUTH_STRAVA_KEY = '' - SOCIAL_AUTH_STRAVA_SECRET = '' - -- extra scopes can be defined by using:: - - SOCIAL_AUTH_STRAVA_SCOPE = ['view_private'] - -.. _Strava API: https://www.strava.com/settings/api diff --git a/docs/backends/stripe.rst b/docs/backends/stripe.rst deleted file mode 100644 index a74342c93..000000000 --- a/docs/backends/stripe.rst +++ /dev/null @@ -1,34 +0,0 @@ -Stripe -====== - -Stripe uses OAuth2 for its authorization service. To setup Stripe backend: - -- Register a new application at `Stripe App Creation`_, and - -- Grab the ``client_id`` value in ``Applications`` tab and fill the ``App Id`` - setting:: - - SOCIAL_AUTH_STRIPE_KEY = 'ca_...' - -- Grab the ``Test Secret Key`` in the ``API Keys`` tab and fille the ``App - Secret`` setting:: - - SOCIAL_AUTH_STRIPE_SECRET = '...' - -- Define ``SOCIAL_AUTH_STRIPE_SCOPE`` with the desired scope (options are - ``read_only`` and ``read_write``):: - - SOCIAL_AUTH_STRIPE_SCOPE = ['read_only'] - -- Add the needed backend to ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.stripe.StripeOAuth2', - ... - ) - -More info on Stripe OAuth2 at `Integrating OAuth`_. - -.. _Stripe App Creation: https://manage.stripe.com/#account/applications/settings -.. _Integrating OAuth: https://stripe.com/docs/connect/oauth diff --git a/docs/backends/suse.rst b/docs/backends/suse.rst deleted file mode 100644 index 239cc5fa9..000000000 --- a/docs/backends/suse.rst +++ /dev/null @@ -1,13 +0,0 @@ -SUSE -==== - -This section describes how to setup the different services provided by SUSE and openSUSE. - - -openSUSE OpenId ---------------- - -openSUSE OpenId works straightforward, not settings are needed. Domains or emails -whitelists can be applied too, check the whitelists_ settings for details. - -.. _whitelists: ../configuration/settings.html#whitelists diff --git a/docs/backends/taobao.rst b/docs/backends/taobao.rst deleted file mode 100644 index 9606ecf12..000000000 --- a/docs/backends/taobao.rst +++ /dev/null @@ -1,15 +0,0 @@ -Taobao OAuth -============ - -Taobao OAuth 2.0 workflow. - -- Register a new application at Open `Open Taobao`_. - -- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings:: - - SOCIAL_AUTH_TAOBAO_KEY = '' - SOCIAL_AUTH_TAOBAO_SECRET = '' - -By default ``token`` is stored in ``extra_data`` field. - -.. _Open Taobao: http://open.taobao.com diff --git a/docs/backends/thisismyjam.rst b/docs/backends/thisismyjam.rst deleted file mode 100644 index 02efa79c4..000000000 --- a/docs/backends/thisismyjam.rst +++ /dev/null @@ -1,17 +0,0 @@ -ThisIsMyJam -=========== - -ThisIsMyJam uses OAuth1 for its auth mechanism. - -- Register a new application at `ThisIsMyJam App Registration`_, set your - application name, website and redirect URI. - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_THISISMYJAM_KEY = '' - SOCIAL_AUTH_THISISMYJAM_SECRET = '' - -Check the rest of their doc at `ThisIsMyJam API Docs`_. - -.. _ThisIsMyJam App Registration: https://www.thisismyjam.com/developers -.. _ThisIsMyJam API Docs: https://www.thisismyjam.com/developers/docs diff --git a/docs/backends/trello.rst b/docs/backends/trello.rst deleted file mode 100644 index 4b55f9931..000000000 --- a/docs/backends/trello.rst +++ /dev/null @@ -1,26 +0,0 @@ -Trello -====== - -Trello provides OAuth1 support for their authentication process. - -In order to enable it, follow: - -- Generate an Application Key pair at `Trello Developers API Keys`_ - -- Fill **Consumer Key** and **Consumer Secret** settings:: - - SOCIAL_AUTH_TRELLO_KEY = '...' - SOCIAL_AUTH_TRELLO_SECRET = '...' - -There are also two optional settings: - -- your app name, otherwise the authorization page will say "Let An unknown application use your account?":: - - SOCIAL_AUTH_TRELLO_APP_NAME = 'My App' - -- the expiration period, social auth defaults to 'never', but you can change it:: - - SOCIAL_AUTH_TRELLO_EXPIRATION = '30days' - - -.. _Trello Developers API Keys: https://trello.com/1/appKey/generate diff --git a/docs/backends/tripit.rst b/docs/backends/tripit.rst deleted file mode 100644 index acc5cd64c..000000000 --- a/docs/backends/tripit.rst +++ /dev/null @@ -1,16 +0,0 @@ -TripIt -====== - -TripIt offers per application keys named ``API Key`` and ``API Secret``. -To enable TripIt these two keys are needed. Further documentation at -`TripIt Developer Center`_: - -- Register a new application at `TripIt App Registration`_, - -- fill **API Key** and **API Secret** values:: - - SOCIAL_AUTH_TRIPIT_KEY = '' - SOCIAL_AUTH_TRIPIT_SECRET = '' - -.. _TripIt Developer Center: https://www.tripit.com/developer -.. _TripIt App Registration: https://www.tripit.com/developer/create diff --git a/docs/backends/tumblr.rst b/docs/backends/tumblr.rst deleted file mode 100644 index 90c1aa046..000000000 --- a/docs/backends/tumblr.rst +++ /dev/null @@ -1,16 +0,0 @@ -Tumblr -====== - -Tumblr uses OAuth 1.0a for authentication. - -- Register a new application at http://www.tumblr.com/oauth/apps - -- Set the ``Default callback URL`` to http://[your domain]/ - -- fill ``OAuth Consumer Key`` and ``Secret Key`` values in your Django - settings:: - - SOCIAL_AUTH_TUMBLR_KEY = '' - SOCIAL_AUTH_TUMBLR_SECRET = '' - -.. _Tumblr API: http://www.tumblr.com/docs/en/api/v2 diff --git a/docs/backends/twilio.rst b/docs/backends/twilio.rst deleted file mode 100644 index 8f118dbb7..000000000 --- a/docs/backends/twilio.rst +++ /dev/null @@ -1,22 +0,0 @@ -Twilio -====== - -- Register a new application at `Twilio Connect Api`_ - -- Fill ``SOCIAL_AUTH_TWILIO_KEY`` and ``SOCIAL_AUTH_TWILIO_SECRET`` values in - the settings:: - - SOCIAL_AUTH_TWILIO_KEY = '' - SOCIAL_AUTH_TWILIO_SECRET = '' - -- Add desired authentication backends to Django's ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS`` - setting:: - - 'social.backends.twilio.TwilioAuth', - -- Usage example:: - - Enter using Twilio - - -.. _Twilio Connect API: https://www.twilio.com/user/account/connect/apps diff --git a/docs/backends/twitch.rst b/docs/backends/twitch.rst deleted file mode 100644 index bb99a9e2c..000000000 --- a/docs/backends/twitch.rst +++ /dev/null @@ -1,19 +0,0 @@ -Twitch -====== - -Twitch works similar to Facebook (OAuth). - -- Register a new application in the `connections tab`_ of your Twitch settings - page, set the callback URL to ``http://example.com/complete/twitch/`` - replacing ``example.com`` with your domain. - -- Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_TWITCH_KEY = '' - SOCIAL_AUTH_TWITCH_SECRET = '' - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_TWITCH_SCOPE = [...] - -.. _connections tab: http://www.twitch.tv/settings/connections diff --git a/docs/backends/twitter.rst b/docs/backends/twitter.rst deleted file mode 100644 index 64e885c1a..000000000 --- a/docs/backends/twitter.rst +++ /dev/null @@ -1,34 +0,0 @@ -Twitter -======= - -Twitter offers per application keys named ``Consumer Key`` and ``Consumer Secret``. -To enable Twitter these two keys are needed. Further documentation at -`Twitter development resources`_: - -- Register a new application at `Twitter App Creation`_, - -- Check the **Allow this application to be used to Sign in with Twitter** - checkbox. If you don't check this box, Twitter will force your user to login - every time. - -- Fill **Consumer Key** and **Consumer Secret** values:: - - SOCIAL_AUTH_TWITTER_KEY = '' - SOCIAL_AUTH_TWITTER_SECRET = '' - -- You need to specify an URL callback or the application will be marked as - Client type instead of the Browser. Almost any dummy value will work if - you plan some test. - -- You can request user's Email address (consult `Twitter verify - credentials`_), the parameter is sent automatically, but the - applicaton needs to be whitelisted in order to get a valid value. - -Twitter usually fails with a 401 error when trying to call the request-token -URL, this is usually caused by server datetime errors (check miscellaneous -section). Installing ``ntp`` and syncing the server date with some pool does -the trick. - -.. _Twitter development resources: http://dev.twitter.com/pages/auth -.. _Twitter App Creation: http://twitter.com/apps/new -.. _Twitter verify credentials: https://dev.twitter.com/rest/reference/get/account/verify_credentials diff --git a/docs/backends/uber.rst b/docs/backends/uber.rst deleted file mode 100644 index 7aca7b97e..000000000 --- a/docs/backends/uber.rst +++ /dev/null @@ -1,28 +0,0 @@ -Uber -========= - -Uber uses OAuth v2 for Authentication. - -- Register a new application at the `Uber API`_, and follow the instructions below - -OAuth2 -========= - -1. Add the Uber OAuth2 backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.uber.UberOAuth2', - ... - ) - -2. Fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_UBER_KEY = '' - SOCIAL_AUTH_UBER_SECRET = '' - -3. Scope should be defined by using:: - - SOCIAL_AUTH_UBER_SCOPE = ['profile', 'request'] - -.. _Uber API: https://developer.uber.com/dashboard diff --git a/docs/backends/untappd.rst b/docs/backends/untappd.rst deleted file mode 100644 index 0b41a1273..000000000 --- a/docs/backends/untappd.rst +++ /dev/null @@ -1,28 +0,0 @@ -Untappd -======= - -Untappd uses OAuth v2 for Authentication, check the `official docs`_. - -- Create an app by filling out the form here: `Add App`_ - -- Apps are approved on a one-by-one basis, so you'll need to wait a - few days to get your client ID and secret. - -- Fill ``Client ID`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_UNTAPPD_KEY = '' - SOCIAL_AUTH_UNTAPPD_SECRET = '' - -- Add the backend to the ``AUTHENTICATION_BACKENDS`` setting:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.untappd.UntappdOAuth2', - ... - ) - -- Then you can start using ``{% url social:begin 'untappd' %}`` in - your templates - -.. _official docs: https://untappd.com/api/docs -.. _Add App: https://untappd.com/api/register?register=new diff --git a/docs/backends/upwork.rst b/docs/backends/upwork.rst deleted file mode 100644 index 59b599096..000000000 --- a/docs/backends/upwork.rst +++ /dev/null @@ -1,28 +0,0 @@ -Upwork -====== - -Upwork supports only OAuth 1. - -- Register a new application at `Upwork Developers`_. - -OAuth1 ------- - -Add the Upwork OAuth backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.upwork.UpworkOAuth', - ... - ) - -- Fill ``App Key`` and ``App Secret`` values in the settings:: - - SOCIAL_AUTH_UPWORK_KEY = '' - SOCIAL_AUTH_UPWORK_SECRET = '' - - -**Note:** For more information please go to `Upwork API Reference`_. - -.. _Upwork Developers: https://www.upwork.com/services/api/apply -.. _Upwork API Reference: https://developers.upwork.com/?lang=python diff --git a/docs/backends/username.rst b/docs/backends/username.rst deleted file mode 100644 index dcd45ef2c..000000000 --- a/docs/backends/username.rst +++ /dev/null @@ -1,52 +0,0 @@ -Username Auth -============= - -python-social-auth_ comes with an UsernameAuth_ backend which comes handy when -your site uses requires the plain old username and password authentication -mechanism. - -Actually that's a lie since the backend doesn't handle password at all, that's -up to the developer to validate the password in and the proper place to do it -is the pipeline, right after the user instance was retrieved or created. - -The reason to leave password handling to the developer is because too many -things are really tied to the project, like the field where the password is -stored, salt handling, password hashing algorithm and validation. So just add -the pipeline functions that will do that following the needs of your project. - - -Backend settings ----------------- - -``SOCIAL_AUTH_USERNAME_FORM_URL = '/login-form/'`` - Used to redirect the user to the login/signup form, it must have at least - one field named ``username``. Form submit should go to ``/complete/username``, - or if it goes to your view, then your view should complete the process - calling ``social.actions.do_complete``. - -``SOCIAL_AUTH_USERNAME_FORM_HTML = 'login_form.html'`` - The template will be used to render the login/signup form to the user, it - must have at least one field named ``username``. Form submit should go to - ``/complete/username``, or if it goes to your view, then your view should - complete the process calling ``social.actions.do_complete``. - - -Password handling ------------------ - -Here's an example of password handling to add to the pipeline:: - - def user_password(strategy, user, is_new=False, *args, **kwargs): - if strategy.backend.name != 'username': - return - - password = strategy.request_data()['password'] - if is_new: - user.set_password(password) - user.save() - elif not user.validate_password(password): - # return {'user': None, 'social': None} - raise AuthException(strategy.backend) - -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _UsernameAuth: https://github.com/omab/python-social-auth/blob/master/social/backends/username.py#L5 diff --git a/docs/backends/vend.rst b/docs/backends/vend.rst deleted file mode 100644 index 880698e59..000000000 --- a/docs/backends/vend.rst +++ /dev/null @@ -1,24 +0,0 @@ -Vend -==== - -Vend supports OAuth 2. - -- Register a new application at `Vend Developers Portal`_ - -- Add the Vend OAuth2 backend to your settings page:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.vend.VendOAuth2', - ... - ) - -- Fill ``App Key`` and ``App Secret`` values in the settings:: - - SOCIAL_AUTH_VEND_OAUTH2_KEY = '' - SOCIAL_AUTH_VEND_OAUTH2_SECRET = '' - -More details on their docs_. - -.. _Vend Developers Portal: https://developers.vendhq.com/developer/applications -.. _docs: https://developers.vendhq.com/documentation diff --git a/docs/backends/vimeo.rst b/docs/backends/vimeo.rst deleted file mode 100644 index b2e4bd089..000000000 --- a/docs/backends/vimeo.rst +++ /dev/null @@ -1,28 +0,0 @@ -Vimeo -===== - -Vimeo uses OAuth1 to grant access to their API. In order to get the backend -running follow: - -- Register an application at `Vimeo Developer Portal`_ filling the required - settings. Ensure to fill ``App Callback URL`` field with - ``http:///complete/vimeo/`` - -- Fill in the **Client Id** and **Client Secret** values in your settings:: - - SOCIAL_AUTH_VIMEO_KEY = '' - SOCIAL_AUTH_VIMEO_SECRET = '' - -- Specify scopes with:: - - SOCIAL_AUTH_VIMEO_SCOPE = [...] - -- Add the backend to ``AUTHENTICATION_BACKENDS``:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.vimeo.VimeoOAuth1', - ... - ) - -.. _Vimeo Developer Portal: https://developer.vimeo.com/apps/new diff --git a/docs/backends/vk.rst b/docs/backends/vk.rst deleted file mode 100644 index a9195c76b..000000000 --- a/docs/backends/vk.rst +++ /dev/null @@ -1,131 +0,0 @@ -VK.com (former Vkontakte) -========================= - -VK.com (former Vkontakte) auth service support. - -OAuth2 ------- - -VK.com uses OAuth2 for Authentication. - -- Register a new application at the `VK.com API`_, - -- fill ``Application Id`` and ``Application Secret`` values in the settings:: - - SOCIAL_AUTH_VK_OAUTH2_KEY = '' - SOCIAL_AUTH_VK_OAUTH2_SECRET = '' - -- Add ``'social.backends.vk.VKOAuth2'`` into your ``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``. - -- Then you can start using ``/login/vk-oauth2`` in your link href. - -- Also it's possible to define extra permissions with:: - - SOCIAL_AUTH_VK_OAUTH2_SCOPE = [...] - - See the `VK.com list of permissions`_. - - -OAuth2 Application ------------------- - -To support OAuth2 authentication for VK.com applications: - -- Create your IFrame application at VK.com. - -- In application settings specify your IFrame URL ``mysite.com/vk`` (current - default). - -- Fill ``Application ID`` and ``Application Secret`` settings:: - - SOCIAL_AUTH_VK_APP_KEY = '' - SOCIAL_AUTH_VK_APP_SECRET = '' - -- Fill ``user_mode``:: - - SOCIAL_AUTH_VK_APP_USER_MODE = 2 - - Possible values: - - ``0``: there will be no check whether a user connected to your - application or not - - ``1``: ``python-social-auth`` will check ``is_app_user`` parameter - VK.com sends when user opens application page one time - - ``2``: (safest) ``python-social-auth`` will check status of user - interactively (useful when you have interactive authentication via AJAX) - -- Add a snippet similar to this into your login template:: - - - - Click to authenticate - -To test, launch the server using ``sudo ./manage.py mysite.com:80`` for -browser to be able to load it when VK.com calls IFrame URL. Open your -VK.com application page via http://vk.com/app. Now you are able to -connect to application and login automatically after connection when visiting -application page. - -For more details see `authentication for VK.com applications`_ - - -OpenAPI -------- - -You can also use VK.com's own OpenAPI to log in, but you need to provide -HTML template with JavaScript code to authenticate, check below for an example. - -- Get an OpenAPI App Id and add it to the settings:: - - SOCIAL_AUTH_VK_OPENAPI_ID = '' - - This app id will be passed to the template as ``VK_APP_ID``. - -Snippet example:: - - - - Click to authorize - - -.. _VK.com OAuth: http://vk.com/dev/authentication -.. _VK.com list of permissions: http://vk.com/dev/permissions -.. _VK.com API: http://vk.com/dev/methods -.. _authentication for VK.com applications: http://www.ikrvss.ru/2011/11/08/django-social-auh-and-vkontakte-application/ diff --git a/docs/backends/weibo.rst b/docs/backends/weibo.rst deleted file mode 100644 index 4d933868c..000000000 --- a/docs/backends/weibo.rst +++ /dev/null @@ -1,23 +0,0 @@ -Weibo OAuth -=========== - -Weibo OAuth 2.0 workflow. - -- Register a new application at Weibo_. - -- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings:: - - SOCIAL_AUTH_WEIBO_KEY = '' - SOCIAL_AUTH_WEIBO_SECRET = '' - -By default ``account id``, ``profile_image_url`` and ``gender`` are stored in -extra_data field. - -The user name is used by default to build the user instance ``username``, -sometimes this contains non-ASCII characters which might not be desirable for -the website. To avoid this issue it's possible to use the Weibo ``domain`` -which will be inside the ASCII range by defining this setting:: - - SOCIAL_AUTH_WEIBO_DOMAIN_AS_USERNAME = True - -.. _Weibo: http://open.weibo.com diff --git a/docs/backends/withings.rst b/docs/backends/withings.rst deleted file mode 100644 index a9f5a6ea7..000000000 --- a/docs/backends/withings.rst +++ /dev/null @@ -1,13 +0,0 @@ -Withings -======== - -Withings uses OAuth v1 for Authentication. - -- Register a new application at the `Withings API`_, and - -- fill ``Client ID`` and ``Client Secret`` from withings.com values in the settings:: - - SOCIAL_AUTH_WITHINGS_KEY = '' - SOCIAL_AUTH_WITHINGS_SECRET = '' - -.. _Withings API: https://oauth.withings.com/partner/add diff --git a/docs/backends/wunderlist.rst b/docs/backends/wunderlist.rst deleted file mode 100644 index 218686d44..000000000 --- a/docs/backends/wunderlist.rst +++ /dev/null @@ -1,13 +0,0 @@ -Wunderlist -========== - -Wunderlist uses OAuth v2 for Authentication. - -- Register a new application at `Wunderlist Developer Portal`_, and - -- fill ``Client Id`` and ``Client Secret`` values in the settings:: - - SOCIAL_AUTH_WUNDERLIST_KEY = '' - SOCIAL_AUTH_WUNDERLIST_SECRET = '' - -.. _Wunderlist Developer Portal: https://developer.wunderlist.com/applications diff --git a/docs/backends/xing.rst b/docs/backends/xing.rst deleted file mode 100644 index 3454b116b..000000000 --- a/docs/backends/xing.rst +++ /dev/null @@ -1,14 +0,0 @@ -XING -==== - -XING uses OAuth1 for their auth mechanism, in order to enable the backend -follow: - -- Register a new application at `XING Apps Dashboard`_, - -- Fill **Consumer Key** and **Consumer Secret** values:: - - SOCIAL_AUTH_XING_KEY = '' - SOCIAL_AUTH_XING_SECRET = '' - -.. _XING Apps Dashboard: https://dev.xing.com/applications diff --git a/docs/backends/yahoo.rst b/docs/backends/yahoo.rst deleted file mode 100644 index 01a0c7e37..000000000 --- a/docs/backends/yahoo.rst +++ /dev/null @@ -1,33 +0,0 @@ -Yahoo -===== - -Yahoo supports OpenId and OAuth2 for their auth flow. - - -Yahoo OpenId ------------- - -OpenId doesn't require any particular configuration beside enabling the backend -in the ``AUTHENTICATION_BACKENDS`` setting:: - - AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.yahoo.YahooOpenId', - ... - ) - - -Yahoo OAuth2 ------------- -OAuth 2.0 workflow, useful if you are planning to use Yahoo's API. - -- Register a new application at `Yahoo Developer Center`_, set your app domain - and configure scopes (they can't be overriden by application). - -- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings:: - - SOCIAL_AUTH_YAHOO_OAUTH2_KEY = '' - SOCIAL_AUTH_YAHOO_OAUTH2_SECRET = '' - - -.. _Yahoo Developer Center: https://developer.yahoo.com/ diff --git a/docs/backends/yammer.rst b/docs/backends/yammer.rst deleted file mode 100644 index 86f4c74c3..000000000 --- a/docs/backends/yammer.rst +++ /dev/null @@ -1,30 +0,0 @@ -Yammer -====== - -Yammer users OAuth2 for their auth mechanism, this application supports Yammer -OAuth2 in production and staging modes. - -Production Mode ---------------- - -In order to enable the backend, follow: - - -- Register an application at `Client Applications`_, - set the ``Redirect URI`` to ``http:///complete/yammer/`` - -- Fill **Client Key** and **Client Secret** settings:: - - SOCIAL_AUTH_YAMMER_KEY = '...' - SOCIAL_AUTH_YAMMER_SECRET = '...' - - -Staging Mode ------------- - -Staging mode is configured the same as ``Production Mode``, but settings are -prefixed with:: - - SOCIAL_AUTH_YAMMER_STAGING_* - -.. _Client Applications: https://www.yammer.com/client_applications diff --git a/docs/backends/zotero.rst b/docs/backends/zotero.rst deleted file mode 100644 index 19da98221..000000000 --- a/docs/backends/zotero.rst +++ /dev/null @@ -1,25 +0,0 @@ -Zotero -====== - -Zotero implements OAuth1 as their authentication mechanism for their Web API v3. - - -1. Go to the `Zotero app registration page`_ to register your application. - -2. Fill the **Client ID** and **Client Secret** in your project settings:: - - SOCIAL_AUTH_ZOTERO_KEY = '...' - SOCIAL_AUTH_ZOTERO_SECRET = '...' - -3. Enable the backend:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - ... - 'social.backends.zotero.ZoteroOAuth', - ... - ) - -Further documentation at `Zotero Web API v3 page`_. - -.. _Zotero app registration page: https://www.zotero.org/oauth/apps -.. _Zotero Web API v3 page: https://www.zotero.org/support/dev/web_api/v3/start diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index e8692b23f..000000000 --- a/docs/conf.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', 'sphinx.ext.viewcode'] -templates_path = ['_templates'] -source_suffix = '.rst' -master_doc = 'index' -project = u'Python Social Auth' -copyright = u'2012, Matías Aguirre' -exclude_patterns = ['_build'] -pygments_style = 'sphinx' -html_theme = 'nature' -html_static_path = [] -htmlhelp_basename = 'PythonSocialAuthdoc' -latex_documents = [ - ('index', 'PythonSocialAuth.tex', u'Python Social Auth Documentation', - u'Matías Aguirre', 'manual'), -] -man_pages = [ - ('index', 'pythonsocialauth', u'Python Social Auth Documentation', - [u'Matías Aguirre'], 1) -] -intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/docs/configuration/cherrypy.rst b/docs/configuration/cherrypy.rst deleted file mode 100644 index bd72659e7..000000000 --- a/docs/configuration/cherrypy.rst +++ /dev/null @@ -1,81 +0,0 @@ -CherryPy Framework -================== - -CherryPy framework is supported, it works but I'm sure there's room for -improvements. The implementation uses SQLAlchemy as ORM and expects some values -accessible on ``cherrypy.request`` for it to work. - -At the moment the configuration is expected on ``cherrypy.config`` but ideally -it should be an application configuration instead. - -Expected values are: - -``cherrypy.request.user`` - Current logged in user, load it in your application on a ``before_handler`` - handler. - -``cherrypy.request.db`` - Current database session, again, load it in your application on - a ``before_handler``. - - -Dependencies ------------- - -The `CherryPy built-in application` depends on sqlalchemy_, there's no support for -others ORMs yet but pull-requests are welcome. - - -Enabling the application ------------------------- - -The application is defined on ``social.apps.cherrypy_app.views.CherryPyPSAViews``, -register it in the preferred way for your project. - -Check the rest of the docs for the other settings like enabling authentication -backends and backends keys. - - -Models Setup ------------- - -The models are located in ``social.apps.cherrypy_app.models``. A reference to -your ``User`` model is required to be defined in the project settings, it -should be an import path, for example:: - - cherrypy.config.update({ - 'SOCIAL_AUTH_USER_MODEL': 'models.User' - }) - - -Login mechanism ---------------- - -By default the application sets the session value ``user_id``, this is a simple -solution and it should be improved, if you want to provider your own login -mechanism you can do it by defining the ``SOCIAL_AUTH_LOGIN_METHOD`` setting, -it should be an import path to a callable, like this:: - - SOCIAL_AUTH_USER_MODEL = 'app.login_user' - -And an example of this function:: - - def login_user(strategy, user): - strategy.session_set('user_id', user.id) - -Then, ensure to load the user in your application at ``cherrypy.request.user``, -for example:: - - def load_user(): - user_id = cherrypy.session.get('user_id') - if user_id: - cherrypy.request.user = cherrypy.request.db.query(User).get(user_id) - else: - cherrypy.request.user = None - - - cherrypy.tools.authenticate = cherrypy.Tool('before_handler', load_user) - - -.. _CherryPy built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/cherrypy_app -.. _sqlalchemy: http://www.sqlalchemy.org/ diff --git a/docs/configuration/django.rst b/docs/configuration/django.rst deleted file mode 100644 index 7aeef15be..000000000 --- a/docs/configuration/django.rst +++ /dev/null @@ -1,213 +0,0 @@ -Django Framework -================ - -Django framework has a little more support since this application was derived -from `django-social-auth`_. Here are some details on configuring this -application on Django. - - -Register the application ------------------------- - -The `Django built-in app`_ comes with two ORMs, one for default Django ORM and -another for MongoEngine_ ORM. - -Add the application to ``INSTALLED_APPS`` setting, for default ORM:: - - INSTALLED_APPS = ( - ... - 'social.apps.django_app.default', - ... - ) - -And for MongoEngine_ ORM:: - - INSTALLED_APPS = ( - ... - 'social.apps.django_app.me', - ... - ) - -Also ensure to define the MongoEngine_ storage setting:: - - SOCIAL_AUTH_STORAGE = 'social.apps.django_app.me.models.DjangoStorage' - - -Database --------- - -(For Django 1.7 and higher) sync database to create needed models:: - - ./manage.py migrate - -If you're still using South, you'll need override SOUTH_MIGRATION_MODULES_:: - - SOUTH_MIGRATION_MODULES = { - 'default': 'social.apps.django_app.default.south_migrations' - } - -Note that Django's app labels take the last part of the import, so -in this case ``social.apps.django_app.default`` becomes ``default`` here. - -Sync database to create needed models:: - - ./manage.py syncdb - - -Authentication backends ------------------------ - -Add desired authentication backends to Django's AUTHENTICATION_BACKENDS_ -setting:: - - AUTHENTICATION_BACKENDS = ( - 'social.backends.open_id.OpenIdAuth', - 'social.backends.google.GoogleOpenId', - 'social.backends.google.GoogleOAuth2', - 'social.backends.google.GoogleOAuth', - 'social.backends.twitter.TwitterOAuth', - 'social.backends.yahoo.YahooOpenId', - ... - 'django.contrib.auth.backends.ModelBackend', - ) - -Take into account that backends **must** be defined in AUTHENTICATION_BACKENDS_ -or Django won't pick them when trying to authenticate the user. - -Don't miss ``django.contrib.auth.backends.ModelBackend`` if using ``django.contrib.auth`` -application or users won't be able to login by username / password method. - - -URLs entries ------------- - -Add URLs entries:: - - urlpatterns = patterns('', - ... - url('', include('social.apps.django_app.urls', namespace='social')) - ... - ) - -In case you need a custom namespace, this setting is also needed:: - - SOCIAL_AUTH_URL_NAMESPACE = 'social' - - -Template Context Processors ---------------------------- - -There's a context processor that will add backends and associations data to -template context:: - - TEMPLATE_CONTEXT_PROCESSORS = ( - ... - 'social.apps.django_app.context_processors.backends', - 'social.apps.django_app.context_processors.login_redirect', - ... - ) - -``backends`` context processor will load a ``backends`` key in the context with -three entries on it: - -``associated`` - It's a list of ``UserSocialAuth`` instances related with the currently - logged in user. Will be empty if there's no current user. - -``not_associated`` - A list of available backend names not associated with the current user yet. - If there's no user logged in, it will be a list of all available backends. - -``backends`` - A list of all available backend names. - - -ORMs ----- - -As detailed above the built-in Django application supports default ORM and -MongoEngine_ ORM. - -When using MongoEngine_ make sure you've followed the instructions for -`MongoEngine Django integration`_, as you're now utilizing that user model. The -`MongoEngine_` backend was developed and tested with version 0.6.10 of -`MongoEngine_`. - -Alternate storage models implementations currently follow a tight pattern of -models that behave near or identical to Django ORM models. It is currently -not decoupled from this pattern by any abstraction layer. If you would like -to implement your own alternate, please see the -``social.apps.django_app.default.models`` and -``social.apps.django_app.me.models`` modules for guidance. - - -Exceptions Middleware ---------------------- - -A base middleware is provided that handles ``SocialAuthBaseException`` by -providing a message to the user via the Django messages framework, and then -responding with a redirect to a URL defined in one of the middleware methods. - -The middleware is at ``social.apps.django_app.middleware.SocialAuthExceptionMiddleware``. -Any method can be overridden, but for simplicity these two are recommended:: - - get_message(request, exception) - get_redirect_uri(request, exception) - -By default, the message is the exception message and the URL for the redirect -is the location specified by the ``LOGIN_ERROR_URL`` setting. - -If a valid backend was detected by ``strategy()`` decorator, it will be -available at ``request.strategy.backend`` and ``process_exception()`` will -use it to build a backend-dependent redirect URL but fallback to default if not -defined. - -Exception processing is disabled if any of this settings is defined with a -``True`` value:: - - _SOCIAL_AUTH_RAISE_EXCEPTIONS = True - SOCIAL_AUTH_RAISE_EXCEPTIONS = True - RAISE_EXCEPTIONS = True - DEBUG = True - -The redirect destination will get two ``GET`` parameters: - -``message = ''`` - Message from the exception raised, in some cases it's the message returned - by the provider during the auth process. - -``backend = ''`` - Backend name that was used, if it was a valid backend. - - -Django Admin ------------- - -The default application (not the MongoEngine_ one) contains an ``admin.py`` -module that will be auto-discovered by the usual mechanism. - -But, by the nature of the application which depends on the existence of a user -model, it's easy to fall in a recursive import ordering making the application -fail to load. This happens because the admin module will build a set of fields -to populate the ``search_fields`` property to search for related users in the -administration UI, but this requires the user model to be retrieved which might -not be defined at that time. - -To avoid this issue define the following setting to circumvent the import -error:: - - SOCIAL_AUTH_ADMIN_USER_SEARCH_FIELDS = ['field1', 'field2'] - -For example:: - - SOCIAL_AUTH_ADMIN_USER_SEARCH_FIELDS = ['username', 'first_name', 'email'] - -The fields listed **must** be user models fields. - -.. _MongoEngine: http://mongoengine.org -.. _MongoEngine Django integration: http://mongoengine-odm.readthedocs.org/en/latest/django.html -.. _django-social-auth: https://github.com/omab/django-social-auth -.. _Django built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/django_app -.. _AUTHENTICATION_BACKENDS: http://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#authentication-backends -.. _django@dc43fbc: https://github.com/django/django/commit/dc43fbc2f21c12e34e309d0e8a121020391aa03a -.. _SOUTH_MIGRATION_MODULES: http://south.readthedocs.org/en/latest/settings.html#south-migration-modules diff --git a/docs/configuration/flask.rst b/docs/configuration/flask.rst deleted file mode 100644 index fc7ada33d..000000000 --- a/docs/configuration/flask.rst +++ /dev/null @@ -1,160 +0,0 @@ -Flask Framework -=============== - -Flask reusable applications are tricky (or I'm not capable enough). Here are -details on how to enable this application on Flask. - - -Dependencies ------------- - -The `Flask built-in app` depends on sqlalchemy_, there's initial support for -MongoEngine_ ORM too (check below for more details). - - -Enabling the application ------------------------- - -The applications define a `Flask Blueprint`_, which needs to be registered once -the Flask app is configured by:: - - from social.apps.flask_app.routes import social_auth - - app.register_blueprint(social_auth) - -For MongoEngine_ you need this setting:: - - SOCIAL_AUTH_STORAGE = 'social.apps.flask_app.me.models.FlaskStorage' - - -Models Setup ------------- - -At the moment the models for python-social-auth_ are defined inside a function -because they need the reference to the current db instance and the User model -used on your project (check *User model reference* below). Once the Flask app -and the database are defined, call ``init_social`` to register the models:: - - from social.apps.flask_app.default.models import init_social - - init_social(app, db) - -For MongoEngine_:: - - from social.apps.flask_app.me.models import init_social - - init_social(app, db) - -So far I wasn't able to find another way to define the models on another way -rather than making it as a side-effect of calling this function since the -database is not available and ``current_app`` cannot be used on init time, just -run time. - - -User model reference --------------------- - -The application keeps a reference to the User model used by your project, -define it by using this setting:: - - SOCIAL_AUTH_USER_MODEL = 'foobar.models.User' - -The value must be the import path to the User model. - - -Global user ------------ - -The application expects the current logged in user accesible at ``g.user``, -define a handler like this to ensure that:: - - @app.before_request - def global_user(): - g.user = get_current_logged_in_user - - -Flask-Login ------------ - -The application works quite well with Flask-Login_, ensure to have some similar -handlers to these:: - - @login_manager.user_loader - def load_user(userid): - try: - return User.query.get(int(userid)) - except (TypeError, ValueError): - pass - - - @app.before_request - def global_user(): - g.user = login.current_user - - - # Make current user available on templates - @app.context_processor - def inject_user(): - try: - return {'user': g.user} - except AttributeError: - return {'user': None} - - -Remembering sessions --------------------- - -The users session can be remembered when specified on login. The common -implementation for this feature is to pass a parameter from the login form -(``remember_me``, ``keep``, etc), to flag the action. Flask-Login_ will mark -the session as persistent if told so. - -python-social-auth_ will check for a given name (``keep``) by default, but -since providers won't pass parameters back to the application, the value must -be persisted in the session before the authentication process happens. - -So, the following setting is required for this to work:: - - SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = ['keep'] - -It's possible to override the default name with this setting:: - - SOCIAL_AUTH_REMEMBER_SESSION_NAME = 'remember_me' - -Don't use the value ``remember`` since that will clash with Flask-Login_ which -pops the value from the session. - -Then just pass the parameter ``keep=1`` as a GET or POST parameter. - - -Exceptions handling -------------------- - -The Django application has a middleware (that fits in the framework -architecture) to facilitate the different exceptions_ handling raised by -python-social-auth_. The same can be accomplished (even on a simpler way) in -Flask by defining an errorhandler_. For example the next code will redirect any -social-auth exception to a ``/socialerror`` URL:: - - from social.exceptions import SocialAuthBaseException - - - @app.errorhandler(500) - def error_handler(error): - if isinstance(error, SocialAuthBaseException): - return redirect('/socialerror') - - -Be sure to set your debug and test flags to ``False`` when testing this on your -development environment, otherwise the exception will be raised and error -handlers won't be called. - - -.. _Flask Blueprint: http://flask.pocoo.org/docs/blueprints/ -.. _Flask-Login: https://github.com/maxcountryman/flask-login -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _Flask built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/flask_app -.. _sqlalchemy: http://www.sqlalchemy.org/ -.. _exceptions: https://github.com/omab/python-social-auth/blob/master/social/exceptions.py -.. _errorhandler: http://flask.pocoo.org/docs/api/#flask.Flask.errorhandler -.. _MongoEngine: http://mongoengine.org diff --git a/docs/configuration/index.rst b/docs/configuration/index.rst deleted file mode 100644 index 92dc283f3..000000000 --- a/docs/configuration/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -Configuration -============= - -All the apps share the settings names, some settings for Django framework are -special (like ``AUTHENTICATION_BACKENDS``). - -Below there's a main settings document detailing each configuration and its -purpose, plus sections detailed for each framework and their particularities. - -Support for more frameworks will be added in the future, pull-requests are very -welcome. - -Contents: - -.. toctree:: - :maxdepth: 2 - - settings - django - flask - pyramid - cherrypy - webpy - porting_from_dsa diff --git a/docs/configuration/porting_from_dsa.rst b/docs/configuration/porting_from_dsa.rst deleted file mode 100644 index aea7e72dc..000000000 --- a/docs/configuration/porting_from_dsa.rst +++ /dev/null @@ -1,145 +0,0 @@ -Porting from django-social-auth -=============================== - - -Being a derivative work from django-social-auth_, porting from it to -python-social-auth_ should be an easy task. Porting to others libraries usually -is a pain, I'm trying to make this as easy as possible. - - -Installed apps --------------- - -On django-social-auth_ there was a single application to add into -``INSTALLED_APPS`` plus a setting to define which ORM to be used (default or -MongoEngine). Now the apps are split and there's not need for that extra -setting. - -When using the default ORM:: - - INSTALLED_APPS = ( - ... - 'social.apps.django_app.default', - ... - ) - -And when using MongoEngine:: - - INSTALLED_APPS = ( - ... - 'social.apps.django_app.me', - ... - ) - -The models table names were defined to be compatible with those used on -django-social-auth_, so data is not needed to be migrated. - - -URLs ----- - -The URLs are namespaced, you can chose your namespace, the `example app`_ uses -the ``social`` namespace. Replace the old include with:: - - urlpatterns = patterns('', - ... - url('', include('social.apps.django_app.urls', namespace='social')) - ... - ) - -On templates use a namespaced URL:: - - {% url 'social:begin' "google-oauth2" %} - -Account disconnection URL would be:: - - {% url 'social:disconnect_individual' provider, id %} - - -Porting settings ----------------- - -All python-social-auth_ settings are prefixed with ``SOCIAL_AUTH_``, except for -some exception on Django framework, ``AUTHENTICATION_BACKENDS`` remains the -same for obvious reasons. - -All backends settings have the backend name into it, all uppercase and with -dashes replaced with underscores, take for instance Google OAuth2 backend is -named ``google-oauth2``, any setting name related to that backend should start -with ``SOCIAL_AUTH_GOOGLE_OAUTH2_``. - -Keys and secrets are some mandatory settings needed for OAuth providers, to -keep consistency the names follow the same naming convention ``*_KEY`` for the -application key, and ``*_SECRET`` for the secret. OAuth1 backends use to have -``CONSUMER`` in the setting name, not anymore. Following with the Google OAuth2 -example:: - - SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '...' - SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '...' - -Remember that the name of the backend is needed in the settings, and names -differ a little from backend to backend, like `Facebook OAuth2 backend`_ name -is ``facebook``. So the settings should be:: - - SOCIAL_AUTH_FACEBOOK_KEY = '...' - SOCIAL_AUTH_FACEBOOK_SECRET = '...' - - -Authentication backends ------------------------ - -Import path for authentication backends changed a little, there's no more -``contrib`` module, there's no need for it. Some backends changed the names to -have some consistency, check the backends, it should be easy to track the names -changes. Examples of the new import paths:: - - AUTHENTICATION_BACKENDS = ( - 'social.backends.open_id.OpenIdAuth', - 'social.backends.google.GoogleOpenId', - 'social.backends.google.GoogleOAuth2', - 'social.backends.google.GoogleOAuth', - 'social.backends.twitter.TwitterOAuth', - 'social.backends.facebook.FacebookOAuth2', - ) - - -Session -------- - -Django stores the last authentication backend used in the user session as an -import path, this can cause import troubles when porting since the old import -paths aren't valid anymore. Some solutions to this problem are: - -1. Clean the session and force the users to login again in your site - -2. Run a migration script that will update the authentication backend session - value for each session in your database. This implies figuring out the new - import path for each backend you have configured, which is the value used in - ``AUTHENTICATION_BACKENDS`` setting. - - `@tomgruner`_ created a Gist here_ that updates the value just for Facebook - backend. A ``template`` for this script would look like this:: - - from django.contrib.sessions.models import Session - - BACKENDS = { - 'social_auth.backends.facebook.FacebookBackend': 'social.backends.facebook.FacebookOAuth2' - } - - for sess in Session.objects.iterator(): - session_dict = sess.get_decoded() - - if '_auth_user_backend' in session_dict.keys(): - # Change old backend import path from new backend import path - if session_dict['_auth_user_backend'].startswith('social_auth'): - session_dict['_auth_user_backend'] = BACKENDS[session_dict['_auth_user_backend']] - new_sess = Session.objects.save(sess.session_key, session_dict, sess.expire_date) - print 'New session saved {}'.format(new_sess.pk) - - -.. _django-social-auth: https://github.com/omab/django-social-auth -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _example app: https://github.com/omab/python-social-auth/blob/master/examples/django_example/example/urls.py#L17 -.. _Facebook OAuth2 backend: https://github.com/omab/python-social-auth/blob/master/social/backends/facebook.py#L29 -.. _@tomgruner: https://github.com/tomgruner -.. _here: https://gist.github.com/tomgruner/5ce8bb1f4c55d17b5b25 diff --git a/docs/configuration/pyramid.rst b/docs/configuration/pyramid.rst deleted file mode 100644 index 7767ed614..000000000 --- a/docs/configuration/pyramid.rst +++ /dev/null @@ -1,137 +0,0 @@ -Pyramid Framework -================= - -Pyramid_ reusable applications are tricky (or I'm not capable enough). Here are -details on how to enable this application on Pyramid. - - -Dependencies ------------- - -The `Pyramid built-in app`_ depends on sqlalchemy_, there's no support for others -ORMs yet but pull-requests are welcome. - - -Enabling the application ------------------------- - -The application can be scanned by ``Configurator.scan()``, also it defines an -``includeme()`` in the ``__init__.py`` file which will add the needed routes to -your application configuration. To scan it just add:: - - config.include('social.apps.pyramid_app') - config.scan('social.apps.pyramid_app') - - -Models Setup ------------- - -At the moment the models for python-social-auth_ are defined inside a function -because they need the reference to the current DB instance and the User model -used on your project (check *User model reference* below). Once the Pyramid -application configuration and database are defined, call ``init_social`` to -register the models:: - - from social.apps.pyramid_app.models import init_social - - init_social(config, Base, DBSession) - -So far I wasn't able to find another way to define the models on another way -rather than making it as a side-effect of calling this function since the -database is not available and ``current_app`` cannot be used on initialization -time, just run time. - - -User model reference --------------------- - -The application keeps a reference to the User model used by your project, -define it by using this setting:: - - SOCIAL_AUTH_USER_MODEL = 'foobar.models.User' - -The value must be the import path to the User model. - - -Global user ------------ - -The application expects the current logged in user accessible at ``request.user``, -the example application ensures that with this hander:: - - def get_user(request): - user_id = request.session.get('user_id') - if user_id: - user = DBSession.query(User)\ - .filter(User.id == user_id)\ - .first() - else: - user = None - return user - -The handler is added to the configuration doing:: - - config.add_request_method('example.auth.get_user', 'user', reify=True) - -This is just a simple example, probably your project does it in a better way. - - -User login ----------- - -Since the application doesn't make any assumption on how you are going to login -the users, you need to specify it. In order to do that, define these settings:: - - SOCIAL_AUTH_LOGIN_FUNCTION = 'example.auth.login_user' - SOCIAL_AUTH_LOGGEDIN_FUNCTION = 'example.auth.login_required' - -The first one must accept the strategy used and the user instance that was -created or retrieved from the database, there you can set the user id in the -session or cookies or whatever place used later to retrieve the id again and -load the user from the database (check the snippet above in *Global User*). - -The second one is used to ensure that there's a user logged in when calling the -disconnect view. It must accept a ``User`` instance and return ``True`` or -``Flase``. - -Check the auth.py_ in the example application for details on how it's done -there. - - -Social auth in templates context --------------------------------- - -To access the social instances related to a user in the template context, you -can do so by accessing the ``social_auth`` attribute in the user instance:: - -
  • ${social.provider}
  • - -Also you can add the backends (associated and not associated to a user) by -enabling this context function in your project:: - - from pyramid.events import subscriber, BeforeRender - from social.apps.pyramid_app.utils import backends - - @subscriber(BeforeRender) - def add_social(event): - request = event['request'] - event.update(backends(request, request.user)) - -That will load a dict with entries:: - - { - 'associated': [...], - 'not_associated': [...], - 'backends': [...] - } - -The ``associated`` key will have all the associated ``UserSocialAuth`` -instances related to the given user. ``not_associated`` will have the backends -names not associated and backends will have all the enabled backends names. - - -.. _Pyramid: http://www.pylonsproject.org/projects/pyramid/about -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _Pyramid built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/pyramid_app -.. _sqlalchemy: http://www.sqlalchemy.org/ -.. _auth.py: https://github.com/omab/python-social-auth/blob/master/examples/pyramid_example/example/auth.py diff --git a/docs/configuration/settings.rst b/docs/configuration/settings.rst deleted file mode 100644 index efff5845c..000000000 --- a/docs/configuration/settings.rst +++ /dev/null @@ -1,311 +0,0 @@ -Configuration -============= - -Application setup ------------------ - -Once the application is installed (check Installation_) define the following -settings to enable the application behavior. Also check the sections dedicated -to each framework for detailed instructions. - - -Settings name -------------- - -Almost all settings are prefixed with ``SOCIAL_AUTH_``, there are some -exceptions for Django framework like ``AUTHENTICATION_BACKENDS``. - -All settings can be defined per-backend by adding the backend name to the -setting name like ``SOCIAL_AUTH_TWITTER_LOGIN_URL``. Settings discovery is done -by reducing the name starting with backend setting, then app setting and -finally global setting, for example:: - - SOCIAL_AUTH_TWITTER_LOGIN_URL - SOCIAL_AUTH_LOGIN_URL - LOGIN_URL - -The backend name is generated from the ``name`` attribute from the backend -class by uppercasing it and replacing ``-`` with ``_``. - - -Keys and secrets ----------------- - -- Setup needed OAuth keys (see OAuth_ section for details):: - - SOCIAL_AUTH_TWITTER_KEY = 'foobar' - SOCIAL_AUTH_TWITTER_SECRET = 'bazqux' - -OpenId backends don't require keys usually, but some need some API Key to -call any API on the provider. Check Backends_ sections for details. - - -Authentication backends ------------------------ - -Register the backends you plan to use, on Django framework use the usual -``AUTHENTICATION_BACKENDS`` settings, for others, define -``SOCIAL_AUTH_AUTHENTICATION_BACKENDS``:: - - SOCIAL_AUTH_AUTHENTICATION_BACKENDS = ( - 'social.backends.open_id.OpenIdAuth', - 'social.backends.google.GoogleOpenId', - 'social.backends.google.GoogleOAuth2', - 'social.backends.google.GoogleOAuth', - 'social.backends.twitter.TwitterOAuth', - 'social.backends.yahoo.YahooOpenId', - ... - ) - - -URLs options ------------- - -These URLs are used on different steps of the auth process, some for successful -results and others for error situations. - -``SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/logged-in/'`` - Used to redirect the user once the auth process ended successfully. The - value of ``?next=/foo`` is used if it was present - -``SOCIAL_AUTH_LOGIN_ERROR_URL = '/login-error/'`` - URL where the user will be redirected in case of an error - -``SOCIAL_AUTH_LOGIN_URL = '/login-url/'`` - Is used as a fallback for ``LOGIN_ERROR_URL`` - -``SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/new-users-redirect-url/'`` - Used to redirect new registered users, will be used in place of - ``SOCIAL_AUTH_LOGIN_REDIRECT_URL`` if defined. Note that ``?next=/foo`` is appended if present, - if you want new users to go to next, you'll need to do it yourself. - -``SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = '/new-association-redirect-url/'`` - Like ``SOCIAL_AUTH_NEW_USER_REDIRECT_URL`` but for new associated accounts - (user is already logged in). Used in place of ``SOCIAL_AUTH_LOGIN_REDIRECT_URL`` - -``SOCIAL_AUTH_DISCONNECT_REDIRECT_URL = '/account-disconnected-redirect-url/'`` - The user will be redirected to this URL when a social account is - disconnected - -``SOCIAL_AUTH_INACTIVE_USER_URL = '/inactive-user/'`` - Inactive users can be redirected to this URL when trying to authenticate. - -Successful URLs will default to ``SOCIAL_AUTH_LOGIN_URL`` while error URLs will -fallback to ``SOCIAL_AUTH_LOGIN_ERROR_URL``. - - -User model ----------- - -``UserSocialAuth`` instances keep a reference to the ``User`` model of your -project, since this is not known, the ``User`` model must be configured by -a setting:: - - SOCIAL_AUTH_USER_MODEL = 'foo.bar.User' - -``User`` model must have a ``username`` and ``email`` field, these are -required. - -Also an ``is_authenticated`` and ``is_active`` boolean flags are recommended, -these can be methods if necessary (must return ``True`` or ``False``). If the -model lacks them a ``True`` value is assumed. - - -Tweaking some fields length ---------------------------- - -Some databases impose limitations on index columns (like MySQL InnoDB). These -limitations won't play nice on some ``UserSocialAuth`` fields. To avoid such -errors, define some of the following settings. - -``SOCIAL_AUTH_UID_LENGTH = `` - Used to define the max length of the field `uid`. A value of 223 should work - when using MySQL InnoDB which impose a 767 bytes limit (assuming UTF-8 - encoding). - -``SOCIAL_AUTH_NONCE_SERVER_URL_LENGTH = `` - ``Nonce`` model has a unique constraint over ``('server_url', 'timestamp', - 'salt')``, salt has a max length of 40, so ``server_url`` length must be - tweaked using this setting. - -``SOCIAL_AUTH_ASSOCIATION_SERVER_URL_LENGTH = `` or ``SOCIAL_AUTH_ASSOCIATION_HANDLE_LENGTH = `` - ``Association`` model has a unique constraint over ``('server_url', - 'handle')``, both fields lengths can be tweaked by these settings. - - -Username generation -------------------- - -Some providers return a username, others just an ID or email or first and last -names. The application tries to build a meaningful username when possible but -defaults to generating one if needed. - -A UUID is appended to usernames in case of collisions. Here are some settings -to control username generation. - -``SOCIAL_AUTH_UUID_LENGTH = 16`` - This controls the length of the UUID appended to usernames. - -``SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True`` - If you want to use the full email address as the ``username``, define this - setting. - -``SOCIAL_AUTH_SLUGIFY_USERNAMES = False`` - For those that prefer slugged usernames, the ``get_username`` pipeline can - apply a slug transformation (code borrowed from Django project) by defining - this setting to ``True``. The feature is disabled by default to to not - force this option to all projects. - -``SOCIAL_AUTH_CLEAN_USERNAMES = True`` - By default the regex ``r'[^\w.@+-_]+'`` is applied over usernames to clean - them from usual undesired characters like spaces. Set this setting to - ``False`` to disable this behavior. - - -Extra arguments on auth processes ---------------------------------- - -Some providers accept particular GET parameters that produce different results -during the auth process, usually used to show different dialog types (mobile -version, etc). - -You can send extra parameters on auth process by defining settings per backend, -example to request Facebook to show Mobile authorization page, define:: - - FACEBOOK_AUTH_EXTRA_ARGUMENTS = {'display': 'touch'} - -For other providers, just define settings in the form:: - - SOCIAL_AUTH__AUTH_EXTRA_ARGUMENTS = {...} - -Also, you can send extra parameters on request token process by defining -settings in the same way explained above but with this other suffix:: - - SOCIAL_AUTH__REQUEST_TOKEN_EXTRA_ARGUMENTS = {...} - -Basic information is requested to the different providers in order to create -a coherent user instance (with first and last name, email and full name), this -could be too intrusive for some sites that want to ask users the minimum data -possible. It's possible to override the default values requested by defining -any of the following settings, for Open Id providers:: - - SOCIAL_AUTH__IGNORE_DEFAULT_AX_ATTRS = True - SOCIAL_AUTH__AX_SCHEMA_ATTRS = [ - (schema, alias) - ] - -For OAuth backends:: - - SOCIAL_AUTH__IGNORE_DEFAULT_SCOPE = True - SOCIAL_AUTH__SCOPE = [ - ... - ] - - -Processing redirects and urlopen --------------------------------- - -The application issues several redirects and API calls. The following settings -allow some tweaks to the behavior of these. - -``SOCIAL_AUTH_SANITIZE_REDIRECTS = False`` - The auth process finishes with a redirect, by default it's done to the - value of ``SOCIAL_AUTH_LOGIN_REDIRECT_URL`` but can be overridden with - ``next`` GET argument. If this setting is ``True``, this application will - vary the domain of the final URL and only redirect to it if it's on the - same domain. - -``SOCIAL_AUTH_REDIRECT_IS_HTTPS = False`` - On projects behind a reverse proxy that uses HTTPS, the redirect URIs - can have the wrong schema (``http://`` instead of ``https://``) if - the request lacks the appropriate headers, which might cause errors during - the auth process. To force HTTPS in the final URIs set this setting to - ``True`` - -``SOCIAL_AUTH_URLOPEN_TIMEOUT = 30`` - Any ``urllib2.urlopen`` call will be performed with the default timeout - value, to change it without affecting the global socket timeout define this - setting (the value specifies timeout seconds). - - ``urllib2.urlopen`` uses ``socket.getdefaulttimeout()`` value by default, so - setting ``socket.setdefaulttimeout(...)`` will affect ``urlopen`` when this - setting is not defined, otherwise this setting takes precedence. Also this - might affect other places in Django. - - ``timeout`` argument was introduced in python 2.6 according to `urllib2 - documentation`_ - - -Whitelists ----------- - -Registration can be limited to a set of users identified by their email -address or domain name. To white-list just set any of these settings: - -``SOCIAL_AUTH__WHITELISTED_DOMAINS = ['foo.com', 'bar.com']`` - Supply a list of domain names to be white-listed. Any user with an email - address on any of the allowed domains will login successfully, otherwise - ``AuthForbidden`` is raised. - -``SOCIAL_AUTH__WHITELISTED_EMAILS = ['me@foo.com', 'you@bar.com']`` - Supply a list of email addresses to be white-listed. Any user with an email - address in this list will login successfully, otherwise ``AuthForbidden`` - is raised. - - -Miscellaneous settings ----------------------- - -``SOCIAL_AUTH_PROTECTED_USER_FIELDS = ['email',]`` - During the pipeline process a ``dict`` named ``details`` will be populated - with the needed values to create the user instance, but it's also used to - update the user instance. Any value in it will be checked as an attribute - in the user instance (first by doing ``hasattr(user, name)``). Usually - there are attributes that cannot be updated (like ``username``, ``id``, - ``email``, etc.), those fields need to be *protect*. Set any field name that - requires *protection* in this setting, and it won't be updated. - -``SOCIAL_AUTH_SESSION_EXPIRATION = False`` - By default, user session expiration time will be set by your web - framework (in Django, for example, it is set with - `SESSION_COOKIE_AGE`_). Some providers return the time that the - access token will live, which is stored in ``UserSocialAuth.extra_data`` - under the key ``expires``. Changing this setting to True will override your - web framework's session length setting and set user session lengths to - match the ``expires`` value from the auth provider. - -``SOCIAL_AUTH_OPENID_PAPE_MAX_AUTH_AGE = `` - Enable `OpenID PAPE`_ extension support by defining this setting. - -``SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = ['foo',]`` - If you want to store extra parameters from POST or GET in session, like it - was made for ``next`` parameter, define this setting with the parameter - names. - - In this case ``foo`` field's value will be stored when user follows this - link ``...``. - -``SOCIAL_AUTH_PASSWORDLESS = False`` - When this setting is ``True`` and ``social.pipeline.mail.send_validation`` - is enabled, it allows the implementation of a `passwordless authentication - mechanism`_. Example of this implementation can be found at - psa-passwordless_. - - -Account disconnection ---------------------- - -Disconnect is an side-effect operation and should be done by POST method only, -some CSRF protection is encouraged (and enforced on Django app). Ensure that -any call to `/disconnect//` or `/disconnect///` is done -using POST. - - -.. _urllib2 documentation: http://docs.python.org/library/urllib2.html#urllib2.urlopen -.. _OpenID PAPE: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0.html -.. _Installation: ../installing.html -.. _Backends: ../backends/index.html -.. _OAuth: http://oauth.net/ -.. _passwordless authentication mechanism: https://medium.com/@ninjudd/passwords-are-obsolete-9ed56d483eb -.. _psa-passwordless: https://github.com/omab/psa-passwordless -.. _SESSION_COOKIE_AGE: https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-SESSION_COOKIE_AGE diff --git a/docs/configuration/webpy.rst b/docs/configuration/webpy.rst deleted file mode 100644 index 8e1ada471..000000000 --- a/docs/configuration/webpy.rst +++ /dev/null @@ -1,74 +0,0 @@ -Webpy Framework -=============== - -Webpy_ framework is easy to setup, once that python-social-auth_ is installed -or accessible in the ``PYTHONPATH``, just add the needed configurations to make -it run. - - -Dependencies ------------- - -The `Webpy built-in app` depends on sqlalchemy_, there's no support for others -ORMs yet but pull-requests are welcome. - - -Configuration -------------- - -Add the needed settings into ``web.config`` store. Settings are prefixed with -``SOCIAL_AUTH_`` but there's a helper for it:: - - from social.utils import setting_name - - web.config[setting_name('USER_MODEL')] = 'models.User' - web.config[setting_name('LOGIN_REDIRECT_URL')] = '/done/' - web.config[setting_name('AUTHENTICATION_BACKENDS')] = ( - 'social.backends.google.GoogleOAuth2', - ... - ) - -Add all the settings needed for the app (check Configuration_ section for -details). - - -URLs ----- - -Add the social application into URLs:: - - from social.apps.webpy_app import app as social_app - - urls = ( - ... - '', social_app.app_social - ... - ) - - -Session -------- - -python-social-auth_ depends on sessions storage to keep some essential values, -usually redirects and ``state`` parameters used to validate authentication -process on OAuth providers. - -The `Webpy built-in app` expects the session reference to be available under -``web.web_session`` so ensure it's available there. - - -User model ----------- - -Like the other apps, the User model must be defined on settings since -a reference to it is kept on ``UserSocialAuth`` instance. Define like this:: - - web.config[setting_name('USER_MODEL')] = 'models.User' - -Where the value is the import path to the User model used on your project. - - -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _Webpy: http://webpy.org/ -.. _Webpy built-in app: https://github.com/omab/python-social-auth/tree/master/social/apps/webpy_app -.. _sqlalchemy: http://www.sqlalchemy.org/ diff --git a/docs/copyright.rst b/docs/copyright.rst deleted file mode 100644 index 32bf55bc0..000000000 --- a/docs/copyright.rst +++ /dev/null @@ -1,12 +0,0 @@ -Copyrights and Licence -====================== - -``python-social-auth`` is protected by BSD licence. Check the LICENCE_ for -details. - -The base work was derived from django-social-auth_ work and copyrighted too, -check `django-social-auth LICENCE`_ for details: - -.. _LICENCE: https://github.com/omab/python-social-auth/blob/master/LICENSE -.. _django-social-auth: https://github.com/omab/django-social-auth -.. _django-social-auth LICENCE: https://github.com/omab/django-social-auth/blob/master/LICENSE diff --git a/docs/developer_intro.rst b/docs/developer_intro.rst deleted file mode 100644 index ebd8526cc..000000000 --- a/docs/developer_intro.rst +++ /dev/null @@ -1,170 +0,0 @@ -Beginners Guide -=============== - -This is an attempt to bring together a number of concepts in python-social-auth -(psa) so that you will understand how it fits into your system. This definitely -has a Django flavor to it (because that's how I learned it). - -Understanding PSA URLs ------------------------ - -If you have not seen namespaced URLs before, you are about to be introduced. -When you add the PSA entry to your urls.py, it looks like this:: - - url(r'', include('social.apps.django_app.urls', namespace='social')) - -that "namespace" part on the end is what keeps the names in the PSA-world from -colliding with the names in your app, or other 3rd-party apps. So your login -link will look like this:: - - Login - -(See how "social" in the URL mapping matches the value of "namespace" in the -urls.py entry?) - -Understanding Backends ----------------------- - -PSA implements a lot of backends. Find the entry in the docs for your backend, -and if it's there, follow the steps to enable it, which come down to - -1) Set up SOCIAL_AUTH_{backend} variables in settings.py. (The - settings vary, based on the backends) - -2) Adding your backend to AUTHENTICATION_BACKENDS in settings.py. - -If you need to implement a different backend (for instance, let's say you -want to use Intuit's OpenID), you can subclass the nearest one and override -the "name" attribute:: - - from social.backends.open_id import OpenIDAuth - - class IntuitOpenID(OpenIDAuth): - name = 'intuit' - -And then add your new backend to AUTHENTICATION_BACKENDS in settings.py. - -A couple notes about the pipeline: - -The standard pipeline does not log the user in until after the pipeline has -completed. So if you get a value in the user key of the accumulative -dictionary, that implies that the user was logged in when the process started. - -Understanding the Pipeline --------------------------- - -Reversing a URL like ``{% url 'social:begin' 'github' %}`` will give you a url -like:: - - http://example.com/login/github - -And clicking on that link will cause the "pipeline" to be started. The pipeline -is a list of functions that build up data about the user as we go through the -steps of the authentication process. (If you really want to understand the -pipeline, look at the source in ``social/backends/base.py``, and see the -``run_pipeline()`` function in ``BaseAuth``.) - -The design contract for each function in the pipeline is: - -1) The pipeline starts with a four-item dictionary (the accumulative dictionary) - which is updated with the results of each function in the pipeline. The - initial four values are: - - ``strategy`` - contains a strategy object - ``backend`` - contains the backend being used during this pipeline run - ``request`` - contains a dictionary of the request keys. Note to Django users -- this is - not an HttpRequest object, it is actually the results of - ``request.REQUEST``. - ``details`` - which is an empty dict. - -2) If the function returns a dictionary or something False-ish, add the contents - of the dictionary to an accumulative dictionary (called ``out`` in - ``run_pipeline``), and call the next step in the pipeline with the - accumulative dictionary. - -3) If something else is returned (for example, a subclass of ``HttpResponse``), - then return that to the browser. - -4) If the pipeline completes, *THEN* the user is authenticated (logged in). So - if you are finding an authenticated user object while the pipeline is - running, that means that the user was logged in when the pipeline started. - -There is one pipeline for your site as a whole -- if you have backend-specific -logic, you have to make your pipeline steps smart enough to skip the step if it -is not relevant. This is as simple as:: - - def my_custom_step(strategy, backend, request, details, *args, **kwargs): - if backend_name != 'my_custom_backend': - return - # otherwise, do the special steps for your custom backend - -Interrupting the Pipeline (and communicating with views) ---------------------------------------------------------- - -Let's say you want to add a custom step in the pipeline -- you want the user -to establish a password so that they can come directly to your site in the -future. We can do that with the @partial decorator, which tells the pipeline -to keep track of where it is so that it can be restarted. - -The first thing we need to do is set up a way for our views to communicate with -the pipeline. That is done by adding a value to the settings file to tell -us which values should be passed back and forth between the Django session -and the pipeline:: - - SOCIAL_AUTH_FIELDS_STORED_IN_SESSION = ['local_password',] - -In our pipeline code, we would have:: - - from django.shortcuts import redirect - from django.contrib.auth.models import User - from social.pipeline.partial import partial - - # partial says "we may interrupt, but we will come back here again" - @partial - def collect_password(strategy, backend, request, details, *args, **kwargs): - # request['local_password'] is set by the pipeline infrastructure - # because it exists in FIELDS_STORED_IN_SESSION - if not request.get('local_password', None): - - # if we return something besides a dict or None, then that is - # returned to the user -- in this case we will redirect to a - # view that can be used to get a password - return redirect("myapp.views.collect_password") - - # grab the user object from the database (remember that they may - # not be logged in yet) and set their password. (Assumes that the - # email address was captured in an earlier step.) - user = User.objects.get(email=kwargs['email']) - user.set_password(request['local_password']) - user.save() - - # continue the pipeline - return - -In our view code, we would have something like:: - - class PasswordForm(forms.Form): - secret_word = forms.CharField(max_length=10) - - def get_user_password(request): - if request.method == 'POST': - form = PasswordForm(request.POST) - if form.is_valid(): - # because of FIELDS_STORED_IN_SESSION, this will get copied - # to the request dictionary when the pipeline is resumed - request.session['local_password'] = form.cleaned_data['secret_word'] - - # once we have the password stashed in the session, we can - # tell the pipeline to resume by using the "complete" endpoint - return redirect(reverse('social:complete', args=("backend_name,"))) - else: - form = PasswordForm() - - return render(request, "password_form.html") - -Note that the ``social:complete`` will re-enter the pipeline with the same -function that interrupted it (in this case, collect_password). diff --git a/docs/exceptions.rst b/docs/exceptions.rst deleted file mode 100644 index fdbfa17c8..000000000 --- a/docs/exceptions.rst +++ /dev/null @@ -1,55 +0,0 @@ -Exceptions -========== - -This set of exceptions were introduced to describe the situations a bit more -than just the ``ValueError`` usually raised. - -``SocialAuthBaseException`` - Base class for all social auth exceptions. - -``AuthException`` - Base exception class for authentication process errors. - -``AuthFailed`` - Authentication failed for some reason. - -``AuthCanceled`` - Authentication was canceled by the user. - -``AuthUnknownError`` - An unknown error stoped the authentication process. - -``AuthTokenError`` - Unauthorized or access token error, it was invalid, impossible to - authenticate or user removed permissions to it. - -``AuthMissingParameter`` - A needed parameter to continue the process was missing, usually raised by - the services that need some POST data like myOpenID. - -``AuthAlreadyAssociated`` - A different user has already associated the social account that the current - user is trying to associate. - -``WrongBackend`` - Raised when the backend given in the URLs is invalid (not enabled or - registered). - -``NotAllowedToDisconnect`` - Raised on disconnect action when it's not safe for the user to disconnect - the social account, probably because the user lacks a password or another - social account. - -``AuthStateMissing`` - The state parameter is missing from the server response. - -``AuthStateForbidden`` - The state parameter returned by the server is not the one sent. - -``AuthTokenRevoked`` - Raised when the user revoked the access_token in the provider. - -``AuthUnreachableProvider`` - Raised when server couldn't communicate with backend. - -These are a subclass of ``ValueError`` to keep backward compatibility. diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 473de706b..000000000 --- a/docs/index.rst +++ /dev/null @@ -1,46 +0,0 @@ -Welcome to Python Social Auth's documentation! -============================================== - -Python Social Auth aims to be an easy to setup social authentication and -authorization mechanism for Python projects supporting protocols like OAuth (1 -and 2), OpenId and others. - -The initial codebase is derived from django-social-auth_ with the idea of -generalizing the process to suit the different frameworks around, providing -the needed tools to bring support to new frameworks. - -django-social-auth_ itself was a product of modified code from -django-twitter-oauth_ and django-openid-auth_ projects. - - -Contents: - -.. toctree:: - :maxdepth: 2 - - intro - installing - configuration/index - pipeline - strategies - storage - exceptions - backends/index - developer_intro - logging_out - tests - use_cases - thanks - copyright - - -Indices and Tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - -.. _django-social-auth: http://github.com/omab/django-social-auth -.. _django-twitter-oauth: https://github.com/henriklied/django-twitter-oauth -.. _django-openid-auth: https://launchpad.net/django-openid-auth diff --git a/docs/installing.rst b/docs/installing.rst deleted file mode 100644 index c1f0cb426..000000000 --- a/docs/installing.rst +++ /dev/null @@ -1,58 +0,0 @@ -Installation -============ - -Dependencies ------------- - -Dependencies that **must** be met to use the application: - -- OpenId_ support depends on python-openid_ - -- OAuth_ support depends on requests-oauthlib_ - -- Several backends demands application registration on their corresponding - sites and other dependencies like sqlalchemy_ on Flask and Webpy. - - -Get a copy ----------- - -From pypi_:: - - $ pip install python-social-auth - -Or:: - - $ easy_install python-social-auth - -Or clone from github_:: - - $ git clone git://github.com/omab/python-social-auth.git - -And add social to ``PYTHONPATH``:: - - $ export PYTHONPATH=$PYTHONPATH:$(pwd)/python-social-auth/ - -Or:: - - $ cd python-social-auth - $ sudo python setup.py install - - -.. _OpenId: http://openid.net/ -.. _OAuth: http://oauth.net/ -.. _pypi: http://pypi.python.org/pypi/python-social-auth/ -.. _github: https://github.com/omab/python-social-auth -.. _python-openid: http://pypi.python.org/pypi/python-openid/ -.. _requests-oauthlib: https://requests-oauthlib.readthedocs.org/ -.. _sqlalchemy: http://www.sqlalchemy.org/ - -Upgrading ---------- - -Django with South -~~~~~~~~~~~~~~~~~ - -Upgrading from 0.1 to 0.2 is likely to cause problems trying to apply a migration when the tables already exist. In this case a fake migration needs to be applied: - -$ python manage.py migrate --fake default diff --git a/docs/intro.rst b/docs/intro.rst deleted file mode 100644 index af3e37c2e..000000000 --- a/docs/intro.rst +++ /dev/null @@ -1,183 +0,0 @@ -Introduction -============ - -Python Social Auth aims to be an easy to setup social authentication and -authorization mechanism for Python projects supporting protocols like OAuth_ (1 -and 2), OpenId_ and others. - - -Features --------- - -This application provides user registration and login using social sites -credentials, here are some features, probably not a full list yet. - - -Supported frameworks -******************** - -Multiple frameworks support: - - * Django_ - * Flask_ - * Pyramid_ - * Webpy_ - * Tornado_ - -More frameworks can be added easily (and should be even easier in the future -once the code matures). - - -Auth providers -************** - -Several supported service by simple backends definition (easy to add new ones -or extend current one): - - * Angel_ OAuth2 - * Beats_ OAuth2 - * Behance_ OAuth2 - * Bitbucket_ OAuth1 - * Box_ OAuth2 - * Dailymotion_ OAuth2 - * Deezer_ OAuth2 - * Disqus_ OAuth2 - * Douban_ OAuth1 and OAuth2 - * Dropbox_ OAuth1 - * Evernote_ OAuth1 - * Facebook_ OAuth2 and OAuth2 for Applications - * Fitbit_ OAuth2 and OAuth1 - * Flickr_ OAuth1 - * Foursquare_ OAuth2 - * `Google App Engine`_ Auth - * Github_ OAuth2 - * Google_ OAuth1, OAuth2 and OpenId - * Instagram_ OAuth2 - * Kakao_ OAuth2 - * Linkedin_ OAuth1 - * Live_ OAuth2 - * Livejournal_ OpenId - * Mailru_ OAuth2 - * MineID_ OAuth2 - * Mixcloud_ OAuth2 - * `Mozilla Persona`_ - * NaszaKlasa_ OAuth2 - * `NGPVAN ActionID`_ OpenId - * Odnoklassniki_ OAuth2 and Application Auth - * OpenId_ - * Podio_ OAuth2 - * Pinterest_ OAuth2 - * Rdio_ OAuth1 and OAuth2 - * Readability_ OAuth1 - * Shopify_ OAuth2 - * Skyrock_ OAuth1 - * Soundcloud_ OAuth2 - * Spotify_ OAuth2 - * ThisIsMyJam_ OAuth1 - * Stackoverflow_ OAuth2 - * Steam_ OpenId - * Stocktwits_ OAuth2 - * Stripe_ OAuth2 - * Tripit_ OAuth1 - * Tumblr_ OAuth1 - * Twilio_ Auth - * Twitch_ OAuth2 - * Twitter_ OAuth1 - * Upwork_ OAuth1 - * Vimeo_ OAuth1 - * VK.com_ OpenAPI, OAuth2 and OAuth2 for Applications - * Weibo_ OAuth2 - * Wunderlist_ OAuth2 - * Xing_ OAuth1 - * Yahoo_ OpenId and OAuth1 - * Yammer_ OAuth2 - * Yandex_ OAuth1, OAuth2 and OpenId - - -User data -********* - -Basic user data population, to allow custom fields values from providers -response. - - -Social accounts association -*************************** - -Multiple social accounts can be associated to a single user. - - -Authentication and disconnection processing -******************************************* - -Extensible pipeline to handle authentication, association and disconnection -mechanism in ways that suits your project. Check `Authentication Pipeline`_ -section. - - -.. _OpenId: http://openid.net/ -.. _OAuth: http://oauth.net/ -.. _myOpenID: https://www.myopenid.com/ -.. _Angel: https://angel.co -.. _Beats: https://www.beats.com -.. _Behance: https://www.behance.net -.. _Bitbucket: https://bitbucket.org -.. _Box: https://www.box.com -.. _Dailymotion: https://dailymotion.com -.. _Deezer: https://www.deezer.com -.. _Disqus: https://disqus.com -.. _Douban: http://www.douban.com -.. _Dropbox: https://dropbox.com -.. _Evernote: https://www.evernote.com -.. _Facebook: https://www.facebook.com -.. _Fitbit: https://fitbit.com -.. _Flickr: http://www.flickr.com -.. _Foursquare: https://foursquare.com -.. _Google App Engine: https://developers.google.com/appengine/ -.. _Github: https://github.com -.. _Google: http://google.com -.. _Instagram: https://instagram.com -.. _Kakao: https://kakao.com -.. _Linkedin: https://www.linkedin.com -.. _Live: https://www.live.com -.. _Livejournal: http://livejournal.com -.. _Mailru: https://mail.ru -.. _MineID: https://www.mineid.org -.. _Mixcloud: https://www.mixcloud.com -.. _Mozilla Persona: http://www.mozilla.org/persona/ -.. _NaszaKlasa: https://developers.nk.pl/ -.. _NGPVAN ActionID: http://developers.ngpvan.com/action-id -.. _Odnoklassniki: http://www.odnoklassniki.ru -.. _Podio: https://podio.com -.. _Shopify: http://shopify.com -.. _Skyrock: https://skyrock.com -.. _Soundcloud: https://soundcloud.com -.. _Spotify: https://www.spotify.com -.. _ThisIsMyJam: https://thisismyjam.com -.. _Stocktwits: https://stocktwits.com -.. _Stripe: https://stripe.com -.. _Tripit: https://www.tripit.com -.. _Twilio: https://www.twilio.com -.. _Twitch: http://www.twitch.tv/ -.. _Twitter: http://twitter.com -.. _VK.com: http://vk.com -.. _Weibo: http://weibo.com -.. _Wunderlist: http://wunderlist.com -.. _Xing: https://www.xing.com -.. _Yahoo: http://yahoo.com -.. _Yammer: https://www.yammer.com -.. _Yandex: https://yandex.ru -.. _Pinterest: https://www.pinterest.com -.. _Readability: http://www.readability.com/ -.. _Stackoverflow: http://stackoverflow.com/ -.. _Steam: http://steamcommunity.com/ -.. _Rdio: https://www.rdio.com -.. _Vimeo: https://vimeo.com/ -.. _Tumblr: http://www.tumblr.com/ -.. _Django: https://github.com/omab/python-social-auth/tree/master/social/apps/django_app -.. _Flask: https://github.com/omab/python-social-auth/tree/master/social/apps/flask_app -.. _Pyramid: http://www.pylonsproject.org/projects/pyramid/about -.. _Webpy: https://github.com/omab/python-social-auth/tree/master/social/apps/webpy_app -.. _Tornado: http://www.tornadoweb.org/ -.. _Authentication Pipeline: pipeline.html -.. _Upwork: https://www.upwork.com diff --git a/docs/logging_out.rst b/docs/logging_out.rst deleted file mode 100644 index bd10bd86e..000000000 --- a/docs/logging_out.rst +++ /dev/null @@ -1,25 +0,0 @@ -Disconnect and Logging Out -========================== - -It's a common misconception that the ``disconnect`` action is the same as -logging the user out, but this is not the case. - -``Disconnect`` is the way that your users can ask your project to "forget about -my account". This implies removing the ``UserSocialAuth`` instance that was -created, this also implies that the user won't be able to login back into your -site with the social account. Instead the action will be a signup, a new user -instance will be created, not related to the previous one. - -Logging out is just a way to say "forget my current session", and usually -implies removing cookies, invalidating a session hash, etc. The many frameworks -have their own ways to logout an account (Django has ``django.contrib.auth.logout``), -``flask-login`` has it's own way too with `logout_user()`_. - -Since disconnecting a social account means that the user won't be able to log -back in with that social provider into the same user, python-social-auth will -check that the user account is in a valid state for disconnection (it has at -least one more social account associated, or a password, etc). This behavior -can be overridden by changing the `Disconnection Pipeline`_. - -.. _logout_user(): https://github.com/maxcountryman/flask-login/blob/a96de342eae560deec008a02179f593c3799b3ba/flask_login.py#L718-L739 -.. _Disconnection Pipeline: pipeline.html#disconnection-pipeline diff --git a/docs/pipeline.rst b/docs/pipeline.rst deleted file mode 100644 index b3efc486c..000000000 --- a/docs/pipeline.rst +++ /dev/null @@ -1,348 +0,0 @@ -Pipeline -======== - -python-social-auth_ uses an extendible pipeline mechanism where developers can -introduce their functions during the authentication, association and -disconnection flows. - -The functions will receive a variable set of arguments related to the current -process, common arguments are the current ``strategy``, ``user`` (if any) and -``request``. It's recommended that all the function also define an ``**kwargs`` -in the parameters to avoid errors for unexpected arguments. - -Each pipeline entry can return a ``dict`` or ``None``, any other type of return -value is treated as a response instance and returned directly to the client, -check *Partial Pipeline* below for details. - -If a ``dict`` is returned, the value in the set will be merged into the -``kwargs`` argument for the next pipeline entry, ``None`` is taken as if ``{}`` -was returned. - - -Authentication Pipeline ------------------------ - -The final process of the authentication workflow is handled by an operations -pipeline where custom functions can be added or default items can be removed to -provide a custom behavior. The default pipeline is a mechanism that creates -user instances and gathers basic data from providers. - -The default pipeline is composed by:: - - ( - # Get the information we can about the user and return it in a simple - # format to create the user instance later. On some cases the details are - # already part of the auth response from the provider, but sometimes this - # could hit a provider API. - 'social.pipeline.social_auth.social_details', - - # Get the social uid from whichever service we're authing thru. The uid is - # the unique identifier of the given user in the provider. - 'social.pipeline.social_auth.social_uid', - - # Verifies that the current auth process is valid within the current - # project, this is where emails and domains whitelists are applied (if - # defined). - 'social.pipeline.social_auth.auth_allowed', - - # Checks if the current social-account is already associated in the site. - 'social.pipeline.social_auth.social_user', - - # Make up a username for this person, appends a random string at the end if - # there's any collision. - 'social.pipeline.user.get_username', - - # Send a validation email to the user to verify its email address. - # Disabled by default. - # 'social.pipeline.mail.mail_validation', - - # Associates the current social details with another user account with - # a similar email address. Disabled by default. - # 'social.pipeline.social_auth.associate_by_email', - - # Create a user account if we haven't found one yet. - 'social.pipeline.user.create_user', - - # Create the record that associates the social account with the user. - 'social.pipeline.social_auth.associate_user', - - # Populate the extra_data field in the social record with the values - # specified by settings (and the default ones like access_token, etc). - 'social.pipeline.social_auth.load_extra_data', - - # Update the user record with any changed info from the auth service. - 'social.pipeline.user.user_details', - ) - - -It's possible to override it by defining the setting ``SOCIAL_AUTH_PIPELINE``. -For example, a pipeline that won't create users, just accept already registered -ones would look like this:: - - SOCIAL_AUTH_PIPELINE = ( - 'social.pipeline.social_auth.social_details', - 'social.pipeline.social_auth.social_uid', - 'social.pipeline.social_auth.auth_allowed', - 'social.pipeline.social_auth.social_user', - 'social.pipeline.social_auth.associate_user', - 'social.pipeline.social_auth.load_extra_data', - 'social.pipeline.user.user_details', - ) - -Note that this assumes the user is already authenticated, and thus the ``user`` key -in the dict is populated. In cases where the authentication is purely external, a -pipeline method must be provided that populates the ``user`` key. Example:: - - - SOCIAL_AUTH_PIPELINE = ( - 'myapp.pipeline.load_user', - 'social.pipeline.social_auth.social_user', - 'social.pipeline.social_auth.associate_user', - 'social.pipeline.social_auth.load_extra_data', - 'social.pipeline.user.user_details', - ) - -Each pipeline function will receive the following parameters: - * Current strategy (which gives access to current store, backend and request) - * User ID given by authentication provider - * User details given by authentication provider - * ``is_new`` flag (initialized as ``False``) - * Any arguments passed to ``auth_complete`` backend method, default views - pass these arguments: - - * current logged in user (if it's logged in, otherwise ``None``) - * current request - - -Disconnection Pipeline ----------------------- - -Like the authentication pipeline, it's possible to define a disconnection -pipeline if needed. - -For example, this can be useful on sites where a user that disconnects all the -related social account is required to fill a password to ensure the -authentication process in the future. This can be accomplished by overriding -the default disconnection pipeline and setup a function that checks if the user -has a password, in case it doesn't a redirect to a fill-your-password form can -be returned and later continue the disconnection process, take into account -that disconnection ensures the POST method by default, a simple method to -ensure this, is to make your form POST to ``/disconnect/`` and set the needed -password in your pipeline function. Check *Partial Pipeline* below. - -In order to override the disconnection pipeline, just define the setting:: - - SOCIAL_AUTH_DISCONNECT_PIPELINE = ( - # Verifies that the social association can be disconnected from the current - # user (ensure that the user login mechanism is not compromised by this - # disconnection). - 'social.pipeline.disconnect.allowed_to_disconnect', - - # Collects the social associations to disconnect. - 'social.pipeline.disconnect.get_entries', - - # Revoke any access_token when possible. - 'social.pipeline.disconnect.revoke_tokens', - - # Removes the social associations. - 'social.pipeline.disconnect.disconnect', - ) - - -Partial Pipeline ----------------- - -It's possible to cut the pipeline process to return to the user asking for more -data and resume the process later. To accomplish this decorate the function -that will cut the process with the ``@partial`` decorator located at -``social/pipeline/partial.py``. - -The old ``social.pipeline.partial.save_status_to_session`` is now deprecated. - -When it's time to resume the process just redirect the user to ``/complete//`` -or ``/disconnect//`` view. The pipeline will resume in the same -function that cut the process. - -``@partial`` and ``save_status_to_session`` stores needed data into user session -under the key ``partial_pipeline``. To get the backend in order to redirect to -any social view, just do:: - - backend = session['partial_pipeline']['backend'] - -Check the `example applications`_ to check a basic usage. - - -Email validation ----------------- - -There's a pipeline to validate email addresses, but it relies a lot on your -project. - -The pipeline is at ``social.pipeline.mail.mail_validation`` and it's a partial -pipeline, it will return a redirect to a URL that you can use to tell the -users that an email validation was sent to them. If you want to mention the -email address you can get it from the session under the key ``email_validation_address``. - -In order to send the validation python-social-auth_ needs a function that will -take care of it, this function is defined by the developer with the setting -``SOCIAL_AUTH_EMAIL_VALIDATION_FUNCTION``. It should be an import path. This -function should take three arguments ``strategy``, ``backend`` and ``code``. -``code`` is a model instance used to validate the email address, it contains -three fields: - -``code = '...'`` - Holds an ``uuid.uuid4()`` value and it's the code used to identify the - validation process. - -``email = '...'`` - Email address trying to be validate. - -``verified = True / False`` - Flag marking if the email was verified or not. - -You should use the code in this instance to build the link for email -validation which should go to ``/complete/email?verification_code=``. If you are using -Django, you can do it with:: - - from django.core.urlresolvers import reverse - url = strategy.build_absolute_uri( - reverse('social:complete', args=(strategy.backend_name,)) - ) + '?verification_code=' + code.code - -On Flask:: - - from flask import url_for - url = url_for('social.complete', backend=strategy.backend_name, - _external=True) + '?verification_code=' + code - -This pipeline can be used globally with any backend if this setting is -defined:: - - SOCIAL_AUTH_FORCE_EMAIL_VALIDATION = True - -Or individually by defining the setting per backend basis like -``SOCIAL_AUTH_TWITTER_FORCE_EMAIL_VALIDATION = True``. - - -Extending the Pipeline -====================== - -The main purpose of the pipeline (either creation or deletion pipelines) is to -allow extensibility for developers. You can jump in the middle of it, do -changes to the data, create other models instances, ask users for extra data, -or even halt the whole process. - -Extending the pipeline implies: - - 1. Writing a function - 2. Locating the function in an accessible path - (accessible in the way that it can be imported) - 3. Overriding the default pipeline definition with one that includes - newly created function. - -The part of writing the function is quite simple. However please be careful -when placing your function in the pipeline definition, because order -does matter in this case! Ordering of functions in ``SOCIAL_AUTH_PIPELINE`` -will determine the value of arguments that each function will receive. -For example, adding your function after ``social.pipeline.user.create_user`` -ensures that your function will get the user instance (created or already existent) -instead of a ``None`` value. - -The pipeline functions will get quite a lot of arguments, ranging from the -backend in use, different model instances, server requests and provider -responses. To enumerate a few: - -``strategy`` - The current strategy instance. - -``backend`` - The current backend instance. - -``uid`` - User ID in the provider, this ``uid`` should identify the user in the - current provider. - -``response = {} or object()`` - The server user-details response, it depends on the protocol in use (and - sometimes the provider implementation of such protocol), but usually it's - just a ``dict`` with the user profile details in such provider. Lots of - information related to the user is provided here, sometimes the ``scope`` - will increase the amount of information in this response on OAuth - providers. - -``details = {}`` - Basic user details generated by the backend, used to create/update the user - model details (this ``dict`` will contain values like ``username``, - ``email``, ``first_name``, ``last_name`` and ``fullname``). - -``user = None`` - The user instance (or ``None`` if it wasn't created or retrieved from the - database yet). - -``social = None`` - This is the associated ``UserSocialAuth`` instance for the given user (or - ``None`` if it wasn't created or retrieved from the DB yet). - -Usually when writing your custom pipeline function, you just want to get some -values from the ``response`` parameter. But you can do even more, like call -other APIs endpoints to retrieve even more details about the user, store them -on some other place, etc. - -Here's an example of a simple pipeline function that will create a ``Profile`` -class instance, related to the current user. This profile will store some simple details -returned by the provider (``Facebook`` in this example). The usual Facebook -``response`` looks like this:: - - { - 'username': 'foobar', - 'access_token': 'CAAD...', - 'first_name': 'Foo', - 'last_name': 'Bar', - 'verified': True, - 'name': 'Foo Bar', - 'locale': 'en_US', - 'gender': 'male', - 'expires': '5183999', - 'email': 'foo@bar.com', - 'updated_time': '2014-01-14T15:58:35+0000', - 'link': 'https://www.facebook.com/foobar', - 'timezone': -3, - 'id': '100000126636010', - } - -Let's say we are interested in storing the user profile link, the gender and -the timezone in our ``Profile`` model:: - - def save_profile(backend, user, response, *args, **kwargs): - if backend.name == 'facebook': - profile = user.get_profile() - if profile is None: - profile = Profile(user_id=user.id) - profile.gender = response.get('gender') - profile.link = response.get('link') - profile.timezone = response.get('timezone') - profile.save() - -Now all that's needed is to tell ``python-social-auth`` to use our function in -the pipeline. Since the function uses user instance, we need to put it after -``social.pipeline.user.create_user``:: - - SOCIAL_AUTH_PIPELINE = ( - 'social.pipeline.social_auth.social_details', - 'social.pipeline.social_auth.social_uid', - 'social.pipeline.social_auth.auth_allowed', - 'social.pipeline.social_auth.social_user', - 'social.pipeline.user.get_username', - 'social.pipeline.user.create_user', - 'path.to.save_profile', # <--- set the path to the function - 'social.pipeline.social_auth.associate_user', - 'social.pipeline.social_auth.load_extra_data', - 'social.pipeline.user.user_details', - ) - -So far the function we created returns ``None``, which is taken as if ``{}`` was returned. -If you want the ``profile`` object to be available to the next function in the -pipeline, all you need to do is return ``{'profile': profile}``. - -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _example applications: https://github.com/omab/python-social-auth/tree/master/examples diff --git a/docs/storage.rst b/docs/storage.rst deleted file mode 100644 index e12e13bce..000000000 --- a/docs/storage.rst +++ /dev/null @@ -1,200 +0,0 @@ -Storage -======= - -Different frameworks support different ORMs, Storage solves the different -interfaces moving the common API to mixins classes. These mixins are used on -apps when defining the different models used by ``python-social-auth``. - - -Social User ------------ - -This model associates a social account data with a user in the system, it -contains the provider name and user ID (``uid``) which should identify the -social account in the remote provider, plus some extra data (``extra_data``) -which is JSON encoded field with extra information from the provider (usually -avatars and similar). - -When implementing this model, it must inherits from UserMixin_ and extend the -needed methods: - -* Username:: - - @classmethod - def get_username(cls, user): - """Return the username for given user""" - raise NotImplementedError('Implement in subclass') - - @classmethod - def username_max_length(cls): - """Return the max length for username""" - raise NotImplementedError('Implement in subclass') - -* User model:: - - @classmethod - def user_model(cls): - """Return the user model""" - raise NotImplementedError('Implement in subclass') - - @classmethod - def changed(cls, user): - """The given user instance is ready to be saved""" - raise NotImplementedError('Implement in subclass') - - @classmethod - def user_exists(cls, username): - """ - Return True/False if a User instance exists with the given arguments. - Arguments are directly passed to filter() manager method. - """ - raise NotImplementedError('Implement in subclass') - - @classmethod - def create_user(cls, username, email=None): - """Create a user with given username and (optional) email""" - raise NotImplementedError('Implement in subclass') - - @classmethod - def get_user(cls, pk): - """Return user instance for given id""" - raise NotImplementedError('Implement in subclass') - -* Social user:: - - @classmethod - def get_social_auth(cls, provider, uid): - """Return UserSocialAuth for given provider and uid""" - raise NotImplementedError('Implement in subclass') - - @classmethod - def get_social_auth_for_user(cls, user): - """Return all the UserSocialAuth instances for given user""" - raise NotImplementedError('Implement in subclass') - - @classmethod - def create_social_auth(cls, user, uid, provider): - """Create a UserSocialAuth instance for given user""" - raise NotImplementedError('Implement in subclass') - -* Social disconnection:: - - @classmethod - def allowed_to_disconnect(cls, user, backend_name, association_id=None): - """Return if it's safe to disconnect the social account for the - given user""" - raise NotImplementedError('Implement in subclass') - - @classmethod - def disconnect(cls, name, user, association_id=None): - """Disconnect the social account for the given user""" - raise NotImplementedError('Implement in subclass') - - -Nonce ------ - -This is a helper class for OpenId mechanism, it stores a one-use number, -shouldn't be used by the project since it's for internal use only. - -When implementing this model, it must inherits from NonceMixin_, and override -the needed method:: - - @classmethod - def use(cls, server_url, timestamp, salt): - """Create a Nonce instance""" - raise NotImplementedError('Implement in subclass') - - -Association ------------ - -Another OpenId helper class, it stores basic data to keep the OpenId -association. Like Nonce_ this is for internal use only. - -When implementing this model, it must inherits from AssociationMixin_, and -override the needed methods:: - - @classmethod - def store(cls, server_url, association): - """Create an Association instance""" - raise NotImplementedError('Implement in subclass') - - @classmethod - def get(cls, *args, **kwargs): - """Get an Association instance""" - raise NotImplementedError('Implement in subclass') - - @classmethod - def remove(cls, ids_to_delete): - """Remove an Association instance""" - raise NotImplementedError('Implement in subclass') - - -Validation code ---------------- - -This class is used to keep track of email validations codes following the usual -email validation mechanism of sending an email to the user with a unique code. -This model is used by the partial pipeline ``social.pipeline.mail.mail_validation``. -Check the docs at *Email validation* in `pipeline docs`_. - -When implementing the model for your framework only one method needs to be -overridden:: - - @classmethod - def get_code(cls, code): - """Return the Code instance with the given code value""" - raise NotImplementedError('Implement in subclass') - - -Storage interface ------------------ - -There's a helper class used by strategies to hide the real models names under -a common API, an instance of this class is used by strategies to access the -storage modules. - -When implementing this class it must inherits from BaseStorage_, add the needed -models references and implement the needed method:: - - class StorageImplementation(BaseStorage): - user = UserModel - nonce = NonceModel - association = AssociationModel - code = CodeModel - - @classmethod - def is_integrity_error(cls, exception): - """Check if given exception flags an integrity error in the DB""" - raise NotImplementedError('Implement in subclass') - - -SQLAlchemy and Django mixins ----------------------------- - -Currently there are partial implementations of mixins for `SQLAlchemy ORM`_ and -`Django ORM`_ with common code used later on current implemented applications. - -**When using `SQLAlchemy ORM`_ and ``ZopeTransactionExtension``, it's -recommended to use the transaction_ application to handle them.** - -Models Examples ---------------- - -Check for current implementations for `Django App`_, `Flask App`_, `Pyramid -App`_, and `Webpy App`_ for examples of implementations. - - -.. _UserMixin: https://github.com/omab/python-social-auth/blob/master/social/storage/base.py#L15 -.. _NonceMixin: https://github.com/omab/python-social-auth/blob/master/social/storage/base.py#L149 -.. _AssociationMixin: https://github.com/omab/python-social-auth/blob/master/social/storage/base.py#L161 -.. _BaseStorage: https://github.com/omab/python-social-auth/blob/master/social/storage/base.py#L201 -.. _SQLAlchemy ORM: https://github.com/omab/python-social-auth/blob/master/social/storage/sqlalchemy_orm.py -.. _Django ORM: https://github.com/omab/python-social-auth/blob/master/social/storage/django_orm.py -.. _Django App: https://github.com/omab/python-social-auth/blob/master/social/apps/django_app/default/models.py -.. _Flask App: https://github.com/omab/python-social-auth/blob/master/social/apps/flask_app/models.py -.. _Pyramid App: https://github.com/omab/python-social-auth/blob/master/social/apps/pyramid_app/models.py -.. _Webpy App: https://github.com/omab/python-social-auth/blob/master/social/apps/webpy_app/models.py -.. _pipeline docs: pipeline.html#email-validation -.. _transaction: https://pypi.python.org/pypi/transaction diff --git a/docs/strategies.rst b/docs/strategies.rst deleted file mode 100644 index 72e014e5c..000000000 --- a/docs/strategies.rst +++ /dev/null @@ -1,77 +0,0 @@ -Strategies -========== - -Different strategies are defined to encapsulate the different frameworks -capabilities under a common API to reuse as much code as possible. - - -Description ------------ - -A strategy's responsibility is to provide access to: - - * Request data and host information and URI building - * Session access - * Project settings - * Response types (HTML and redirects) - * HTML rendering - -Different frameworks implement these features on different ways, thus the need -for these interfaces. - - -Implementing a new Strategy ---------------------------- - -The following methods must be defined on strategies sub-classes. - -Request:: - - def request_data(self): - """Return current request data (POST or GET)""" - raise NotImplementedError('Implement in subclass') - - def request_host(self): - """Return current host value""" - raise NotImplementedError('Implement in subclass') - - def build_absolute_uri(self, path=None): - """Build absolute URI with given (optional) path""" - raise NotImplementedError('Implement in subclass') - - -Session:: - - def session_get(self, name): - """Return session value for given key""" - raise NotImplementedError('Implement in subclass') - - def session_set(self, name, value): - """Set session value for given key""" - raise NotImplementedError('Implement in subclass') - - def session_pop(self, name): - """Pop session value for given key""" - raise NotImplementedError('Implement in subclass') - - -Settings:: - - def get_setting(self, name): - """Return value for given setting name""" - raise NotImplementedError('Implement in subclass') - - -Responses:: - - def html(self, content): - """Return HTTP response with given content""" - raise NotImplementedError('Implement in subclass') - - def redirect(self, url): - """Return a response redirect to the given URL""" - raise NotImplementedError('Implement in subclass') - - def render_html(self, tpl=None, html=None, context=None): - """Render given template or raw html with given context""" - raise NotImplementedError('Implement in subclass') diff --git a/docs/tests.rst b/docs/tests.rst deleted file mode 100644 index 656f483af..000000000 --- a/docs/tests.rst +++ /dev/null @@ -1,48 +0,0 @@ -Testing python-social-auth -========================== - -Testing the application is fair simple, just met the dependencies and run the -testing suite. - -The testing suite uses HTTPretty_ to mock server responses, it's not a live -test against the providers API, to do it that way, a browser and a tool like -Selenium are needed, that's slow, prone to errors on some cases, and some of -the application examples must be running to perform the testing. Plus real Key -and Secret pairs, in the end it's a mess to test functionality which is the -real point. - -By mocking the server responses, we can test the backends functionality (and -other areas too) easily and quick. - - -Installing dependencies ------------------------ - -Go to the tests_ directory and install the dependencies listed in the -requirements.txt_. Then run with ``nosetests`` command, or with the -``run_tests.sh`` script. - -Tox ---- - -You can use tox_ to test compatibility against all supported Python versions: - -.. code-block:: bash - - $ pip install tox # if not present - $ tox - - -Pending -------- - -At the moment only OAuth1, OAuth2 and OpenId backends are being tested, and -just login and partial pipeline features are covered by the test. There's still -a lot to work on, like: - - * Frameworks support - -.. _HTTPretty: https://github.com/gabrielfalcao/HTTPretty -.. _tests: https://github.com/omab/python-social-auth/tree/master/tests -.. _requirements.txt: https://github.com/omab/python-social-auth/blob/master/tests/requirements.txt -.. _tox: http://tox.readthedocs.org/ diff --git a/docs/thanks.rst b/docs/thanks.rst deleted file mode 100644 index 46d7a2078..000000000 --- a/docs/thanks.rst +++ /dev/null @@ -1,219 +0,0 @@ -Thanks -====== - - -python-social-auth_ is the result of almost 3 years of development done on -django-social-auth_ which is the result of my initial work and the thousands -lines of code contributed by so many developers that took time to work on -improvements, report bugs and hunt them down to propose a fix. So, here is -a big list of users that helped to build this library (if somebody is missed -let me know and I'll update the list): - - * kjoconnor_ - * krvss_ - * estebistec_ - * mrmch_ - * uruz_ - * maraujop_ - * bacher09_ - * dokterbob_ - * hassek_ - * andrusha_ - * vicalloy_ - * caioariede_ - * danielgtaylor_ - * stephenmcd_ - * gugu_ - * yrik_ - * dhendo_ - * yekibud_ - * tmackenzie_ - * LuanP_ - * jezdez_ - * serdardalgic_ - * Jolmberg_ - * ChrisCooper_ - * marselester_ - * eshellman_ - * micrypt_ - * revolunet_ - * dasevilla_ - * seansay_ - * hepochen_ - * gibuloto_ - * crodjer_ - * sidmitra_ - * ryr_ - * inve1_ - * mback2k_ - * hannesstruss_ - * NorthIsUp_ - * tonyxiao_ - * dhepper_ - * Troytft_ - * gardaud_ - * oinopion_ - * gameguy43_ - * vinigracindo_ - * syabro_ - * bashmish_ - * ggreer_ - * avillavi_ - * r4vi_ - * roderyc_ - * daonb_ - * slon7_ - * JasonGiedymin_ - * tymofij_ - * Cassus_ - * martey_ - * t0m_ - * johnthedebs_ - * jammons_ - * stefanw_ - * maxgrosse_ - * mattucf_ - * tadeo_ - * haxoza_ - * bradbeattie_ - * henward0_ - * bernardokyotoku_ - * czpython_ - * glasscube42_ - * assiotis_ - * dbaxa_ - * JasonSanford_ - * originell_ - * cihann_ - * niftynei_ - * mikesun_ - * 1st_ - * betonimig_ - * ozexpert_ - * stephenLee_ - * julianvargasalvarez_ - * youngrok_ - * garrypolley_ - * amirouche_ - * fmoga_ - * pydanny_ - * pygeek_ - * dgouldin_ - * kotslon_ - * kirkchris_ - * barracel_ - * sayar_ - * kulbir_ - * Morgul_ - * spstpl_ - * bluszcz_ - * vbsteven_ - * sbassi_ - * aspcanada_ - * browniebroke_ - - -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _django-social-auth: https://github.com/omab/django-social-auth -.. _kjoconnor: https://github.com/kjoconnor -.. _krvss: https://github.com/krvss -.. _estebistec: https://github.com/estebistec -.. _mrmch: https://github.com/mrmch -.. _uruz: https://github.com/uruz -.. _maraujop: https://github.com/maraujop -.. _bacher09: https://github.com/bacher09 -.. _dokterbob: https://github.com/dokterbob -.. _hassek: https://github.com/hassek -.. _andrusha: https://github.com/andrusha -.. _vicalloy: https://github.com/vicalloy -.. _caioariede: https://github.com/caioariede -.. _danielgtaylor: https://github.com/danielgtaylor -.. _stephenmcd: https://github.com/stephenmcd -.. _gugu: https://github.com/gugu -.. _yrik: https://github.com/yrik -.. _dhendo: https://github.com/dhendo -.. _yekibud: https://github.com/yekibud -.. _tmackenzie: https://github.com/tmackenzie -.. _LuanP: https://github.com/LuanP -.. _jezdez: https://github.com/jezdez -.. _serdardalgic: https://github.com/serdardalgic -.. _Jolmberg: https://github.com/Jolmberg -.. _ChrisCooper: https://github.com/ChrisCooper -.. _marselester: https://github.com/marselester -.. _eshellman: https://github.com/eshellman -.. _micrypt: https://github.com/micrypt -.. _revolunet: https://github.com/revolunet -.. _dasevilla: https://github.com/dasevilla -.. _seansay: https://github.com/seansay -.. _hepochen: https://github.com/hepochen -.. _gibuloto: https://github.com/gibuloto -.. _crodjer: https://github.com/crodjer -.. _sidmitra: https://github.com/sidmitra -.. _ryr: https://github.com/ryr -.. _inve1: https://github.com/inve1 -.. _mback2k: https://github.com/mback2k -.. _hannesstruss: https://github.com/hannesstruss -.. _NorthIsUp: https://github.com/NorthIsUp -.. _tonyxiao: https://github.com/tonyxiao -.. _dhepper: https://github.com/dhepper -.. _Troytft: https://github.com/Troytft -.. _gardaud: https://github.com/gardaud -.. _oinopion: https://github.com/oinopion -.. _gameguy43: https://github.com/gameguy43 -.. _vinigracindo: https://github.com/vinigracindo -.. _syabro: https://github.com/syabro -.. _bashmish: https://github.com/bashmish -.. _ggreer: https://github.com/ggreer -.. _avillavi: https://github.com/avillavi -.. _r4vi: https://github.com/r4vi -.. _roderyc: https://github.com/roderyc -.. _daonb: https://github.com/daonb -.. _slon7: https://github.com/slon7 -.. _JasonGiedymin: https://github.com/JasonGiedymin -.. _tymofij: https://github.com/tymofij -.. _Cassus: https://github.com/Cassus -.. _martey: https://github.com/martey -.. _t0m: https://github.com/t0m -.. _johnthedebs: https://github.com/johnthedebs -.. _jammons: https://github.com/jammons -.. _stefanw: https://github.com/stefanw -.. _maxgrosse: https://github.com/maxgrosse -.. _mattucf: https://github.com/mattucf -.. _tadeo: https://github.com/tadeo -.. _haxoza: https://github.com/haxoza -.. _bradbeattie: https://github.com/bradbeattie -.. _henward0: https://github.com/henward0 -.. _bernardokyotoku: https://github.com/bernardokyotoku -.. _czpython: https://github.com/czpython -.. _glasscube42: https://github.com/glasscube42 -.. _assiotis: https://github.com/assiotis -.. _dbaxa: https://github.com/dbaxa -.. _JasonSanford: https://github.com/JasonSanford -.. _originell: https://github.com/originell -.. _cihann: https://github.com/cihann -.. _niftynei: https://github.com/niftynei -.. _mikesun: https://github.com/mikesun -.. _1st: https://github.com/1st -.. _betonimig: https://github.com/betonimig -.. _ozexpert: https://github.com/ozexpert -.. _stephenLee: https://github.com/stephenLee -.. _julianvargasalvarez: https://github.com/julianvargasalvarez -.. _youngrok: https://github.com/youngrok -.. _garrypolley: https://github.com/garrypolley -.. _amirouche: https://github.com/amirouche -.. _fmoga: https://github.com/fmoga -.. _pydanny: https://github.com/pydanny -.. _pygeek: https://github.com/pygeek -.. _dgouldin: https://github.com/dgouldin -.. _kotslon: https://github.com/kotslon -.. _kirkchris: https://github.com/kirkchris -.. _barracel: https://github.com/barracel -.. _sayar: https://github.com/sayar -.. _kulbir: https://github.com/kulbir -.. _Morgul: https://github.com/Morgul -.. _spstpl: https://github.com/spstpl -.. _bluszcz: https://github.com/bluszcz -.. _vbsteven: https://github.com/vbsteven -.. _sbassi: https://github.com/sbassi -.. _aspcanada: https://github.com/aspcanada -.. _browniebroke: https://github.com/browniebroke diff --git a/docs/use_cases.rst b/docs/use_cases.rst deleted file mode 100644 index 4f7c92641..000000000 --- a/docs/use_cases.rst +++ /dev/null @@ -1,312 +0,0 @@ -Use Cases -========= - -Some miscellaneous options and use cases for python-social-auth_. - - -Return the user to the original page ------------------------------------- - -There's a common scenario to return the user back to the original page from -where they requested to login. For that purpose, the usual ``next`` query-string -argument is used. The value of this parameter will be stored in the session and -later used to redirect the user when login was successful. - -In order to use it, just define it with your link. For instance, when using -Django:: - - Login with Facebook - - -Pass custom GET/POST parameters and retrieve them on authentication -------------------------------------------------------------------- - -In some cases, you might need to send data over the URL, and retrieve it while -processing the after-effect. For example, for conditionally executing code in -custom pipelines. - -In such cases, add it to ``FIELDS_STORED_IN_SESSION``. - -In your settings:: - - FIELDS_STORED_IN_SESSION = ['key'] - -In template:: - - Login with Facebook - -In your custom pipeline, retrieve it using:: - - strategy.session_get('key') - - - -Retrieve Google+ Friends ------------------------- - -Google provides a `People API endpoint`_ to retrieve the people in your circles -on Google+. In order to access that API first we need to define the needed -scope:: - - SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [ - 'https://www.googleapis.com/auth/plus.login' - ] - -Once we have the ``access token`` we can call the API like this:: - - import requests - - user = User.objects.get(...) - social = user.social_auth.get(provider='google-oauth2') - response = requests.get( - 'https://www.googleapis.com/plus/v1/people/me/people/visible', - params={'access_token': social.extra_data['access_token']} - ) - friends = response.json()['items'] - - -Associate users by email ------------------------- - -Sometimes it's desirable that social accounts are automatically associated if -the email already matches a user account. - -For example, if a user signed up with his Facebook account, then logged out and -next time tries to use Google OAuth2 to login, it could be nice (if both social -sites have the same email address configured) that the user gets into his -initial account created by Facebook backend. - -This scenario is possible by enabling the ``associate_by_email`` pipeline -function, like this:: - - SOCIAL_AUTH_PIPELINE = ( - 'social.pipeline.social_auth.social_details', - 'social.pipeline.social_auth.social_uid', - 'social.pipeline.social_auth.auth_allowed', - 'social.pipeline.social_auth.social_user', - 'social.pipeline.user.get_username', - 'social.pipeline.social_auth.associate_by_email', # <--- enable this one - 'social.pipeline.user.create_user', - 'social.pipeline.social_auth.associate_user', - 'social.pipeline.social_auth.load_extra_data', - 'social.pipeline.user.user_details', - ) - -This feature is disabled by default because it's not 100% secure to automate -this process with all the backends. Not all the providers will validate your -email account and others users could take advantage of that. - -Take for instance User A registered in your site with the email -``foo@bar.com``. Then a malicious user registers into another provider that -doesn't validate his email with that same account. Finally this user will turn -to your site (which supports that provider) and sign up to it, since the email -is the same, the malicious user will take control over the User A account. - - -Signup by OAuth access_token ----------------------------- - -It's a common scenario that mobile applications will use an SDK to signup -a user within the app, but that signup won't be reflected by -python-social-auth_ unless the corresponding database entries are created. In -order to do so, it's possible to create a view / route that creates those -entries by a given ``access_token``. Take the following code for instance (the -code follows Django conventions, but versions for others frameworks can be -implemented easily):: - - from django.contrib.auth import login - - from social.apps.django_app.utils import psa - - # Define an URL entry to point to this view, call it passing the - # access_token parameter like ?access_token=. The URL entry must - # contain the backend, like this: - # - # url(r'^register-by-token/(?P[^/]+)/$', - # 'register_by_access_token') - - @psa('social:complete') - def register_by_access_token(request, backend): - # This view expects an access_token GET parameter, if it's needed, - # request.backend and request.strategy will be loaded with the current - # backend and strategy. - token = request.GET.get('access_token') - user = request.backend.do_auth(request.GET.get('access_token')) - if user: - login(request, user) - return 'OK' - else: - return 'ERROR' - -The snippet above is quite simple, it doesn't return JSON and usually this call -will be done by AJAX. It doesn't return the user information, but that's -something that can be extended and filled to suit the project where it's going -to be used. - - -Multiple scopes per provider ----------------------------- - -At the moment python-social-auth_ doesn't provide a method to define multiple -scopes for single backend, this is usually desired since it's recommended to -ask the user for the minimum scope possible and increase the access when it's -really needed. It's possible to add a new backend extending the original one to -accomplish that behavior. There are two ways to do it. - -1. Overriding ``get_scope()`` method:: - - from social.backends.facebook import FacebookOAuth2 - - - class CustomFacebookOAuth2(FacebookOauth2): - def get_scope(self): - scope = super(CustomFacebookOAuth2, self).get_scope() - if self.data.get('extrascope'): - scope = scope + [('foo', 'bar')] - return scope - - - This method is quite simple, it overrides the method that returns the scope - value in a backend (``get_scope()``) and adds extra values tot he list if it - was indicated by a parameter in the ``GET`` or ``POST`` data - (``self.data``). - - Put this new backend in some place in your project and replace the original - ``FacebookOAuth2`` in ``AUTHENTICATION_BACKENDS`` with this new version. - - When overriding this method, take into account that the default output the - base class for ``get_scope()`` is the raw value from the settings (whatever - they are defined), doing this will actually update the value in your - settings for all the users:: - - scope = super(CustomFacebookOAuth2, self).get_scope() - scope += ['foo', 'bar'] - - Instead do it like this:: - - scope = super(CustomFacebookOAuth2, self).get_scope() - scope = scope + ['foo', 'bar'] - -2. It's possible to do the same by defining a second backend which extends from - the original but overrides the name, this will imply new URLs and also new - settings for the new backend (since the name is used to build the settings - names), it also implies a new application in the provider since not all - providers give you the option of defining multiple redirect URLs. To do it - just add a backend like:: - - from social.backends.facebook import FacebookOAuth2 - - - class CustomFacebookOAuth2(FacebookOauth2): - name = 'facebook-custom' - - Put this new backend in some place in your project keeping the original - ``FacebookOAuth2`` in ``AUTHENTICATION_BACKENDS``. Now a new set of URLs - will be functional:: - - /login/facebook-custom - /complete/facebook-custom - /disconnect/facebook-custom - - And also a new set of settings:: - - SOCIAL_AUTH_FACEBOOK_CUSTOM_KEY = '...' - SOCIAL_AUTH_FACEBOOK_CUSTOM_SECRET = '...' - SOCIAL_AUTH_FACEBOOK_CUSTOM_SCOPE = [...] - - When the extra permissions are needed, just redirect the user to - ``/login/facebook-custom`` and then get the social auth entry for this new - backend with ``user.social_auth.get(provider='facebook-custom')`` and use - the ``access_token`` in it. - - -Enable a user to choose a username from his World of Warcraft characters ------------------------------------------------------------------------- - -If you want to register new users on your site via battle.net, you can enable -these users to choose a username from their own World-of-Warcraft characters. -To do this, use the ``battlenet-oauth2`` backend along with a small form to -choose the username. - -The form is rendered via a partial pipeline item like this:: - - @partial - def pick_character_name(backend, details, response, is_new=False, *args, **kwargs): - if backend.name == 'battlenet-oauth2' and is_new: - data = backend.strategy.request_data() - if data.get('character_name') is None: - # New user and didn't pick a character name yet, so we render - # and send a form to pick one. The form must do a POST/GET - # request to the same URL (/complete/battlenet-oauth2/). In this - # example we expect the user option under the key: - # character_name - # you have to filter the result list according to your needs. - # In this example, only guild members are allowed to sign up. - char_list = [ - c['name'] for c in backend.get_characters(response.get('access_token')) - if 'guild' in c and c['guild'] == '' - ] - return render_to_response('pick_character_form.html', {'charlist': char_list, }) - else: - # The user selected a character name - return {'username': data.get('character_name')} - -Don't forget to add the partial to the pipeline:: - - SOCIAL_AUTH_PIPELINE = ( - 'social.pipeline.social_auth.social_details', - 'social.pipeline.social_auth.social_uid', - 'social.pipeline.social_auth.auth_allowed', - 'social.pipeline.social_auth.social_user', - 'social.pipeline.user.get_username', - 'path.to.pick_character_name', - 'social.pipeline.user.create_user', - 'social.pipeline.social_auth.associate_user', - 'social.pipeline.social_auth.load_extra_data', - 'social.pipeline.user.user_details', - ) - -It needs to be somewhere before create_user because the partial will change the -username according to the users choice. - - -Re-prompt Google OAuth2 users to refresh the ``refresh_token`` --------------------------------------------------------------- - -A ``refresh_token`` also expire, a ``refresh_token`` can be lost, but they can -also be refreshed (or re-fetched) if you ask to Google the right way. In order -to do so, set this setting:: - - SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = { - 'access_type': 'offline', - 'approval_prompt': 'auto' - } - -Then link the users to ``/login/google-oauth2?approval_prompt=force``. If you -want to refresh the ``refresh_token`` only on those users that don't have it, -do it with a pipeline function:: - - def redirect_if_no_refresh_token(backend, response, social, *args, **kwargs): - if backend.name == 'google-oauth2' and social and \ - response.get('refresh_token') is None and \ - social.extra_data.get('refresh_token') is None: - return redirect('/login/google-oauth2?approval_prompt=force') - -Set this pipeline after ``social_user``:: - - SOCIAL_AUTH_PIPELINE = ( - 'social.pipeline.social_auth.social_details', - 'social.pipeline.social_auth.social_uid', - 'social.pipeline.social_auth.auth_allowed', - 'social.pipeline.social_auth.social_user', - 'path.to.redirect_if_no_refresh_token', - 'social.pipeline.user.get_username', - 'social.pipeline.user.create_user', - 'social.pipeline.social_auth.associate_user', - 'social.pipeline.social_auth.load_extra_data', - 'social.pipeline.user.user_details', - ) - - -.. _python-social-auth: https://github.com/omab/python-social-auth -.. _People API endpoint: https://developers.google.com/+/api/latest/people/list diff --git a/requirements-python3.txt b/requirements-python3.txt index a126ab21b..4e8d6b68a 100644 --- a/requirements-python3.txt +++ b/requirements-python3.txt @@ -1,20 +1 @@ -python3-openid>=3.0.9 -requests>=2.9.1 -oauthlib>=1.0.3 -requests-oauthlib>=0.6.1 -six>=1.10.0 -PyJWT>=1.4.0 social-auth-core -social-auth-storage-mongoengine -social-auth-storage-peewee -social-auth-storage-sqlalchemy -social-auth-app-cherrypy -social-auth-app-django -social-auth-app-django-mongoengine -social-auth-app-flask -social-auth-app-flask-mongoengine -social-auth-app-flask-peewee -social-auth-app-flask-sqlalchemy -social-auth-app-pyramid -social-auth-app-tornado -social-auth-app-webpy diff --git a/site/css/bootstrap-responsive.min.css b/site/css/bootstrap-responsive.min.css deleted file mode 100644 index 059786010..000000000 --- a/site/css/bootstrap-responsive.min.css +++ /dev/null @@ -1,9 +0,0 @@ -/*! - * Bootstrap Responsive v2.3.0 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/site/css/bootstrap.min.css b/site/css/bootstrap.min.css deleted file mode 100644 index fd5ed7340..000000000 --- a/site/css/bootstrap.min.css +++ /dev/null @@ -1,9 +0,0 @@ -/*! - * Bootstrap v2.3.0 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} diff --git a/site/css/site.css b/site/css/site.css deleted file mode 100644 index 0292b3b71..000000000 --- a/site/css/site.css +++ /dev/null @@ -1,4 +0,0 @@ -body { - padding-top: 60px; - padding-bottom: 40px; -} diff --git a/site/docs b/site/docs deleted file mode 120000 index 16bfa418b..000000000 --- a/site/docs +++ /dev/null @@ -1 +0,0 @@ -../docs/_build/ \ No newline at end of file diff --git a/site/img/glyphicons-halflings-white.png b/site/img/glyphicons-halflings-white.png deleted file mode 100644 index 3bf6484a2..000000000 Binary files a/site/img/glyphicons-halflings-white.png and /dev/null differ diff --git a/site/img/glyphicons-halflings.png b/site/img/glyphicons-halflings.png deleted file mode 100644 index a99699932..000000000 Binary files a/site/img/glyphicons-halflings.png and /dev/null differ diff --git a/site/index.html b/site/index.html deleted file mode 100644 index 230537bb5..000000000 --- a/site/index.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - Python Social Auth - - - - - - - - - -
    -
    -

    Python Social Auth

    -

    - Python Social Auth is an easy to setup social authentication/registration - mechanism with support for several frameworks and auth providers. -

    - -

    - Crafted using base code from django-social-auth, implements a common interface - to define new authentication providers from third parties. And to bring support - for more frameworks and ORMs. -

    -

    Learn more »

    -
    - -
    -
    -

    Frameworks

    -

    - The lib supports a few frameworks at the moment with Django, - Flask, Pyramid, - Webpy, CherryPy and - Tornado and more to come. The frameworks API - should ease the implementation to increase the number of frameworks supported. -

    -

    View details »

    -
    - -
    -

    Authentication Providers

    -

    - Ported from django-social-auth, the application - brings plenty of authentication providers, many from popular services like Google, - Facebook, Twitter and - Github. The backends API - have some implementation details on how to implement your own backends. -

    -

    View details »

    -
    -
    - -
    -
    -

    ORMs

    -

    - There are multiple ORM python libraries around, - some frameworks has their own built-in version too. python-social-auth - tries to support the different interfaces available, at the moment SQLAlchemy, - Django ORM and Mongoengine - are supported, but with the Storage API it should be easy to add more support. -

    -

    View details »

    -
    - -
    -

    Development and Contact

    -

    - The code is available on Github, report any - issue if you find any. Pull requests are - always welcome. There's a mailing list - and IRC channel #python-social-auth on Freenode network. -

    -

    View details »

    -
    -
    - -
    - -
    -

    © Matías Aguirre 2012

    -
    -
    - - - - - diff --git a/site/js/bootstrap.min.js b/site/js/bootstrap.min.js deleted file mode 100644 index e05923da8..000000000 --- a/site/js/bootstrap.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! -* Bootstrap.js by @fat & @mdo -* Copyright 2012 Twitter, Inc. -* http://www.apache.org/licenses/LICENSE-2.0.txt -*/ -!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||s.toggleClass("open"),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);if(!n.options.delay||!n.options.delay.show)return n.show();clearTimeout(this.timeout),n.hoverState="in",this.timeout=setTimeout(function(){n.hoverState=="in"&&n.show()},n.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'
    ',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'

    '}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery); \ No newline at end of file diff --git a/social/__init__.py b/social/__init__.py index 8766fd5a1..0f1326029 100644 --- a/social/__init__.py +++ b/social/__init__.py @@ -2,6 +2,6 @@ python-social-auth application, allows OpenId or OAuth user registration/authentication just adding a few configurations. """ -version = (0, 2, 21) +version = (0, 3, 0) extra = '' __version__ = '.'.join(map(str, version)) + extra diff --git a/tox.ini b/tox.ini index 0ddc92f13..f109b3d46 100644 --- a/tox.ini +++ b/tox.ini @@ -21,8 +21,3 @@ deps = -r{toxinidir}/social/tests/requirements-python3.txt [testenv:py35] deps = -r{toxinidir}/social/tests/requirements-python3.txt - -[testenv:doc] -changedir = docs -deps = sphinx -commands = sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html