Permalink
Browse files

Added initial version of Flask-OAuth

  • Loading branch information...
0 parents commit 5c4df6dd756837272c140bff5e068852e616534f @mitsuhiko committed May 8, 2010
3 .gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+*.pyc
+*.pyo
3 .gitmodules
@@ -0,0 +1,3 @@
+[submodule "docs/_themes"]
+ path = docs/_themes
+ url = git://github.com/mitsuhiko/flask-sphinx-themes.git
31 LICENSE
@@ -0,0 +1,31 @@
+Copyright (c) 2010 by Armin Ronacher.
+
+Some rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+* The names of the contributors may not be used to endorse or
+ promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3 README
@@ -0,0 +1,3 @@
+Flask-OAuth
+
+Description goes here
130 docs/Makefile
@@ -0,0 +1,130 @@
+# 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 <target>' where <target> 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/Flask-OAuth.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Flask-OAuth.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/Flask-OAuth"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Flask-OAuth"
+ @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 all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+
+latexpdf: latex
+ $(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."
1 docs/_themes
@@ -0,0 +1 @@
+Subproject commit 584d7a19366cac4e690e3ce926d7253e3ed050b7
214 docs/conf.py
@@ -0,0 +1,214 @@
+# -*- coding: utf-8 -*-
+#
+# Flask-OAuth documentation build configuration file, created by
+# sphinx-quickstart on Sat May 8 13:26:52 2010.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.append(os.path.abspath('_themes'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Flask-OAuth'
+copyright = u'2010, Armin Ronacher'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.9'
+# The full version, including alpha/beta/rc tags.
+release = '0.9'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+#pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'flask_small'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ['_themes']
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Flask-OAuthdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'Flask-OAuth.tex', u'Flask-OAuth Documentation',
+ u'Armin Ronacher', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'flask-oauth', u'Flask-OAuth Documentation',
+ [u'Armin Ronacher'], 1)
+]
+
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'http://docs.python.org/': None}
20 docs/index.rst
@@ -0,0 +1,20 @@
+.. Flask-OAuth documentation master file, created by
+ sphinx-quickstart on Sat May 8 13:26:52 2010.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to Flask-OAuth's documentation!
+=======================================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
155 docs/make.bat
@@ -0,0 +1,155 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> 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. text to make text files
+ echo. man to make manual pages
+ echo. changes to make an overview over 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
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "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.
+ goto end
+)
+
+if "%1" == "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\Flask-OAuth.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Flask-OAuth.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "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.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
BIN example/static/openid.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN example/static/sign-in.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 example/static/style.css
@@ -0,0 +1,49 @@
+body {
+ font-family: 'Georgia', serif;
+ font-size: 16px;
+ margin: 30px;
+ padding: 0;
+}
+
+img {
+ border: none;
+}
+
+a {
+ color: #335E79;
+}
+
+p.message {
+ color: #335E79;
+ padding: 10px;
+ background: #CADEEB;
+}
+
+p.error {
+ color: #783232;
+ padding: 10px;
+ background: #EBCACA;
+}
+
+input {
+ font-family: 'Georgia', serif;
+ font-size: 16px;
+ border: 1px solid black;
+ color: #335E79;
+ padding: 2px;
+}
+
+input[type="submit"] {
+ background: #CADEEB;
+ color: #335E79;
+ border-color: #335E79;
+}
+
+input[name="openid"] {
+ background: url(openid.png) 4px no-repeat;
+ padding-left: 24px;
+}
+
+h1, h2 {
+ font-weight: normal;
+}
19 example/templates/index.html
@@ -0,0 +1,19 @@
+{% extends "layout.html" %}
+{% block body %}
+ <h2>Overview</h2>
+ {% if g.user %}
+ <p>
+ Hello {{ g.user.name }}! Wanna tweet something?
+ <form action="{{ url_for('tweet') }}" method=post>
+ <p>
+ <input type=text name=tweet size=40>
+ <input type=submit value="Tweet!">
+ </form>
+ {% else %}
+ <p>
+ <a href="{{ url_for('login') }}"><img src="{{
+ url_for('static', filename='sign-in.png') }}" alt="sign in"></a>
+ {% endif %}
+ <p>
+ This is just an example page so that something is here.
+{% endblock %}
17 example/templates/layout.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>{% block title %}Welcome{% endblock %} | Flask OAuth Example</title>
+<link rel=stylesheet type=text/css href="{{ url_for('static',
+ filename='style.css') }}">
+<h1>Flask OAuth Example</h1>
+<ul class=navigation>
+ <li><a href="{{ url_for('index') }}">overview</a>
+ {% if g.user %}
+ <li><a href="{{ url_for('logout') }}">sign out [{{ g.user.name }}]</a>
+ {% else %}
+ <li><a href="{{ url_for('login') }}">sign in</a>
+ {% endif %}
+</ul>
+{% for message in get_flashed_messages() %}
+ <p class=message>{{ message }}
+{% endfor %}
+{% block body %}{% endblock %}
125 example/tweet.py
@@ -0,0 +1,125 @@
+from flask import Flask, request, redirect, url_for, session, flash, g, \
+ render_template
+from flaskext.oauth import OAuth
+
+from sqlalchemy import create_engine, Column, Integer, String
+from sqlalchemy.orm import scoped_session, sessionmaker
+from sqlalchemy.ext.declarative import declarative_base
+
+# configuration
+DATABASE_URI = 'sqlite:////tmp/flask-oauth.db'
+SECRET_KEY = 'development key'
+DEBUG = True
+
+# setup flask
+app = Flask(__name__)
+app.debug = DEBUG
+app.secret_key = SECRET_KEY
+oauth = OAuth()
+
+# Use Twitter as example remote application
+twitter = oauth.remote_app('twitter',
+ base_url='http://api.twitter.com/1/',
+ request_token_url='http://api.twitter.com/oauth/request_token',
+ access_token_url='http://api.twitter.com/oauth/access_token',
+ authorize_url='http://api.twitter.com/oauth/authenticate',
+ consumer_key='xBeXxg9lyElUgwZT6AZ0A',
+ consumer_secret='aawnSpNTOVuDCjx7HMh6uSXetjNN8zWLpZwCEU4LBrk'
+)
+
+# setup sqlalchemy
+engine = create_engine(DATABASE_URI)
+db_session = scoped_session(sessionmaker(autocommit=False,
+ autoflush=False,
+ bind=engine))
+Base = declarative_base()
+Base.query = db_session.query_property()
+
+def init_db():
+ Base.metadata.create_all(bind=engine)
+
+
+class User(Base):
+ __tablename__ = 'users'
+ id = Column('user_id', Integer, primary_key=True)
+ name = Column(String(60))
+ oauth_token = Column(String(200))
+ oauth_secret = Column(String(200))
+
+ def __init__(self, name, oauth_token, oauth_secret):
+ self.name = name
+ self.oauth_token = oauth_token
+ self.oauth_secret = oauth_secret
+
+
+@app.before_request
+def before_request():
+ g.user = None
+ if 'user_id' in session:
+ g.user = User.query.get(session['user_id'])
+
+
+@app.after_request
+def after_request(response):
+ db_session.remove()
+ return response
+
+
+@twitter.tokengetter
+def get_twitter_token():
+ user = g.user
+ if user is not None:
+ return user.oauth_token, user.oauth_secret
+
+
+@app.route('/')
+def index():
+ return render_template('index.html')
+
+
+@app.route('/tweet', methods=['POST'])
+def tweet():
+ status = request.form['tweet']
+ if not status:
+ return redirect(url_for('index'))
+ resp = twitter.post('statuses/update.json', data={
+ 'status': status
+ })
+ if resp.status == 403:
+ flash('Your tweet was too long.')
+ else:
+ flash('Successfully tweeted your tweet (ID: #%s)' % resp.data['id'])
+ return redirect(url_for('index'))
+
+
+@app.route('/login')
+def login():
+ callback = url_for('oauth_authorized', next=request.args.get('next')
+ or request.referrer)
+ return twitter.authorize(callback=callback)
+
+
+@app.route('/logout')
+def logout():
+ session.pop('user_id')
+ flash('You were signed out')
+ return redirect(request.referrer or url_for('index'))
+
+
+@app.route('/oauth-authorized')
+@twitter.authorized_handler
+def oauth_authorized(resp):
+ user = User.query.filter_by(name=resp['screen_name']).first()
+ if user is None:
+ user = User(resp['screen_name'],
+ resp['oauth_token'],
+ resp['oauth_token_secret'])
+ db_session.add(user)
+ db_session.commit()
+ session['user_id'] = user.id
+ flash('You were signed in')
+ return redirect(request.args.get('next') or url_for('index'))
+
+
+if __name__ == '__main__':
+ app.run()
1 flaskext/__init__.py
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)
188 flaskext/oauth.py
@@ -0,0 +1,188 @@
+# -*- coding: utf-8 -*-
+"""
+ flaskext.oauth
+ ~~~~~~~~~~~~~~
+
+ Description of the module goes here...
+
+ :copyright: (c) 2010 by Armin Ronacher.
+ :license: BSD, see LICENSE for more details.
+"""
+import httplib2
+from functools import wraps
+from urlparse import urljoin
+from flask import request, session, json, redirect
+from werkzeug import url_decode, url_encode, url_quote, \
+ parse_options_header, Headers
+import oauth2
+
+
+def parse_response(resp, content, strict=False):
+ ct, options = parse_options_header(resp['content-type'])
+ if ct == 'application/json':
+ return json.loads(content)
+ elif ct != 'application/x-www-form-urlencoded':
+ if strict:
+ return content
+ return url_decode(content).to_dict()
+
+
+def encode_request_data(data, format):
+ if format is None:
+ return data, None
+ elif format == 'json':
+ return json.dumps(data), 'application/json'
+ elif format == 'urlencoded':
+ return url_encode(data), 'application/x-www-form-urlencoded'
+ raise TypeError('Unknown format %r' % format)
+
+
+class OAuthResponse(object):
+
+ def __init__(self, resp, content):
+ self.headers = Headers(resp)
+ self.raw_data = content
+ self.data = parse_response(resp, content, strict=True)
+
+ @property
+ def status(self):
+ return self.headers.get('status', type=int)
+
+
+class OAuthClient(oauth2.Client):
+
+ def request_new_token(self, uri, callback=None):
+ params = {}
+ if callback is not None:
+ params['oauth_callback'] = callback
+ req = oauth2.Request.from_consumer_and_token(
+ self.consumer, token=self.token,
+ http_method='POST', http_url=uri, parameters=params)
+ req.sign_request(self.method, self.consumer, self.token)
+ body = req.to_postdata()
+ headers = {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Content-Length': str(len(body))
+ }
+ return httplib2.Http.request(self, uri, method='POST',
+ body=body, headers=headers)
+
+
+class OAuthException(RuntimeError):
+ pass
+
+
+class OAuth(object):
+
+ def remote_app(self, name, **kwargs):
+ return OAuthRemoteApp(self, name, **kwargs)
+
+
+class OAuthRemoteApp(object):
+
+ def __init__(self, oauth, name, request_token_url,
+ access_token_url, authorize_url,
+ consumer_key, consumer_secret,
+ base_url=None, free_token_after_auth=True):
+ self.oauth = oauth
+ self.base_url = base_url
+ self.name = name
+ self.request_token_url = request_token_url
+ self.access_token_url = access_token_url
+ self.authorize_url = authorize_url
+ self.consumer_key = consumer_key
+ self.consumer_secret = consumer_secret
+ self.tokengetter_func = None
+ self.free_token_after_auth = free_token_after_auth
+
+ self._consumer = oauth2.Consumer(self.consumer_key,
+ self.consumer_secret)
+ self._client = OAuthClient(self._consumer)
+
+ def get(self, *args, **kwargs):
+ kwargs['method'] = 'GET'
+ return self.request(*args, **kwargs)
+
+ def post(self, *args, **kwargs):
+ kwargs['method'] = 'POST'
+ return self.request(*args, **kwargs)
+
+ def put(self, *args, **kwargs):
+ kwargs['method'] = 'PUT'
+ return self.request(*args, **kwargs)
+
+ def delete(self, *args, **kwargs):
+ kwargs['method'] = 'DELETE'
+ return self.request(*args, **kwargs)
+
+ def make_client(self):
+ return oauth2.Client(self._consumer, self.get_request_token())
+
+ def request(self, url, data=None, headers=None, format='urlencoded',
+ method='GET', content_type=None):
+ if headers is None:
+ headers = {}
+ client = self.make_client()
+ if content_type is None:
+ data, content_type = encode_request_data(data, format)
+ if content_type is not None:
+ headers['Content-Type'] = content_type
+ resp, content = client.request(self.expand_url(url), method=method,
+ body=data, headers=headers)
+ return OAuthResponse(resp, content)
+
+ def expand_url(self, url):
+ return urljoin(self.base_url, url)
+
+ def generate_request_token(self, callback=None):
+ if callback is not None:
+ callback = urljoin(request.url, callback)
+ resp, content = self._client.request_new_token(
+ self.expand_url(self.request_token_url), callback)
+ if resp['status'] != '200':
+ raise OAuthException('Failed to generate request token')
+ data = parse_response(resp, content)
+ if data is None:
+ raise OAuthException('Invalid token response from ' + self.name)
+ tup = (data['oauth_token'], data['oauth_token_secret'])
+ session[self.name + '_oauthtok'] = tup
+ return tup
+
+ def get_request_token(self):
+ rv = self.tokengetter_func()
+ if rv is None:
+ rv = session.get(self.name + '_oauthtok')
+ if rv is None:
+ raise OAuthException('No token available')
+ return oauth2.Token(*rv)
+
+ def free_request_token(self):
+ session.pop(self.name + '_oauthtok')
+
+ def authorize(self, callback=None):
+ token = self.generate_request_token(callback)[0]
+ url = '%s?oauth_token=%s' % (self.expand_url(self.authorize_url),
+ url_quote(token))
+ return redirect(url)
+
+ def tokengetter(self, f):
+ self.tokengetter_func = f
+ return f
+
+ def authorized_handler(self, f):
+ @wraps(f)
+ def decorated(*args, **kwargs):
+ client = self.make_client()
+ resp, content = client.request('%s?oauth_verifier=%s' % (
+ self.expand_url(self.access_token_url),
+ request.args['oauth_verifier']
+ ), 'GET')
+ if resp['status'] != '200':
+ raise OAuthException('Invalid response from ' + self.name)
+ data = parse_response(resp, content)
+ try:
+ return f(data)
+ finally:
+ if self.free_token_after_auth:
+ self.free_request_token()
+ return decorated
44 setup.py
@@ -0,0 +1,44 @@
+"""
+Flask-OAuth
+-----------
+
+Description goes here...
+
+Links
+`````
+
+* `documentation <http://packages.python.org/Flask-OAuth`_
+* `development version
+ <http://github.com/USERNAME/REPOSITORY/zipball/master#egg=Flask-OAuth-dev>`_
+
+"""
+from setuptools import setup
+
+
+setup(
+ name='Flask-OAuth',
+ version='0.1',
+ url='<enter URL here>',
+ license='BSD',
+ author='Armin Ronacher',
+ description='<enter short description here>',
+ long_description=__doc__,
+ packages=['flaskext'],
+ namespace_packages=['flaskext'],
+ zip_safe=False,
+ platforms='any',
+ install_requires=[
+ 'Flask',
+ 'oauth2'
+ ],
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+ 'Topic :: Software Development :: Libraries :: Python Modules'
+ ]
+)

0 comments on commit 5c4df6d

Please sign in to comment.