<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.mediagoblin.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rodney757</id>
	<title>GNU MediaGoblin Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.mediagoblin.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rodney757"/>
	<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/Special:Contributions/Rodney757"/>
	<updated>2026-05-09T14:01:42Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=HackingHowto&amp;diff=1332</id>
		<title>HackingHowto</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=HackingHowto&amp;diff=1332"/>
		<updated>2013-07-02T18:55:31Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Mac OS X Lion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Hacking HOWTO =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== So you want to hack on GNU MediaGoblin? ==&lt;br /&gt;
&lt;br /&gt;
First thing to do is check out the [http://mediagoblin.org/join/ web site] where we list all the project&lt;br /&gt;
infrastructure including:&lt;br /&gt;
&lt;br /&gt;
* the IRC channel&lt;br /&gt;
* the mailing list&lt;br /&gt;
* the issue tracker&lt;br /&gt;
&lt;br /&gt;
Additionally, we have information on how to get involved, who to talk&lt;br /&gt;
to, what needs to be worked on, and other things besides!&lt;br /&gt;
&lt;br /&gt;
Second thing to do is take a look at [http://docs.mediagoblin.org/devel/codebase.html codebase chapter] where&lt;br /&gt;
we&#039;ve started documenting how GNU MediaGoblin is built and how to add&lt;br /&gt;
new things.  If you&#039;re planning on contributing in python, you should be aware&lt;br /&gt;
of [http://www.python.org/dev/peps/pep-0008/ PEP-8], the official Python style guide,&lt;br /&gt;
which we follow.&lt;br /&gt;
&lt;br /&gt;
Third you&#039;ll need to get the requirements.&lt;br /&gt;
&lt;br /&gt;
Fourth, you&#039;ll need to build a development environment.  We use an&lt;br /&gt;
in-package checkout of virtualenv.  This isn&#039;t the convenional way to&lt;br /&gt;
install virtualenv (normally you don&#039;t install virtualenv inside the&lt;br /&gt;
package itself) but we&#039;ve found that it&#039;s significantly easier for&lt;br /&gt;
newcomers who aren&#039;t already familiar with virtualenv.  If you *are*&lt;br /&gt;
already familiar with virtualenv, feel free to just install&lt;br /&gt;
mediagoblin in your own virtualenv setup... the necessary adjustments&lt;br /&gt;
should be obvious.&lt;br /&gt;
&lt;br /&gt;
== Getting requirements ==&lt;br /&gt;
&lt;br /&gt;
First, you need to have the following installed before you can build&lt;br /&gt;
an environment for hacking on GNU MediaGoblin:&lt;br /&gt;
&lt;br /&gt;
* Python 2.6 or 2.7  - http://www.python.org/ (You&#039;ll need Python as well as the dev files for building modules.)&lt;br /&gt;
* python-lxml        - http://lxml.de/&lt;br /&gt;
* git                - http://git-scm.com/&lt;br /&gt;
* SQLAlchemy 0.7.0 or higher   - http://www.sqlalchemy.org/&lt;br /&gt;
* Python Imaging Library (PIL) - http://www.pythonware.com/products/pil/&lt;br /&gt;
* virtualenv         - http://www.virtualenv.org/&lt;br /&gt;
* Python GStreamer Bindings - http://gstreamer.freedesktop.org/modules/gst-python.html&lt;br /&gt;
&lt;br /&gt;
=== GNU/Linux ===&lt;br /&gt;
&lt;br /&gt;
==== Debian and derivatives ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;re running Debian GNU/Linux or a Debian-derived distribution&lt;br /&gt;
such as Debian, Mint, or [http://bugs.foocorp.net/issues/478 Ubuntu 10.10+], running the following should install these&lt;br /&gt;
requirements:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|sudo apt-get install git-core python python-dev python-lxml python-imaging python-virtualenv python-gst0.10 libjpeg8-dev}}&lt;br /&gt;
&lt;br /&gt;
==== Fedora / RedHat(?) ====&lt;br /&gt;
&lt;br /&gt;
On Fedora:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|yum install python-paste-deploy python-paste-script git-core python python-devel python-lxml python-imaging python-virtualenv gstreamer-python}}&lt;br /&gt;
&lt;br /&gt;
=== Mac OS X ===&lt;br /&gt;
&lt;br /&gt;
==== Mac OS X Lion ====&lt;br /&gt;
&lt;br /&gt;
Download the Newest Python.&lt;br /&gt;
&lt;br /&gt;
Git is already installed.&lt;br /&gt;
&lt;br /&gt;
* Note for PIL and lxml, you can: pip install pil lxml&lt;br /&gt;
&lt;br /&gt;
Python-lxml: http://muffinresearch.co.uk/archives/2009/03/05/install-lxml-on-osx/ with sudo&lt;br /&gt;
&lt;br /&gt;
Python Imaging Library (PIL): http://code.google.com/appengine/docs/python/images/installingPIL.html#mac&lt;br /&gt;
&lt;br /&gt;
Libjpeg &amp;amp; Libpng: http://ethan.tira-thompson.com/Mac_OS_X_Ports.html Combo Installer&lt;br /&gt;
&lt;br /&gt;
==== Mac OS X Snow Leopard ====&lt;br /&gt;
&lt;br /&gt;
# You will probably want to install MacPorts this will give you access to many free software packages in the same manner to apt-get and yum: https://www.macports.org/install.php&lt;br /&gt;
# Ensure you install Git and the command line tools: https://help.github.com/articles/set-up-git#platform-mac&lt;br /&gt;
# Once both of those are installed type this in your terminal and enter your password when prompted for it {{Cmd|sudo port install python27 py27-lxml py27-sqlalchemy py27-pil py27-virtualenv py27-gst-python py27-pastescript}}&lt;br /&gt;
&lt;br /&gt;
=== Microsoft Windows ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Thanks wctype!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Getting requirements ====&lt;br /&gt;
&lt;br /&gt;
* Python 2.7  -  [http://www.python.org/download/ Download] &amp;lt;!-- http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi --&amp;gt;&lt;br /&gt;
* git - [https://github.com/msysgit/git/downloads Download] &amp;lt;!-- https://github.com/downloads/msysgit/git/Git-1.7.11-preview20120620.exe --&amp;gt;&lt;br /&gt;
* python-lxml - [http://pypi.python.org/pypi/lxml/2.3.5#downloads Tarball] [http://www.lfd.uci.edu/~gohlke/pythonlibs/#pil Binaries] &amp;lt;!-- http://pypi.python.org/packages/source/l/lxml/lxml-2.3.5.tar.gz, http://www.lfd.uci.edu/~gohlke/pythonlibs/z8sp4uqu/lxml-2.3.5.win32-py2.7.exe --&amp;gt;&lt;br /&gt;
* Python Imaging Library (PIL) - [http://www.pythonware.com/products/pil/ Download] &amp;lt;!-- http://effbot.org/downloads/PIL-1.1.7.win32-py2.7.exe] --&amp;gt;&lt;br /&gt;
* virtualenv - [http://pypi.python.org/pypi/virtualenvwrapper-win/1.0.8#downloads Download] &amp;lt;!-- http://pypi.python.org/packages/source/v/virtualenvwrapper-win/virtualenvwrapper-win-1.0.8.zip --&amp;gt;&lt;br /&gt;
* OSSBuild project provides reasonably up-to-date binaries of GStreamer - [https://code.google.com/p/ossbuild/downloads/list Download] &amp;lt;!-- http://ossbuild.googlecode.com/files/GStreamer-WinBuilds-GPL-x86.msi --&amp;gt;&lt;br /&gt;
* py-bcrypt - [https://bitbucket.org/alexandrul/py-bcrypt/downloads/ Download] &amp;lt;!-- https://bitbucket.org/alexandrul/py-bcrypt/downloads/py-bcrypt-0.2.post1.win32-py2.7.exe --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;You can help:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you have instructions for other GNU/Linux distributions, Windows, or Mac OS X to set&lt;br /&gt;
up requirements, [http://mediagoblin.org/join/ let us know]!&lt;br /&gt;
&lt;br /&gt;
== How to set up and maintain an environment for hacking with virtualenv ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Requirements&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No additional requirements.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Create a development environment&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
After installing the requirements, follow these steps:&lt;br /&gt;
&lt;br /&gt;
* Clone the repository: {{Cmd|git clone &amp;lt;nowiki&amp;gt;git://gitorious.org/mediagoblin/mediagoblin.git&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
* Change directories to your new checkout: {{Cmd|cd mediagoblin}}&lt;br /&gt;
* Checkout git submodules: {{Cmd|git submodule init}} {{Cmd|git submodule update}}&lt;br /&gt;
* Set up the in-package virtualenv:&lt;br /&gt;
  (virtualenv --system-site-packages . || virtualenv .) &lt;br /&gt;
* Run setup.py:&lt;br /&gt;
  {{Cmd|./bin/python setup.py develop}}&lt;br /&gt;
* Init the database:&lt;br /&gt;
  {{Cmd|./bin/gmg dbupdate}}&lt;br /&gt;
&lt;br /&gt;
That&#039;s it!&lt;br /&gt;
&lt;br /&gt;
(If you have troubles in the remaining steps, consider try installing&lt;br /&gt;
virtualenv with one of the flags --setuptools, --distribute or possibly --no-site-packages.  Additionally, if your system has python3.X as the default, you might need to do virtualenv --python=python2.7 or --python=python2.6)&lt;br /&gt;
&lt;br /&gt;
If you have problems, please [http://mediagoblin.org/join/ let us know]!&lt;br /&gt;
&lt;br /&gt;
== Updating an existing environment ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Updating for dependency changes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
While hacking on GNU MediaGoblin over time, you&#039;ll eventually have to&lt;br /&gt;
update your development environment because the dependencies have&lt;br /&gt;
changed.&lt;br /&gt;
&lt;br /&gt;
To do that, run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./bin/python setup.py develop --upgrade &amp;amp;&amp;amp; ./bin/gmg dbupdate}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Updating for code changes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Cmd|git pull -u}}&lt;br /&gt;
{{Cmd|git submodule update}}&lt;br /&gt;
&lt;br /&gt;
== Running the server ==&lt;br /&gt;
&lt;br /&gt;
If you want to get things running quickly and without hassle, just&lt;br /&gt;
run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./lazyserver.sh}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This will start up a python server where you can begin playing with&lt;br /&gt;
mediagoblin, listening on 127.0.0.1:6543.  It will also run celery in &amp;quot;always eager&amp;quot; mode so you&lt;br /&gt;
don&#039;t have to start a separate process for it.&lt;br /&gt;
&lt;br /&gt;
By default, the instance is not sending out confirmation mails. Instead they are redirected to the standard output (the console) of lazyserver.sh.&lt;br /&gt;
&lt;br /&gt;
You can change this behavior setting &amp;lt;code&amp;gt;email_debug_mode&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; in mediagoblin.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is fine in development, but if you want to actually run celery&lt;br /&gt;
separately for testing (or deployment purposes), you&#039;ll want to run&lt;br /&gt;
the server independently:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./bin/paster serve paste.ini --reload}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running celeryd ==&lt;br /&gt;
&lt;br /&gt;
If you aren&#039;t using &amp;lt;tt&amp;gt;./lazyserver.sh&amp;lt;/tt&amp;gt; or otherwise aren&#039;t running celery&lt;br /&gt;
in always eager mode, you&#039;ll need to do this if you want your media to&lt;br /&gt;
process and actually show up.  It&#039;s probably a good idea in&lt;br /&gt;
development to have the web server (above) running in one terminal and&lt;br /&gt;
celeryd in another window.&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|&amp;lt;nowiki&amp;gt;CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery ./bin/celeryd&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running the test suite ==&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./runtests.sh}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running a shell ==&lt;br /&gt;
&lt;br /&gt;
If you want a shell with your database pre-setup and an instantiated&lt;br /&gt;
application ready and at your fingertips....&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./bin/gmg shell}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
== Wiping your user data ==&lt;br /&gt;
&lt;br /&gt;
You can completely wipe all data from the instance by doing:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|rm -rf mediagoblin.db kombu.db celery.db user_dev; ./bin/gmg dbupdate}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Unless you&#039;re doing development and working on and testing creating&lt;br /&gt;
a new instance, you will probably never have to do this.&lt;br /&gt;
&lt;br /&gt;
== Quickstart for Django programmers ==&lt;br /&gt;
&lt;br /&gt;
We&#039;re not using Django, but the codebase is very Django-like in its&lt;br /&gt;
structure.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;routing.py&amp;lt;/tt&amp;gt; is like &amp;lt;tt&amp;gt;urls.py&amp;lt;/tt&amp;gt; in Django&lt;br /&gt;
* &amp;lt;tt&amp;gt;models.py&amp;lt;/tt&amp;gt; has SQLAlchemy ORM definitions&lt;br /&gt;
* &amp;lt;tt&amp;gt;views.py&amp;lt;/tt&amp;gt; is where the views go&lt;br /&gt;
&lt;br /&gt;
We&#039;re using SQLAlchemy, which is semi-similar to the Django ORM, but&lt;br /&gt;
not really because you can get a lot more fine-grained.  The&lt;br /&gt;
[http://docs.sqlalchemy.org/en/latest/orm/tutorial.html SQLAlchemy ORM tutorial] is a great place to start.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;YouCanHelp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If there are other things that you think would help orient someone&lt;br /&gt;
new to GNU MediaGoblin but coming from Django, let us know!&lt;br /&gt;
&lt;br /&gt;
== Showing off your work with PageKite ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;re doing development with MediaGoblin, it&#039;s sometimes helpful to show off your work to gather feedback from other contributors.  A number of the MediaGoblin developers use something called [http://pagekite.net PageKite], which is a fellow free software web service which makes temporarily showing off work on your machine easy.  There&#039;s a [http://pagekite.net/wiki/Howto/UsePageKiteWithMediaGoblin/ tutorial on how to use PageKite and MediaGoblin together] available on the PageKite wiki.&lt;br /&gt;
&lt;br /&gt;
If you are doing a lot of MediaGoblin development, the PageKite people have graciously offered us a good amount of bandwidth at no cost in an effort to help out fellow free software projects.  If you&#039;ve been making significant contributions, PM Chris Webber on freenode (who is paroneayea there) and ask if you can be added to our group plan.&lt;br /&gt;
&lt;br /&gt;
== Bite-sized bugs to start with ==&lt;br /&gt;
&lt;br /&gt;
Now you should visit our latest list of [http://issues.mediagoblin.org/query?status=!closed&amp;amp;keywords=~bitesized bite-sized issues] because squishing bugs is messy fun. If you&#039;re interested in other things to work on, or need help getting started on a bug, let us know on [http://mediagoblin.org/join/ the mailing list] or on the [http://mediagoblin.org/join/ IRC channel].&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=HackingHowto&amp;diff=1325</id>
		<title>HackingHowto</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=HackingHowto&amp;diff=1325"/>
		<updated>2013-06-22T17:43:17Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Mac OS X Lion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Hacking HOWTO =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== So you want to hack on GNU MediaGoblin? ==&lt;br /&gt;
&lt;br /&gt;
First thing to do is check out the [http://mediagoblin.org/join/ web site] where we list all the project&lt;br /&gt;
infrastructure including:&lt;br /&gt;
&lt;br /&gt;
* the IRC channel&lt;br /&gt;
* the mailing list&lt;br /&gt;
* the issue tracker&lt;br /&gt;
&lt;br /&gt;
Additionally, we have information on how to get involved, who to talk&lt;br /&gt;
to, what needs to be worked on, and other things besides!&lt;br /&gt;
&lt;br /&gt;
Second thing to do is take a look at [http://docs.mediagoblin.org/devel/codebase.html codebase chapter] where&lt;br /&gt;
we&#039;ve started documenting how GNU MediaGoblin is built and how to add&lt;br /&gt;
new things.  If you&#039;re planning on contributing in python, you should be aware&lt;br /&gt;
of [http://www.python.org/dev/peps/pep-0008/ PEP-8], the official Python style guide,&lt;br /&gt;
which we follow.&lt;br /&gt;
&lt;br /&gt;
Third you&#039;ll need to get the requirements.&lt;br /&gt;
&lt;br /&gt;
Fourth, you&#039;ll need to build a development environment.  We use an&lt;br /&gt;
in-package checkout of virtualenv.  This isn&#039;t the convenional way to&lt;br /&gt;
install virtualenv (normally you don&#039;t install virtualenv inside the&lt;br /&gt;
package itself) but we&#039;ve found that it&#039;s significantly easier for&lt;br /&gt;
newcomers who aren&#039;t already familiar with virtualenv.  If you *are*&lt;br /&gt;
already familiar with virtualenv, feel free to just install&lt;br /&gt;
mediagoblin in your own virtualenv setup... the necessary adjustments&lt;br /&gt;
should be obvious.&lt;br /&gt;
&lt;br /&gt;
== Getting requirements ==&lt;br /&gt;
&lt;br /&gt;
First, you need to have the following installed before you can build&lt;br /&gt;
an environment for hacking on GNU MediaGoblin:&lt;br /&gt;
&lt;br /&gt;
* Python 2.6 or 2.7  - http://www.python.org/ (You&#039;ll need Python as well as the dev files for building modules.)&lt;br /&gt;
* python-lxml        - http://lxml.de/&lt;br /&gt;
* git                - http://git-scm.com/&lt;br /&gt;
* SQLAlchemy 0.7.0 or higher   - http://www.sqlalchemy.org/&lt;br /&gt;
* Python Imaging Library (PIL) - http://www.pythonware.com/products/pil/&lt;br /&gt;
* virtualenv         - http://www.virtualenv.org/&lt;br /&gt;
* Python GStreamer Bindings - http://gstreamer.freedesktop.org/modules/gst-python.html&lt;br /&gt;
&lt;br /&gt;
=== GNU/Linux ===&lt;br /&gt;
&lt;br /&gt;
==== Debian and derivatives ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;re running Debian GNU/Linux or a Debian-derived distribution&lt;br /&gt;
such as Debian, Mint, or [http://bugs.foocorp.net/issues/478 Ubuntu 10.10+], running the following should install these&lt;br /&gt;
requirements:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|sudo apt-get install git-core python python-dev python-lxml python-imaging python-virtualenv python-gst0.10 libjpeg8-dev}}&lt;br /&gt;
&lt;br /&gt;
==== Fedora / RedHat(?) ====&lt;br /&gt;
&lt;br /&gt;
On Fedora:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|yum install python-paste-deploy python-paste-script git-core python python-devel python-lxml python-imaging python-virtualenv gstreamer-python}}&lt;br /&gt;
&lt;br /&gt;
=== Mac OS X ===&lt;br /&gt;
&lt;br /&gt;
==== Mac OS X Lion ====&lt;br /&gt;
&lt;br /&gt;
Download the Newest Python.&lt;br /&gt;
&lt;br /&gt;
Git is already installed.&lt;br /&gt;
&lt;br /&gt;
* Note for PIL and lxml, you can: pip install pil lxml&lt;br /&gt;
&lt;br /&gt;
Python-lxml: http://muffinresearch.co.uk/archives/2009/03/05/install-lxml-on-osx/ with sudo&lt;br /&gt;
&lt;br /&gt;
Python Imaging Library (PIL): http://code.google.com/appengine/docs/python/images/installingPIL.html#mac&lt;br /&gt;
&lt;br /&gt;
Libjpeg &amp;amp; Libpng: http://ethan.tira-thompson.org/Mac_OS_X_Ports.html Combo Installer&lt;br /&gt;
&lt;br /&gt;
==== Mac OS X Snow Leopard ====&lt;br /&gt;
&lt;br /&gt;
# You will probably want to install MacPorts this will give you access to many free software packages in the same manner to apt-get and yum: https://www.macports.org/install.php&lt;br /&gt;
# Ensure you install Git and the command line tools: https://help.github.com/articles/set-up-git#platform-mac&lt;br /&gt;
# Once both of those are installed type this in your terminal and enter your password when prompted for it {{Cmd|sudo port install python27 py27-lxml py27-sqlalchemy py27-pil py27-virtualenv py27-gst-python py27-pastescript}}&lt;br /&gt;
&lt;br /&gt;
=== Microsoft Windows ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Thanks wctype!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Getting requirements ====&lt;br /&gt;
&lt;br /&gt;
* Python 2.7  -  [http://www.python.org/download/ Download] &amp;lt;!-- http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi --&amp;gt;&lt;br /&gt;
* git - [https://github.com/msysgit/git/downloads Download] &amp;lt;!-- https://github.com/downloads/msysgit/git/Git-1.7.11-preview20120620.exe --&amp;gt;&lt;br /&gt;
* python-lxml - [http://pypi.python.org/pypi/lxml/2.3.5#downloads Tarball] [http://www.lfd.uci.edu/~gohlke/pythonlibs/#pil Binaries] &amp;lt;!-- http://pypi.python.org/packages/source/l/lxml/lxml-2.3.5.tar.gz, http://www.lfd.uci.edu/~gohlke/pythonlibs/z8sp4uqu/lxml-2.3.5.win32-py2.7.exe --&amp;gt;&lt;br /&gt;
* Python Imaging Library (PIL) - [http://www.pythonware.com/products/pil/ Download] &amp;lt;!-- http://effbot.org/downloads/PIL-1.1.7.win32-py2.7.exe] --&amp;gt;&lt;br /&gt;
* virtualenv - [http://pypi.python.org/pypi/virtualenvwrapper-win/1.0.8#downloads Download] &amp;lt;!-- http://pypi.python.org/packages/source/v/virtualenvwrapper-win/virtualenvwrapper-win-1.0.8.zip --&amp;gt;&lt;br /&gt;
* OSSBuild project provides reasonably up-to-date binaries of GStreamer - [https://code.google.com/p/ossbuild/downloads/list Download] &amp;lt;!-- http://ossbuild.googlecode.com/files/GStreamer-WinBuilds-GPL-x86.msi --&amp;gt;&lt;br /&gt;
* py-bcrypt - [https://bitbucket.org/alexandrul/py-bcrypt/downloads/ Download] &amp;lt;!-- https://bitbucket.org/alexandrul/py-bcrypt/downloads/py-bcrypt-0.2.post1.win32-py2.7.exe --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;You can help:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you have instructions for other GNU/Linux distributions, Windows, or Mac OS X to set&lt;br /&gt;
up requirements, [http://mediagoblin.org/join/ let us know]!&lt;br /&gt;
&lt;br /&gt;
== How to set up and maintain an environment for hacking with virtualenv ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Requirements&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No additional requirements.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Create a development environment&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
After installing the requirements, follow these steps:&lt;br /&gt;
&lt;br /&gt;
* Clone the repository: {{Cmd|git clone &amp;lt;nowiki&amp;gt;git://gitorious.org/mediagoblin/mediagoblin.git&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
* Change directories to your new checkout: {{Cmd|cd mediagoblin}}&lt;br /&gt;
* Checkout git submodules: {{Cmd|git submodule init}} {{Cmd|git submodule update}}&lt;br /&gt;
* Set up the in-package virtualenv:&lt;br /&gt;
  (virtualenv --system-site-packages . || virtualenv .) &lt;br /&gt;
* Run setup.py:&lt;br /&gt;
  {{Cmd|./bin/python setup.py develop}}&lt;br /&gt;
* Init the database:&lt;br /&gt;
  {{Cmd|./bin/gmg dbupdate}}&lt;br /&gt;
&lt;br /&gt;
That&#039;s it!&lt;br /&gt;
&lt;br /&gt;
(If you have troubles in the remaining steps, consider try installing&lt;br /&gt;
virtualenv with one of the flags --setuptools, --distribute or possibly --no-site-packages.  Additionally, if your system has python3.X as the default, you might need to do virtualenv --python=python2.7 or --python=python2.6)&lt;br /&gt;
&lt;br /&gt;
If you have problems, please [http://mediagoblin.org/join/ let us know]!&lt;br /&gt;
&lt;br /&gt;
== Updating an existing environment ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Updating for dependency changes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
While hacking on GNU MediaGoblin over time, you&#039;ll eventually have to&lt;br /&gt;
update your development environment because the dependencies have&lt;br /&gt;
changed.&lt;br /&gt;
&lt;br /&gt;
To do that, run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./bin/python setup.py develop --upgrade &amp;amp;&amp;amp; ./bin/gmg dbupdate}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Updating for code changes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Cmd|git pull -u}}&lt;br /&gt;
{{Cmd|git submodule update}}&lt;br /&gt;
&lt;br /&gt;
== Running the server ==&lt;br /&gt;
&lt;br /&gt;
If you want to get things running quickly and without hassle, just&lt;br /&gt;
run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./lazyserver.sh}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This will start up a python server where you can begin playing with&lt;br /&gt;
mediagoblin, listening on 127.0.0.1:6543.  It will also run celery in &amp;quot;always eager&amp;quot; mode so you&lt;br /&gt;
don&#039;t have to start a separate process for it.&lt;br /&gt;
&lt;br /&gt;
By default, the instance is not sending out confirmation mails. Instead they are redirected to the standard output (the console) of lazyserver.sh.&lt;br /&gt;
&lt;br /&gt;
You can change this behavior setting &amp;lt;code&amp;gt;email_debug_mode&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; in mediagoblin.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is fine in development, but if you want to actually run celery&lt;br /&gt;
separately for testing (or deployment purposes), you&#039;ll want to run&lt;br /&gt;
the server independently:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./bin/paster serve paste.ini --reload}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running celeryd ==&lt;br /&gt;
&lt;br /&gt;
If you aren&#039;t using &amp;lt;tt&amp;gt;./lazyserver.sh&amp;lt;/tt&amp;gt; or otherwise aren&#039;t running celery&lt;br /&gt;
in always eager mode, you&#039;ll need to do this if you want your media to&lt;br /&gt;
process and actually show up.  It&#039;s probably a good idea in&lt;br /&gt;
development to have the web server (above) running in one terminal and&lt;br /&gt;
celeryd in another window.&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|&amp;lt;nowiki&amp;gt;CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery ./bin/celeryd&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running the test suite ==&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./runtests.sh}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running a shell ==&lt;br /&gt;
&lt;br /&gt;
If you want a shell with your database pre-setup and an instantiated&lt;br /&gt;
application ready and at your fingertips....&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./bin/gmg shell}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
== Wiping your user data ==&lt;br /&gt;
&lt;br /&gt;
You can completely wipe all data from the instance by doing:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|rm -rf mediagoblin.db kombu.db celery.db user_dev; ./bin/gmg dbupdate}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Unless you&#039;re doing development and working on and testing creating&lt;br /&gt;
a new instance, you will probably never have to do this.&lt;br /&gt;
&lt;br /&gt;
== Quickstart for Django programmers ==&lt;br /&gt;
&lt;br /&gt;
We&#039;re not using Django, but the codebase is very Django-like in its&lt;br /&gt;
structure.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;routing.py&amp;lt;/tt&amp;gt; is like &amp;lt;tt&amp;gt;urls.py&amp;lt;/tt&amp;gt; in Django&lt;br /&gt;
* &amp;lt;tt&amp;gt;models.py&amp;lt;/tt&amp;gt; has SQLAlchemy ORM definitions&lt;br /&gt;
* &amp;lt;tt&amp;gt;views.py&amp;lt;/tt&amp;gt; is where the views go&lt;br /&gt;
&lt;br /&gt;
We&#039;re using SQLAlchemy, which is semi-similar to the Django ORM, but&lt;br /&gt;
not really because you can get a lot more fine-grained.  The&lt;br /&gt;
[http://docs.sqlalchemy.org/en/latest/orm/tutorial.html SQLAlchemy ORM tutorial] is a great place to start.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;YouCanHelp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If there are other things that you think would help orient someone&lt;br /&gt;
new to GNU MediaGoblin but coming from Django, let us know!&lt;br /&gt;
&lt;br /&gt;
== Showing off your work with PageKite ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;re doing development with MediaGoblin, it&#039;s sometimes helpful to show off your work to gather feedback from other contributors.  A number of the MediaGoblin developers use something called [http://pagekite.net PageKite], which is a fellow free software web service which makes temporarily showing off work on your machine easy.  There&#039;s a [http://pagekite.net/wiki/Howto/UsePageKiteWithMediaGoblin/ tutorial on how to use PageKite and MediaGoblin together] available on the PageKite wiki.&lt;br /&gt;
&lt;br /&gt;
If you are doing a lot of MediaGoblin development, the PageKite people have graciously offered us a good amount of bandwidth at no cost in an effort to help out fellow free software projects.  If you&#039;ve been making significant contributions, PM Chris Webber on freenode (who is paroneayea there) and ask if you can be added to our group plan.&lt;br /&gt;
&lt;br /&gt;
== Bite-sized bugs to start with ==&lt;br /&gt;
&lt;br /&gt;
Now you should visit our latest list of [http://issues.mediagoblin.org/query?status=!closed&amp;amp;keywords=~bitesized bite-sized issues] because squishing bugs is messy fun. If you&#039;re interested in other things to work on, or need help getting started on a bug, let us know on [http://mediagoblin.org/join/ the mailing list] or on the [http://mediagoblin.org/join/ IRC channel].&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1290</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1290"/>
		<updated>2013-05-06T14:25:03Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* basic_auth: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Different use cases for different login systems ==&lt;br /&gt;
&lt;br /&gt;
Different login systems may affect the way auth stuff works differently.  For example, all of these cases are very different, but all fall under the &amp;quot;auth world view&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* You log in via some central auth system thing that uses the mediagoblin login page interface, but passes off the username/password to some other database.  (If that username and password exist remotely, do we need to &amp;quot;give&amp;quot; that username to a newly created user?)&lt;br /&gt;
* Persona/OpenID style: You have a user, but you have the option to log in the user via some external page and then come back.  In this case, we&#039;re probably not creating new users on-demand, and we don&#039;t really use the login page at all anyway.&lt;br /&gt;
&lt;br /&gt;
== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        def get_response(function, *args):&lt;br /&gt;
            for p in _auth_providers:&lt;br /&gt;
                response = p.function(*args)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
            raise NotImplemented(&amp;quot;No provider for %s&amp;quot; % functions)&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return get_response(&amp;quot;check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config1))&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config2))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Plugins can configure the individual instance (ldap server name)&lt;br /&gt;
* Plugins can instantiate multiple providers for different backends, like two different ldap servers&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more &amp;quot;hooky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers += hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
        ...&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: get_auth_provider}&lt;br /&gt;
        def get_auth_provider(): return AuthUserInterface()&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Still allows configuration on the individual instance&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
* No easy way to add multiple instances of one Provider&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This is the way we are going to implement auth plugins.&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    mediagoblin.ini:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        [plugins]&lt;br /&gt;
        [[plugins.ldap]]&lt;br /&gt;
        [[[server1]]]&lt;br /&gt;
        [[[server2]]]&lt;br /&gt;
&lt;br /&gt;
    auth/__init__.py:&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        ...&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login}&lt;br /&gt;
        #  or depending on the plugin&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            serv1 = ldap_thing(config1)&lt;br /&gt;
            serv2 = ldap_thing(config2)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv1.check_login)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv2.check_login)&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
        def check_login(user, password):&lt;br /&gt;
            if a: return True   # Yes, let them in&lt;br /&gt;
            if b: return False  # No and don&#039;t try other providers&lt;br /&gt;
            return None  # Don&#039;t know, try next provider.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
All the Pros from the interface design are not here:&lt;br /&gt;
* config data has to be global on the plugin, not local to the instantiated provider&lt;br /&gt;
* No straight way of doing multiple instances.&lt;br /&gt;
*: Yes, the individual hook could do it by itself&lt;br /&gt;
&lt;br /&gt;
==Various ideas on how to use classy authentication providers with the hooky authentication system==&lt;br /&gt;
 &lt;br /&gt;
    &amp;lt;nowiki&amp;gt;&lt;br /&gt;
     ...&lt;br /&gt;
    class LDAPLoginer():&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        my_ldap = LDAPLoginer(ldap_config)&lt;br /&gt;
        add_hook(&#039;login&#039;: my_ldap.login)&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
    def add_classy_hooks(cls, hook_list):&lt;br /&gt;
        q = {}&lt;br /&gt;
        for h in hook_list:&lt;br /&gt;
            q[h] = getattr(cls, h)&lt;br /&gt;
        pluginapi.add_hooks_dict(q)&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        ldap = LDAPAuth(ldap_config)&lt;br /&gt;
        add_classy_hooks(ldap, [&#039;check_login&#039;])&lt;br /&gt;
    ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Proposed DB Schema ==&lt;br /&gt;
&lt;br /&gt;
Would remove pw_hash from User model. Reason is if someone would like to have the only way to login to an account is with OpenID or Persona. We would still require every account to have a unique username regardless of the Authentication enabled, thus username will be left in the User model. Email would be left in the User model for the same reason as username.&lt;br /&gt;
&lt;br /&gt;
===OpenID/Persona:===&lt;br /&gt;
&lt;br /&gt;
openid_url = Column(unicode, nullable=False)&lt;br /&gt;
&lt;br /&gt;
user = Column(Integer, ForeignKey(User,id), nullable=False)&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1289</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1289"/>
		<updated>2013-05-06T00:45:42Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Proposed DB Schema */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Different use cases for different login systems ==&lt;br /&gt;
&lt;br /&gt;
Different login systems may affect the way auth stuff works differently.  For example, all of these cases are very different, but all fall under the &amp;quot;auth world view&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* You log in via some central auth system thing that uses the mediagoblin login page interface, but passes off the username/password to some other database.  (If that username and password exist remotely, do we need to &amp;quot;give&amp;quot; that username to a newly created user?)&lt;br /&gt;
* Persona/OpenID style: You have a user, but you have the option to log in the user via some external page and then come back.  In this case, we&#039;re probably not creating new users on-demand, and we don&#039;t really use the login page at all anyway.&lt;br /&gt;
&lt;br /&gt;
== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        def get_response(function, *args):&lt;br /&gt;
            for p in _auth_providers:&lt;br /&gt;
                response = p.function(*args)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
            raise NotImplemented(&amp;quot;No provider for %s&amp;quot; % functions)&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return get_response(&amp;quot;check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config1))&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config2))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Plugins can configure the individual instance (ldap server name)&lt;br /&gt;
* Plugins can instantiate multiple providers for different backends, like two different ldap servers&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more &amp;quot;hooky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers += hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
        ...&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: get_auth_provider}&lt;br /&gt;
        def get_auth_provider(): return AuthUserInterface()&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Still allows configuration on the individual instance&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
* No easy way to add multiple instances of one Provider&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This is the way we are going to implement auth plugins.&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    mediagoblin.ini:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        [plugins]&lt;br /&gt;
        [[plugins.ldap]]&lt;br /&gt;
        [[[server1]]]&lt;br /&gt;
        [[[server2]]]&lt;br /&gt;
&lt;br /&gt;
    auth/__init__.py:&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        ...&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login}&lt;br /&gt;
        #  or depending on the plugin&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            serv1 = ldap_thing(config1)&lt;br /&gt;
            serv2 = ldap_thing(config2)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv1.check_login)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv2.check_login)&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
        def check_login(user, password):&lt;br /&gt;
            if a: return True   # Yes, let them in&lt;br /&gt;
            if b: return False  # No and don&#039;t try other providers&lt;br /&gt;
            return None  # Don&#039;t know, try next provider.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
All the Pros from the interface design are not here:&lt;br /&gt;
* config data has to be global on the plugin, not local to the instantiated provider&lt;br /&gt;
* No straight way of doing multiple instances.&lt;br /&gt;
*: Yes, the individual hook could do it by itself&lt;br /&gt;
&lt;br /&gt;
==Various ideas on how to use classy authentication providers with the hooky authentication system==&lt;br /&gt;
 &lt;br /&gt;
    &amp;lt;nowiki&amp;gt;&lt;br /&gt;
     ...&lt;br /&gt;
    class LDAPLoginer():&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        my_ldap = LDAPLoginer(ldap_config)&lt;br /&gt;
        add_hook(&#039;login&#039;: my_ldap.login)&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
    def add_classy_hooks(cls, hook_list):&lt;br /&gt;
        q = {}&lt;br /&gt;
        for h in hook_list:&lt;br /&gt;
            q[h] = getattr(cls, h)&lt;br /&gt;
        pluginapi.add_hooks_dict(q)&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        ldap = LDAPAuth(ldap_config)&lt;br /&gt;
        add_classy_hooks(ldap, [&#039;check_login&#039;])&lt;br /&gt;
    ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Proposed DB Schema ==&lt;br /&gt;
&lt;br /&gt;
Would remove pw_hash from User model. Reason is if someone would like to have the only way to login to an account is with OpenID or Persona. We would still require every account to have a unique username regardless of the Authentication enabled, thus username will be left in the User model. Email would be left in the User model for the same reason as username.&lt;br /&gt;
&lt;br /&gt;
===basic_auth:===&lt;br /&gt;
&lt;br /&gt;
pw_hash = Column(Unicode, nullable=False) &lt;br /&gt;
&lt;br /&gt;
user = Column(Integer, ForeignKey(User.id), nullable=False)&lt;br /&gt;
&lt;br /&gt;
===OpenID/Persona:===&lt;br /&gt;
&lt;br /&gt;
openid_url = Column(unicode, nullable=False)&lt;br /&gt;
&lt;br /&gt;
user = Column(Integer, ForeignKey(User,id), nullable=False)&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1288</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1288"/>
		<updated>2013-05-06T00:31:30Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* basic_auth */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Different use cases for different login systems ==&lt;br /&gt;
&lt;br /&gt;
Different login systems may affect the way auth stuff works differently.  For example, all of these cases are very different, but all fall under the &amp;quot;auth world view&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* You log in via some central auth system thing that uses the mediagoblin login page interface, but passes off the username/password to some other database.  (If that username and password exist remotely, do we need to &amp;quot;give&amp;quot; that username to a newly created user?)&lt;br /&gt;
* Persona/OpenID style: You have a user, but you have the option to log in the user via some external page and then come back.  In this case, we&#039;re probably not creating new users on-demand, and we don&#039;t really use the login page at all anyway.&lt;br /&gt;
&lt;br /&gt;
== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        def get_response(function, *args):&lt;br /&gt;
            for p in _auth_providers:&lt;br /&gt;
                response = p.function(*args)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
            raise NotImplemented(&amp;quot;No provider for %s&amp;quot; % functions)&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return get_response(&amp;quot;check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config1))&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config2))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Plugins can configure the individual instance (ldap server name)&lt;br /&gt;
* Plugins can instantiate multiple providers for different backends, like two different ldap servers&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more &amp;quot;hooky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers += hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
        ...&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: get_auth_provider}&lt;br /&gt;
        def get_auth_provider(): return AuthUserInterface()&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Still allows configuration on the individual instance&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
* No easy way to add multiple instances of one Provider&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This is the way we are going to implement auth plugins.&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    mediagoblin.ini:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        [plugins]&lt;br /&gt;
        [[plugins.ldap]]&lt;br /&gt;
        [[[server1]]]&lt;br /&gt;
        [[[server2]]]&lt;br /&gt;
&lt;br /&gt;
    auth/__init__.py:&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        ...&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login}&lt;br /&gt;
        #  or depending on the plugin&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            serv1 = ldap_thing(config1)&lt;br /&gt;
            serv2 = ldap_thing(config2)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv1.check_login)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv2.check_login)&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
        def check_login(user, password):&lt;br /&gt;
            if a: return True   # Yes, let them in&lt;br /&gt;
            if b: return False  # No and don&#039;t try other providers&lt;br /&gt;
            return None  # Don&#039;t know, try next provider.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
All the Pros from the interface design are not here:&lt;br /&gt;
* config data has to be global on the plugin, not local to the instantiated provider&lt;br /&gt;
* No straight way of doing multiple instances.&lt;br /&gt;
*: Yes, the individual hook could do it by itself&lt;br /&gt;
&lt;br /&gt;
==Various ideas on how to use classy authentication providers with the hooky authentication system==&lt;br /&gt;
 &lt;br /&gt;
    &amp;lt;nowiki&amp;gt;&lt;br /&gt;
     ...&lt;br /&gt;
    class LDAPLoginer():&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        my_ldap = LDAPLoginer(ldap_config)&lt;br /&gt;
        add_hook(&#039;login&#039;: my_ldap.login)&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
    def add_classy_hooks(cls, hook_list):&lt;br /&gt;
        q = {}&lt;br /&gt;
        for h in hook_list:&lt;br /&gt;
            q[h] = getattr(cls, h)&lt;br /&gt;
        pluginapi.add_hooks_dict(q)&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        ldap = LDAPAuth(ldap_config)&lt;br /&gt;
        add_classy_hooks(ldap, [&#039;check_login&#039;])&lt;br /&gt;
    ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Proposed DB Schema ==&lt;br /&gt;
&lt;br /&gt;
===basic_auth===&lt;br /&gt;
&lt;br /&gt;
pw_hash = Column(Unicode, nullable=False)&lt;br /&gt;
user = Column(Integer, ForeignKey(User.id), nullable=False)&lt;br /&gt;
&lt;br /&gt;
===openid/persona===&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1287</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1287"/>
		<updated>2013-05-06T00:16:58Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* __init__.py Base Class */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Different use cases for different login systems ==&lt;br /&gt;
&lt;br /&gt;
Different login systems may affect the way auth stuff works differently.  For example, all of these cases are very different, but all fall under the &amp;quot;auth world view&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* You log in via some central auth system thing that uses the mediagoblin login page interface, but passes off the username/password to some other database.  (If that username and password exist remotely, do we need to &amp;quot;give&amp;quot; that username to a newly created user?)&lt;br /&gt;
* Persona/OpenID style: You have a user, but you have the option to log in the user via some external page and then come back.  In this case, we&#039;re probably not creating new users on-demand, and we don&#039;t really use the login page at all anyway.&lt;br /&gt;
&lt;br /&gt;
== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        def get_response(function, *args):&lt;br /&gt;
            for p in _auth_providers:&lt;br /&gt;
                response = p.function(*args)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
            raise NotImplemented(&amp;quot;No provider for %s&amp;quot; % functions)&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return get_response(&amp;quot;check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config1))&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config2))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Plugins can configure the individual instance (ldap server name)&lt;br /&gt;
* Plugins can instantiate multiple providers for different backends, like two different ldap servers&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more &amp;quot;hooky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers += hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
        ...&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: get_auth_provider}&lt;br /&gt;
        def get_auth_provider(): return AuthUserInterface()&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Still allows configuration on the individual instance&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
* No easy way to add multiple instances of one Provider&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This is the way we are going to implement auth plugins.&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    mediagoblin.ini:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        [plugins]&lt;br /&gt;
        [[plugins.ldap]]&lt;br /&gt;
        [[[server1]]]&lt;br /&gt;
        [[[server2]]]&lt;br /&gt;
&lt;br /&gt;
    auth/__init__.py:&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        ...&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login}&lt;br /&gt;
        #  or depending on the plugin&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            serv1 = ldap_thing(config1)&lt;br /&gt;
            serv2 = ldap_thing(config2)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv1.check_login)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv2.check_login)&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
        def check_login(user, password):&lt;br /&gt;
            if a: return True   # Yes, let them in&lt;br /&gt;
            if b: return False  # No and don&#039;t try other providers&lt;br /&gt;
            return None  # Don&#039;t know, try next provider.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
All the Pros from the interface design are not here:&lt;br /&gt;
* config data has to be global on the plugin, not local to the instantiated provider&lt;br /&gt;
* No straight way of doing multiple instances.&lt;br /&gt;
*: Yes, the individual hook could do it by itself&lt;br /&gt;
&lt;br /&gt;
==Various ideas on how to use classy authentication providers with the hooky authentication system==&lt;br /&gt;
 &lt;br /&gt;
    &amp;lt;nowiki&amp;gt;&lt;br /&gt;
     ...&lt;br /&gt;
    class LDAPLoginer():&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        my_ldap = LDAPLoginer(ldap_config)&lt;br /&gt;
        add_hook(&#039;login&#039;: my_ldap.login)&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
    def add_classy_hooks(cls, hook_list):&lt;br /&gt;
        q = {}&lt;br /&gt;
        for h in hook_list:&lt;br /&gt;
            q[h] = getattr(cls, h)&lt;br /&gt;
        pluginapi.add_hooks_dict(q)&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        ldap = LDAPAuth(ldap_config)&lt;br /&gt;
        add_classy_hooks(ldap, [&#039;check_login&#039;])&lt;br /&gt;
    ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Proposed DB Schema ==&lt;br /&gt;
&lt;br /&gt;
===basic_auth===&lt;br /&gt;
&lt;br /&gt;
===openid/persona===&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1284</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1284"/>
		<updated>2013-05-03T16:12:49Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* __init__.py Base Class */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Different use cases for different login systems ==&lt;br /&gt;
&lt;br /&gt;
Different login systems may affect the way auth stuff works differently.  For example, all of these cases are very different, but all fall under the &amp;quot;auth world view&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* You log in via some central auth system thing that uses the mediagoblin login page interface, but passes off the username/password to some other database.  (If that username and password exist remotely, do we need to &amp;quot;give&amp;quot; that username to a newly created user?)&lt;br /&gt;
* Persona/OpenID style: You have a user, but you have the option to log in the user via some external page and then come back.  In this case, we&#039;re probably not creating new users on-demand, and we don&#039;t really use the login page at all anyway.&lt;br /&gt;
&lt;br /&gt;
== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        def get_response(function, *args):&lt;br /&gt;
            for p in _auth_providers:&lt;br /&gt;
                response = p.function(*args)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
            raise NotImplemented(&amp;quot;No provider for %s&amp;quot; % functions)&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return get_response(&amp;quot;check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config1))&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config2))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Plugins can configure the individual instance (ldap server name)&lt;br /&gt;
* Plugins can instantiate multiple providers for different backends, like two different ldap servers&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more &amp;quot;hooky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers += hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
        ...&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: get_auth_provider}&lt;br /&gt;
        def get_auth_provider(): return AuthUserInterface()&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Still allows configuration on the individual instance&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
* No easy way to add multiple instances of one Provider&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This is the way we are going to implement auth plugins.&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    mediagoblin.ini:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        [plugins]&lt;br /&gt;
        [[plugins.ldap]]&lt;br /&gt;
        [[[server1]]]&lt;br /&gt;
        [[[server2]]]&lt;br /&gt;
&lt;br /&gt;
    auth/__init__.py:&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        ...&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login}&lt;br /&gt;
        #  or depending on the plugin&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            serv1 = ldap_thing(config1)&lt;br /&gt;
            serv2 = ldap_thing(config2)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv1.check_login)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv2.check_login)&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
        def check_login(user, password):&lt;br /&gt;
            if a: return True   # Yes, let them in&lt;br /&gt;
            if b: return False  # No and don&#039;t try other providers&lt;br /&gt;
            return None  # Don&#039;t know, try next provider.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
All the Pros from the interface design are not here:&lt;br /&gt;
* config data has to be global on the plugin, not local to the instantiated provider&lt;br /&gt;
* No straight way of doing multiple instances.&lt;br /&gt;
*: Yes, the individual hook could do it by itself&lt;br /&gt;
&lt;br /&gt;
==Various ideas on how to use classy authentication providers with the hooky authentication system==&lt;br /&gt;
 &lt;br /&gt;
    &amp;lt;nowiki&amp;gt;&lt;br /&gt;
     ...&lt;br /&gt;
    class LDAPLoginer():&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        my_ldap = LDAPLoginer(ldap_config)&lt;br /&gt;
        add_hook(&#039;login&#039;: my_ldap.login)&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    ...&lt;br /&gt;
    def add_classy_hooks(cls, hook_list):&lt;br /&gt;
        q = {}&lt;br /&gt;
        for h in hook_list:&lt;br /&gt;
            q[h] = getattr(cls, h)&lt;br /&gt;
        pluginapi.add_hooks_dict(q)&lt;br /&gt;
&lt;br /&gt;
    for ldap_config in ldap_configs:&lt;br /&gt;
        ldap = LDAPAuth(ldap_config)&lt;br /&gt;
        add_classy_hooks(ldap, [&#039;check_login&#039;])&lt;br /&gt;
    ...&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1283</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1283"/>
		<updated>2013-05-03T14:23:03Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Non-Interfacey Design w/ hooks for every call: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Different use cases for different login systems ==&lt;br /&gt;
&lt;br /&gt;
Different login systems may affect the way auth stuff works differently.  For example, all of these cases are very different, but all fall under the &amp;quot;auth world view&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* You log in via some central auth system thing that uses the mediagoblin login page interface, but passes off the username/password to some other database.  (If that username and password exist remotely, do we need to &amp;quot;give&amp;quot; that username to a newly created user?)&lt;br /&gt;
* Persona/OpenID style: You have a user, but you have the option to log in the user via some external page and then come back.  In this case, we&#039;re probably not creating new users on-demand, and we don&#039;t really use the login page at all anyway.&lt;br /&gt;
&lt;br /&gt;
== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        def get_response(function, *args):&lt;br /&gt;
            for p in _auth_providers:&lt;br /&gt;
                response = p.function(*args)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
            raise NotImplemented(&amp;quot;No provider for %s&amp;quot; % functions)&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return get_response(&amp;quot;check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config1))&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config2))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Plugins can configure the individual instance (ldap server name)&lt;br /&gt;
* Plugins can instantiate multiple providers for different backends, like two different ldap servers&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more &amp;quot;hooky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers += hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
        ...&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: get_auth_provider}&lt;br /&gt;
        def get_auth_provider(): return AuthUserInterface()&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Still allows configuration on the individual instance&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
* No easy way to add multiple instances of one Provider&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This is the way we are going to implement auth plugins.&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    mediagoblin.ini:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        [plugins]&lt;br /&gt;
        [[plugins.ldap]]&lt;br /&gt;
        [[[server1]]]&lt;br /&gt;
        [[[server2]]]&lt;br /&gt;
&lt;br /&gt;
    auth/__init__.py:&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        ...&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login}&lt;br /&gt;
        #  or depending on the plugin&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            serv1 = ldap_thing(config1)&lt;br /&gt;
            serv2 = ldap_thing(config2)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv1.check_login)&lt;br /&gt;
            pluginapi.add_hook(&amp;quot;check_login&amp;quot;, serv2.check_login)&lt;br /&gt;
       ...&lt;br /&gt;
&lt;br /&gt;
        def check_login(user, password):&lt;br /&gt;
            if a: return True   # Yes, let them in&lt;br /&gt;
            if b: return False  # No and don&#039;t try other providers&lt;br /&gt;
            return None  # Don&#039;t know, try next provider.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
All the Pros from the interface design are not here:&lt;br /&gt;
* config data has to be global on the plugin, not local to the instantiated provider&lt;br /&gt;
* No straight way of doing multiple instances.&lt;br /&gt;
*: Yes, the individual hook could do it by itself&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1281</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1281"/>
		<updated>2013-05-02T20:10:07Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Non-Interfacey Design w/ hooks for every call: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        def get_response(function, *args):&lt;br /&gt;
            for p in _auth_providers:&lt;br /&gt;
                response = p.function(*args)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
            raise NotImplemented(&amp;quot;No provider for %s&amp;quot; % functions)&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return get_response(&amp;quot;check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config1))&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config2))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Plugins can configure the individual instance (ldap server name)&lt;br /&gt;
* Plugins can instantiate multiple providers for different backends, like two different ldap servers&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more &amp;quot;hooky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers += hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
        ...&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: get_auth_provider}&lt;br /&gt;
        def get_auth_provider(): return AuthUserInterface()&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Still allows configuration on the individual instance&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
* No easy way to add multiple instances of one Provider&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login}&lt;br /&gt;
        def check_login(user, password):&lt;br /&gt;
            if a: return True   # Yes, let them in&lt;br /&gt;
            if b: return False  # No and don&#039;t try other providers&lt;br /&gt;
            return None  # Don&#039;t know, try next provider.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
All the Pros from the interface design are not here:&lt;br /&gt;
* config data has to be global on the plugin, not local to the instantiated provider&lt;br /&gt;
* No straight way of doing multiple instances.&lt;br /&gt;
*: Yes, the individual hook could do it by itself&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1280</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1280"/>
		<updated>2013-05-02T20:09:39Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Interfacey Design w/ hooks: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        def get_response(function, *args):&lt;br /&gt;
            for p in _auth_providers:&lt;br /&gt;
                response = p.function(*args)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
            raise NotImplemented(&amp;quot;No provider for %s&amp;quot; % functions)&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return get_response(&amp;quot;check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config1))&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config2))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Plugins can configure the individual instance (ldap server name)&lt;br /&gt;
* Plugins can instantiate multiple providers for different backends, like two different ldap servers&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more &amp;quot;hooky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers += hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
        ...&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: get_auth_provider}&lt;br /&gt;
        def get_auth_provider(): return AuthUserInterface()&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Still allows configuration on the individual instance&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
* No easy way to add multiple instances of one Provider&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login}&lt;br /&gt;
        def check_login(user, password):&lt;br /&gt;
            if a: return True   # Yes, let them in&lt;br /&gt;
            if b: return False  # No and don&#039;t try other providers&lt;br /&gt;
            return None  # Don&#039;t know, try next provider.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
All the Pros from the interface design are not here:&lt;br /&gt;
* config data has to be global on the plugin, not local to the instantiated provider&lt;br /&gt;
* No straight way of doing multiple instances.&lt;br /&gt;
*: Yes, the individual hook could do it by itself&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1279</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1279"/>
		<updated>2013-05-02T20:08:51Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Interfacey Design w/o hooks: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        def get_response(function, *args):&lt;br /&gt;
            for p in _auth_providers:&lt;br /&gt;
                response = p.function(*args)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
            raise NotImplemented(&amp;quot;No provider for %s&amp;quot; % functions)&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return get_response(&amp;quot;check_login&amp;quot;, user, password)&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config1))&lt;br /&gt;
            add_auth_provider(SomeAuthPlugin(config2))&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Plugins can configure the individual instance (ldap server name)&lt;br /&gt;
* Plugins can instantiate multiple providers for different backends, like two different ldap servers&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface. Basicly a variation on the previous idea, just a bit more &amp;quot;hooky&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers += hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
        ...&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: get_auth_provider}&lt;br /&gt;
        def get_auth_provider(): return AuthUserInterface()&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
* Plugins could inherit from another plugin and override.&lt;br /&gt;
* Still allows configuration on the individual instance&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
* No easy way to add multiple instances of one Provider&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login}&lt;br /&gt;
        def check_login(user, password):&lt;br /&gt;
            if a: return True   # Yes, let them in&lt;br /&gt;
            if b: return False  # No and don&#039;t try other providers&lt;br /&gt;
            return None  # Don&#039;t know, try next provider.&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
All the Pros from the interface design are not here:&lt;br /&gt;
* config data has to be global on the plugin, not local to the instantiated provider&lt;br /&gt;
* No straight way of doing multiple instances.&lt;br /&gt;
*: Yes, the individual hook could do it by itself&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1277</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1277"/>
		<updated>2013-05-02T19:27:22Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
       def get_response(function(*args)):&lt;br /&gt;
           for p in _auth_providers:&lt;br /&gt;
               response = p.function(*args)&lt;br /&gt;
&lt;br /&gt;
        class AuthUserInterface(object):&lt;br /&gt;
&lt;br /&gt;
            def check_login(self, user, password):&lt;br /&gt;
                response = get_response(check_login(user, password))&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
                raise NotImplementedError&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(AuthPluginInterface())&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers = hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
       def get_response(function(*args)):&lt;br /&gt;
           for p in _auth_providers:&lt;br /&gt;
               response = p.function(*args)&lt;br /&gt;
&lt;br /&gt;
       class AuthUserInterface(object):&lt;br /&gt;
&lt;br /&gt;
            def check_login(self, user, password):&lt;br /&gt;
                response = get_response(check_login(user, password))&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
                raise NotImplementedError&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: AuthUserInterface()}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1276</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1276"/>
		<updated>2013-05-02T19:26:07Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Interfacey Design w/ hooks: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        class AuthUserInterface(object):&lt;br /&gt;
&lt;br /&gt;
            def check_login(self, user, password):&lt;br /&gt;
                for p in _auth_providers:&lt;br /&gt;
                    res = p.check_login(user, password)&lt;br /&gt;
                if res:&lt;br /&gt;
                    return res&lt;br /&gt;
                raise NotImplementedError&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(AuthPluginInterface())&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers = hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
       def get_response(function(*args)):&lt;br /&gt;
           for p in _auth_providers:&lt;br /&gt;
               response = p.function(*args)&lt;br /&gt;
&lt;br /&gt;
       class AuthUserInterface(object):&lt;br /&gt;
&lt;br /&gt;
            def check_login(self, user, password):&lt;br /&gt;
                response = get_response(check_login(user, password))&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
                raise NotImplementedError&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: AuthUserInterface()}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1275</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1275"/>
		<updated>2013-05-02T19:25:36Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Interfacey Design w/ hooks: */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        class AuthUserInterface(object):&lt;br /&gt;
&lt;br /&gt;
            def check_login(self, user, password):&lt;br /&gt;
                for p in _auth_providers:&lt;br /&gt;
                    res = p.check_login(user, password)&lt;br /&gt;
                if res:&lt;br /&gt;
                    return res&lt;br /&gt;
                raise NotImplementedError&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(AuthPluginInterface())&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers = hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
       def get_response(function(*args)):&lt;br /&gt;
           for p in _auth_providers:&lt;br /&gt;
               response = p.function(*args)&lt;br /&gt;
&lt;br /&gt;
       class AuthUserInterface(object):&lt;br /&gt;
&lt;br /&gt;
            def check_login(self, user, password):&lt;br /&gt;
                response = get_response(check_login(user, password)&lt;br /&gt;
                if response:&lt;br /&gt;
                    return response&lt;br /&gt;
                raise NotImplementedError&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: AuthUserInterface()}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1274</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1274"/>
		<updated>2013-05-02T18:58:39Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Auth Plugin Design Pros/Cons */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/o hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below. Calls would be added to _auth_providers list in the dummy class when setup_plugin is run. Each function in the dummy class would run through the _auth_providers list and return the response from the corresponding function from the last plugin in _auth_providers list.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        _auth_providers = []&lt;br /&gt;
        def add_auth_provider(provider):&lt;br /&gt;
            _auth_providers.append(provider)&lt;br /&gt;
&lt;br /&gt;
        class AuthUserInterface(object):&lt;br /&gt;
&lt;br /&gt;
            def check_login(self, user, password):&lt;br /&gt;
                for p in _auth_providers:&lt;br /&gt;
                    res = p.check_login(user, password)&lt;br /&gt;
                if res:&lt;br /&gt;
                    return res&lt;br /&gt;
                raise NotImplementedError&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def setup_plugin():&lt;br /&gt;
            add_auth_provider(AuthPluginInterface())&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
*basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Interfacey Design w/ hooks:===&lt;br /&gt;
&lt;br /&gt;
Using an interface design similar to the Base Class design below and using hooks to register the auth_plugin interface.&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def setup_auth():&lt;br /&gt;
            global _auth_providers&lt;br /&gt;
            _auth_providers = hook_runall(&amp;quot;auth_provider&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        class AuthUserInterface(object):&lt;br /&gt;
&lt;br /&gt;
            def check_login(self, user, password):&lt;br /&gt;
                for p in _auth_providers:&lt;br /&gt;
                    res = p.check_login(user, password)&lt;br /&gt;
                if res:&lt;br /&gt;
                    return res&lt;br /&gt;
                raise NotImplementedError&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_provider&amp;quot;: AuthUserInterface()}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
* would basically be duplicating the code for hook_handle&lt;br /&gt;
&lt;br /&gt;
===Non-Interfacey Design w/ hooks for every call:===&lt;br /&gt;
&lt;br /&gt;
This design would have a plugin &amp;quot;template&amp;quot; in auth/__init__.py similar to the Interfacey designs, except that it would use hook_handle() for each function.&lt;br /&gt;
&lt;br /&gt;
 Ex.&lt;br /&gt;
    auth/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        def check_login(user, Password):&lt;br /&gt;
            return hook_handle(&amp;quot;auth_check_login&amp;quot;, user, password)&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    auth_plugin/__init__.py:&amp;lt;nowiki&amp;gt;&lt;br /&gt;
        hooks = {&amp;quot;auth_check_login&amp;quot;: check_login&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Pros====&lt;br /&gt;
&lt;br /&gt;
* Simpler to implement&lt;br /&gt;
&lt;br /&gt;
====Cons====&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1273</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1273"/>
		<updated>2013-05-02T18:22:14Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== Auth Plugin Design Pros/Cons ==&lt;br /&gt;
&lt;br /&gt;
Interfacey Design w/o hooks:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;nowiki&amp;gt;Place holder&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Interfacey Design w/ hooks:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;nowiki&amp;gt;Insert non-formatted text here&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Non-Interfacey Design w/ hooks for every call:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;nowiki&amp;gt;Insert non-formatted text here&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Meeting&amp;diff=1272</id>
		<title>Meeting</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Meeting&amp;diff=1272"/>
		<updated>2013-05-02T18:09:09Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Next Meeting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== MediaGoblin Monthly Meeting ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;When:&#039;&#039;&#039; 9:00 am Pacific Time first Saturday of the month. [http://www.timeanddate.com/worldclock/converter.html Convert time to your timezone].  Print current UTC time: &amp;lt;code&amp;gt;date -u +&amp;quot;It&#039;s %F %T UTC&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Where:&#039;&#039;&#039; IRC #mediagoblin on irc.freenode.net&lt;br /&gt;
&lt;br /&gt;
Always announced several days in advance on the [http://lists.mediagoblin.org/pipermail/devel/ mailing list] as is date adjustments, agenda discussion and other meeting preparation.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Purpose:&#039;&#039;&#039; The idea is to discuss the past month, what happened, what was good, what should be done better. And to create roadmap for the upcoming month and assign tasks to people willing to handle them.&lt;br /&gt;
&lt;br /&gt;
Typical Agenda topics:&lt;br /&gt;
&lt;br /&gt;
* What happened in the last month, what was good, what could be better next time?&lt;br /&gt;
* What should be done next month?&lt;br /&gt;
&lt;br /&gt;
Meetings are logged. [http://mediagoblin.org/irclogs/ Logs for past meetings.]&lt;br /&gt;
&lt;br /&gt;
== Next Meeting ==&lt;br /&gt;
&lt;br /&gt;
[[meeting-2013-05-04|May 4th, 2013, 9:00 am Pacific Time (2013-05-04 16:00 UTC)]]&lt;br /&gt;
&lt;br /&gt;
* GSOC and Gnome Outreach for Women participation update&lt;br /&gt;
* Mention the bug triage meeting&lt;br /&gt;
* Improving our unit tests?&lt;br /&gt;
* 0.4.0 release coming soon&lt;br /&gt;
* Help review code?&lt;br /&gt;
&lt;br /&gt;
== Past Meetings ==&lt;br /&gt;
&lt;br /&gt;
=== April 6, 2013, 9:00 am Pacific Time (2013-03-30 16:00 UTC) ===&lt;br /&gt;
&lt;br /&gt;
* Plugins update&lt;br /&gt;
* Post-libreplanet sprint merging&lt;br /&gt;
* Gstreamer 1.0 stuff (if Joar is here!)&lt;br /&gt;
* GSOC and Gnome Outreach for Women participation&lt;br /&gt;
* ???&lt;br /&gt;
&lt;br /&gt;
=== March 2nd, 2013, 9:00 am Pacific Time (2013-03-02 16:00 UTC) ===&lt;br /&gt;
&lt;br /&gt;
* Bug triage day discussion&lt;br /&gt;
* Upgrading Trac to 1.0&lt;br /&gt;
* Next release: 0.3.3&lt;br /&gt;
* Consider have release dates?&lt;br /&gt;
* Plugin stystem&lt;br /&gt;
* Consider moving to GStreamer 1.0&lt;br /&gt;
** Debian - 1.0 in sid&lt;br /&gt;
** Ubuntu - 1.0 in 12.10&lt;br /&gt;
*** Possibly backports for 12.04&lt;br /&gt;
** Fedora - 1.0 in 18&lt;br /&gt;
* Upcoming conferences and hackathons&lt;br /&gt;
&lt;br /&gt;
=== February 9th, 2013, 9:00 am Pacific Time (2013-02-09 16:00 UTC) ===&lt;br /&gt;
&lt;br /&gt;
* 0.3.3 milestone!  What about our next release? :)&lt;br /&gt;
* Where to put Developer docs?&lt;br /&gt;
*: Our Documentation for developers is currently a bit split. Some are on the wiki, some in the main docs. There are pros and cons for both. We should consider where to put things. One place? Which? Or decide on an individual basis?&lt;br /&gt;
*: Good about main docs: Easy to integrate source code doc strings. That way internal api docs can be kept mostly up to date.&lt;br /&gt;
*: Good about wiki: Doesn&#039;t feel so &amp;quot;set in stone&amp;quot;.&lt;br /&gt;
* wiki spam: Do we want to change something?&lt;br /&gt;
* [http://lists.mediagoblin.org/pipermail/devel/2012-November/000307.html Designing features!]&lt;br /&gt;
* Plugins, and architecting for plugins&lt;br /&gt;
* Chris Webber gives updates on how he&#039;s settling into his role ;)&lt;br /&gt;
&lt;br /&gt;
=== October 13th, 2012, 9:00 am Pacific Time (2012-10-13 16:00 UTC) ===&lt;br /&gt;
&lt;br /&gt;
* 0.3.2 release&lt;br /&gt;
** What existing features need to be wrapped up?&lt;br /&gt;
*** Werkzeug switch&lt;br /&gt;
** What time might we do the release?&lt;br /&gt;
* Fundraising campaign&lt;br /&gt;
** Keeping things going mid-campaign&lt;br /&gt;
** You have questions?  I have answers, kinda :)&lt;br /&gt;
* Getting new contributors involved&lt;br /&gt;
* Plugins?  New features?&lt;br /&gt;
&lt;br /&gt;
==== Etherpad ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AGENDA&lt;br /&gt;
&lt;br /&gt;
     0.3.2 release &lt;br /&gt;
&lt;br /&gt;
     What existing features need to be wrapped up? &lt;br /&gt;
&lt;br /&gt;
     Werkzeug switch &lt;br /&gt;
&lt;br /&gt;
     What time might we do the release? &lt;br /&gt;
&lt;br /&gt;
    Congrats to Deb from the mediagoblin team! Congrats de Deb!&lt;br /&gt;
&lt;br /&gt;
     Fundraising campaign &lt;br /&gt;
&lt;br /&gt;
     Keeping things going mid-campaign &lt;br /&gt;
&lt;br /&gt;
     You have questions?  I have answers, kinda :) &lt;br /&gt;
&lt;br /&gt;
     Getting new contributors involved &lt;br /&gt;
&lt;br /&gt;
     Plugins?  New features? &lt;br /&gt;
&lt;br /&gt;
-- http://wiki.mediagoblin.org/Meeting#Next_Meeting&lt;br /&gt;
Fundraising stuff&lt;br /&gt;
Things are going great mostly when people check it out!&lt;br /&gt;
But how to spread the word?&lt;br /&gt;
&lt;br /&gt;
    should contact more podcasts, etc&lt;br /&gt;
&lt;br /&gt;
    currently working with FSF on this&lt;br /&gt;
&lt;br /&gt;
    need community to spread the word!&lt;br /&gt;
&lt;br /&gt;
    List of places already spreaded list and contacted&lt;br /&gt;
&lt;br /&gt;
VideoThumbnailerMarkII&lt;br /&gt;
New video thumbnailer, rewritten to try to eliminate a bug in the old one where processing would stall.&lt;br /&gt;
New bugs introduce (of course ;)&lt;br /&gt;
Collections&lt;br /&gt;
Merged - Thanks aaronw!&lt;br /&gt;
WebOb =&amp;gt; Werkzeug switch&lt;br /&gt;
Made some things break. Need help with testing + bugfixes&lt;br /&gt;
borked stuffs:&lt;br /&gt;
&lt;br /&gt;
    Accessing paths without trailing slashes, e.g. /submit (instead of /submit/)&lt;br /&gt;
&lt;br /&gt;
    Still a lot of legacy WebOb responses (such as webob.exc.HTTPFound() HTTPForbidden() left)&lt;br /&gt;
&lt;br /&gt;
API&lt;br /&gt;
Delivered to mrn.is, tryggvib will test it and get back with feedback.&lt;br /&gt;
Working, still a lot of room for improvements.&lt;br /&gt;
Mostly done, usable, still room for improvements. Example applications:&lt;br /&gt;
&lt;br /&gt;
    https://github.com/jwandborg/automgtic&lt;br /&gt;
&lt;br /&gt;
    https://github.com/jwandborg/omgmg&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== September 1st, 2012, 9:00 am Pacific Time (2012-09-01 16:00 UTC) ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2012-09-01.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
* FIXME - can someone type in summary here?&lt;br /&gt;
&lt;br /&gt;
=== August 4th, 2012, 9:00 am Pacific Time (2012-08-04 16:00 UTC) ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2012-08-04.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
* Release schedule&lt;br /&gt;
* Plugins and themes! Who&#039;s working on one? What problems are you having? -- Please write up issues for problems so they can get fixed!&lt;br /&gt;
* Should we namespace plugins? If so, how should we namespace plugins?&lt;br /&gt;
** Python 3.3 will have support for namespace plugins. [http://www.python.org/dev/peps/pep-0420/#namespace-packages-today]&lt;br /&gt;
** In Python &amp;gt;=2.3, &amp;lt;3.3 it&#039;s a hack [http://www.python.org/dev/peps/pep-0402/#the-problem][http://www.python.org/dev/peps/pep-0420/#namespace-packages-today]&lt;br /&gt;
** Flask has a workaround[https://github.com/mitsuhiko/flask/blob/master/flask/ext/__init__.py]&lt;br /&gt;
&lt;br /&gt;
=== July 7th, 2012, 9:00 am Pacific Time (2012-07-07 16:00 UTC) ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2012-07-07.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
Announcements:&lt;br /&gt;
&lt;br /&gt;
* Anyone who wants to edit the wiki needs to be in the goblin army group. Ask Will or Chris to get added.&lt;br /&gt;
* Plugin infrastructure landed. If you&#039;re interested in writing plugins, talk to Will. Some documentation at http://docs.mediagoblin.org/#part-2-plugin-writer-s-guide&lt;br /&gt;
&lt;br /&gt;
Agenda:&lt;br /&gt;
&lt;br /&gt;
* Keyboard shortcuts ([http://issues.mediagoblin.org/ticket/346 #346])&lt;br /&gt;
* Ticket triaging?&lt;br /&gt;
* Base plugin stuff!&lt;br /&gt;
* Theming&lt;br /&gt;
* Conference: OSCON&lt;br /&gt;
* Chris Webber&#039;s new &amp;quot;office hours&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== June 2nd, 2012, 9:00 am Pacific Time ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2012-06-02.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
* docs changes&lt;br /&gt;
** Will split the docs/ guide into a Site Administrator&#039;s Guide and a Plugin Writer&#039;s Guide&lt;br /&gt;
** Has anyone looked at the Plugin Writer&#039;s Guide, yet?&lt;br /&gt;
** Will wants to add a &amp;quot;Contributor&#039;s Guide&amp;quot; to docs/ which he&#039;d update from the wiki before every release&lt;br /&gt;
* Is there a way to improve our unit tests and motivation to write them?&lt;br /&gt;
** Simulating a browser by the way of [http://phantomjs.org/ PhantomJS], [http://seleniumhq.org/ Selenium] instead of having code simulating other code against itself might be more natural to write and even more testing the actual application. I have a good feeling about this, please prove me wrong if I&#039;d be. --[[User:Joar|Joar]] 08:53, 28 May 2012 (EDT)&lt;br /&gt;
* Administrative panel/tools and user uploads panel&lt;br /&gt;
* Git and tickets &lt;br /&gt;
* Plugins&lt;br /&gt;
** What&#039;s the state of things?&lt;br /&gt;
** Documentation&lt;br /&gt;
** What plugins might we want to build for this upcoming release?&lt;br /&gt;
** What things do we currently have that we might want to pluginify?&lt;br /&gt;
* State of kuneco/federation mini-update (Chris)&lt;br /&gt;
&lt;br /&gt;
=== May 5th, 2012, 9:00 am Pacific Time ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2012-05-05.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
* Post-release reflections&lt;br /&gt;
** Woohoo, release!&lt;br /&gt;
** How did this release process go?&lt;br /&gt;
*** We should talk about that conference.&lt;br /&gt;
** What&#039;s left to clean up?&lt;br /&gt;
*** Mongokit-&amp;gt;SQL &amp;quot;style&amp;quot; query conversion?&lt;br /&gt;
*** Other cruft code?&lt;br /&gt;
* What are our next goals?&lt;br /&gt;
** Plugins&lt;br /&gt;
** Federation&lt;br /&gt;
** Favoriting&lt;br /&gt;
*** Take that, Pinterest! ;)&lt;br /&gt;
** Galleries&lt;br /&gt;
** Theming&lt;br /&gt;
*** Using sass would be neat&lt;br /&gt;
** Access restrictions&lt;br /&gt;
*** User management, or having a &amp;quot;secret url&amp;quot; that is not in the photo index that you can share with friends and generate as needed for any media type&lt;br /&gt;
** What about traffic? Some of us will host GMG on limited plans.&lt;br /&gt;
** Some kind of coding guidelines? Do we have a philosophy like &amp;quot;Keep it Simple, Stupid&amp;quot;&lt;br /&gt;
*** This concerns things like: Should plugins land in core eventually, do we want to support ALL THE MEDIA TYPES, ...&lt;br /&gt;
** Podcasting support?&lt;br /&gt;
** Things that have been hanging???&lt;br /&gt;
** Bugtrackers and milestone?&lt;br /&gt;
** More??? We should organize things!&lt;br /&gt;
* jancborchardt and his team of UX wizard-students&lt;br /&gt;
* Website redesign&lt;br /&gt;
* OpenShift?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== April 7th, 2012, 4:00 pm UTC ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2012-04-07.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
* Post-SQL stuff&lt;br /&gt;
* Pending 0.0.3 release!&lt;br /&gt;
* Are there stray patches/branches to be merged?&lt;br /&gt;
* Our glorious upcoming plugin future! (Update from Will)&lt;br /&gt;
&lt;br /&gt;
=== March 3rd, 2012, 9:00 am Pacific Time ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2012-03-03.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
* [[GSOC 2012]]&lt;br /&gt;
* State of the SQL transition (preview: it&#039;s super close, but we need help!)&lt;br /&gt;
* Plugin discussion (Will can&#039;t make this, but we should talk about use cases)&lt;br /&gt;
* MediaGoblin at upcoming conferences&lt;br /&gt;
* PageKite accounts&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2012-02 (held on 2012-02-04) ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2012-02-04.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
* Code style guide?  See also: http://issues.mediagoblin.org/ticket/197&lt;br /&gt;
* Kuneco/federation&lt;br /&gt;
* API&lt;br /&gt;
* More testing discussion?&lt;br /&gt;
* Theming?&lt;br /&gt;
* Preliminary plugin discussion&lt;br /&gt;
* Status update from the &amp;quot;SQL Team&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Some of the decisions:&lt;br /&gt;
&lt;br /&gt;
* file an issue about proper &amp;amp;lt;audio&amp;amp;gt; support.&lt;br /&gt;
* some TODOs recorded&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2011-12 (held on 2011-12-03) ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2011-12-03.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
* We plan to create a plugin system.  Do we want to create that soon or push it off until things settle a bit more?  ([[User:Willkg|Willkg]] 08:54, 10 November 2011 (EST))&lt;br /&gt;
* [[Feature Ideas]]: What should we do about the wiki page? Keep it and have it as a monthly topic for &amp;quot;what next&amp;quot;? Convert everything to long waiting bugs?&lt;br /&gt;
* Possibility of an [[SQL Database Backend]]?&lt;br /&gt;
*: &#039;executive summary&#039; (well, you should read the long docs): &amp;quot;We could move to sql. It&#039;s probably replacing one type of pain by another type of pain, but those are somewhat comparable. Leaving the main question: Do we want to occupy our main devs for some long time with this task and loose momentum?&amp;quot;&lt;br /&gt;
* Schendje&#039;s [http://wiki.mediagoblin.org/Feature_Ideas/Activities activities proposal]&lt;br /&gt;
* &amp;quot;Coming up next&amp;quot; blogpost draft by Deb Nicholson&lt;br /&gt;
* Jef&#039;s requests:&lt;br /&gt;
** Ticket #466 &amp;quot;Use of &amp;quot;Submit&amp;quot; in site copy is sterile and not as friendly and welcoming as it could be&amp;quot;. I&#039;d really like to change this soon to something more suitable. How can we improve the wording here? Some alternatives have been mentioned in the bug report, but which one should we pick? Link: http://bugs.foocorp.net/issues/466&lt;br /&gt;
** The concept and naming of &amp;quot;favourites&amp;quot;. We&#039;ll (hopefully) be able to &amp;quot;favourite&amp;quot; media soon, which I *think* means that 1) it&#039;ll work like a &amp;quot;I like this&amp;quot; comment, a quick token of appreciation, 2) it&#039;ll be added to your list of favourites so you can save and promote it, and 3) we could maybe use the number of favourites as a ranking. What I&#039;d like to know is: is that the intended purpose? If so, should we name them favo(u)rites or something else? &amp;quot;Like&amp;quot;, &amp;quot;love&amp;quot;, &amp;quot;save&amp;quot;, &amp;quot;appreciate&amp;quot;, &amp;quot;heart&amp;quot;, &amp;quot;high five&amp;quot; and many more could all be contenders. And the name should be consistent with the action and purpose, of course. So I&#039;d like to clear up how and why we will use favourites and what we should call them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2011-11 (held on 2011-11-05) ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2011-11-05.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
* What happened in the last month, what was good, what could be better next time?&lt;br /&gt;
** Release:&lt;br /&gt;
*** Good: 0.1.0 released!&lt;br /&gt;
*** Bad: postponing vs not postponing&lt;br /&gt;
** Sites and deployment documentation:&lt;br /&gt;
*** Good: new mediagoblin.org&lt;br /&gt;
*** Good: deployment documentation&lt;br /&gt;
*** Bad: py-bcrypt’s site was down just after the release, so the virtualenv deployment didn’t work, and it wasn’t clear how to fix it.&lt;br /&gt;
** Live instances:&lt;br /&gt;
*** Joar has a live instance!&lt;br /&gt;
*** But what does it mean? Should ordinary users start using it?&lt;br /&gt;
**** Details at [[User:Joar/mg.wandborg.se]] -- [[User:Joar|Joar]] 17:01, 6 November 2011 (EST)&lt;br /&gt;
*** nyergler added a note about &amp;quot;heartbeat&amp;quot;/status to API notes&lt;br /&gt;
* What should be done next month?&lt;br /&gt;
* Starting real work on federation (via OStatus)... and do we split any of this work out into its own library?&lt;br /&gt;
* An API&lt;br /&gt;
* Creative Commons licensing tools&lt;br /&gt;
* Merging in the multimedia/video branch&lt;br /&gt;
*: (this is *very close* already actually thanks to the hard work of Joar Wandborg!  But we need some help on the gstreamer front to fix a few issues... if you or someone you know is an expert in this area we could really use their help to make the videos that come out smoother!)&lt;br /&gt;
* Rollover items from 0.1.0&lt;br /&gt;
* Multiple file upload interface&lt;br /&gt;
* Drag and drop uploads interface (probably related!)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2011-10 (held on 2011-10-01) ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2011-10-01.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
This month&#039;s meeting was a quickly announced short meeting. The project is getting back on track and next month&#039;s meeting will be scheduled more properly. A bunch of people were around.&lt;br /&gt;
&lt;br /&gt;
The most important decisions:&lt;br /&gt;
* The project will keep monthly releases. They&#039;re the heartbeat of the project.&lt;br /&gt;
* Release 0.1.0 this sunday/monday.&lt;br /&gt;
* New website will hopefully be deployed in the next few days.&lt;br /&gt;
* And the following things are planned to happen during this month: Most importantly federation. The developers have decided to make up their minds on what federation aactually should mean for MediaGoblin. Concerning code, probably &amp;quot;activity streams&amp;quot; are the first goal. If there is no (good) python library for this, a new stand alone library may be created. If so, a name for it has to be found. It should have something about communication in it. And the other thing to happen during this month is an ongoing discussion about &amp;quot;bus factor&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2011-09 (held on 2011-09-03) ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2011-09-03.txt IRC log]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2011-08 (held on 2011-08-06) ===&lt;br /&gt;
&lt;br /&gt;
[http://mediagoblin.org/irclogs/irc_meeting_2011-08-06.txt IRC log]&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1267</id>
		<title>Authentication</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=Authentication&amp;diff=1267"/>
		<updated>2013-04-30T23:09:05Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: /* Designing Authentication API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Designing Authentication API ==&lt;br /&gt;
&lt;br /&gt;
To make our auth(entication) system more modular, we&#039;re likely going to have some sort of interface style API for it. This page is to design it.&lt;br /&gt;
&lt;br /&gt;
== __init__.py Base Class ==&lt;br /&gt;
&lt;br /&gt;
***This is a brainstorm of some of the functions and variables that the base class should include.***&lt;br /&gt;
&lt;br /&gt;
basic_auth = False # Will be used to render to correct forms if using both basic_auth and openid/persona&lt;br /&gt;
&lt;br /&gt;
login_form = # Plugin LoginForm class&lt;br /&gt;
&lt;br /&gt;
registration_form = # Plugin RegistrationForm class&lt;br /&gt;
&lt;br /&gt;
    class UserAuthInterface(object):&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&lt;br /&gt;
        deg _raise_not_implemented(self):&lt;br /&gt;
            # Will raise a warning if some component of this interface isn&#039;t implemented by an Auth plugin&lt;br /&gt;
&lt;br /&gt;
        def check_login(self, user, password):&lt;br /&gt;
            return False&lt;br /&gt;
        &lt;br /&gt;
        def get_user(self, *args):&lt;br /&gt;
            # Will query database and will return a User() object&lt;br /&gt;
&lt;br /&gt;
        def create_user(self, *args):&lt;br /&gt;
            # Will create a new user and save to the db.&lt;br /&gt;
            # Will return User() object&lt;br /&gt;
&lt;br /&gt;
        def extra_validation(self, register_form, *args):&lt;br /&gt;
            # Will query the db and add error messages to register_form if any.&lt;br /&gt;
            # return true if able to create new user &lt;br /&gt;
&lt;br /&gt;
        def get_user_metadata(self, user):&lt;br /&gt;
            # Return a nice object with metadata from auth provider. Used to pre-fill registration forms&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
	<entry>
		<id>https://wiki.mediagoblin.org/index.php?title=HackingHowto&amp;diff=1251</id>
		<title>HackingHowto</title>
		<link rel="alternate" type="text/html" href="https://wiki.mediagoblin.org/index.php?title=HackingHowto&amp;diff=1251"/>
		<updated>2013-04-20T22:36:19Z</updated>

		<summary type="html">&lt;p&gt;Rodney757: Making Create a development environment more clear&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Hacking HOWTO =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== So you want to hack on GNU MediaGoblin? ==&lt;br /&gt;
&lt;br /&gt;
First thing to do is check out the [http://mediagoblin.org/join/ web site] where we list all the project&lt;br /&gt;
infrastructure including:&lt;br /&gt;
&lt;br /&gt;
* the IRC channel&lt;br /&gt;
* the mailing list&lt;br /&gt;
* the issue tracker&lt;br /&gt;
&lt;br /&gt;
Additionally, we have information on how to get involved, who to talk&lt;br /&gt;
to, what needs to be worked on, and other things besides!&lt;br /&gt;
&lt;br /&gt;
Second thing to do is take a look at [http://docs.mediagoblin.org/devel/codebase.html codebase chapter] where&lt;br /&gt;
we&#039;ve started documenting how GNU MediaGoblin is built and how to add&lt;br /&gt;
new things.  If you&#039;re planning on contributing in python, you should be aware&lt;br /&gt;
of [http://www.python.org/dev/peps/pep-0008/ PEP-8], the official Python style guide,&lt;br /&gt;
which we follow.&lt;br /&gt;
&lt;br /&gt;
Third you&#039;ll need to get the requirements.&lt;br /&gt;
&lt;br /&gt;
Fourth, you&#039;ll need to build a development environment.  We use an&lt;br /&gt;
in-package checkout of virtualenv.  This isn&#039;t the convenional way to&lt;br /&gt;
install virtualenv (normally you don&#039;t install virtualenv inside the&lt;br /&gt;
package itself) but we&#039;ve found that it&#039;s significantly easier for&lt;br /&gt;
newcomers who aren&#039;t already familiar with virtualenv.  If you *are*&lt;br /&gt;
already familiar with virtualenv, feel free to just install&lt;br /&gt;
mediagoblin in your own virtualenv setup... the necessary adjustments&lt;br /&gt;
should be obvious.&lt;br /&gt;
&lt;br /&gt;
== Getting requirements ==&lt;br /&gt;
&lt;br /&gt;
First, you need to have the following installed before you can build&lt;br /&gt;
an environment for hacking on GNU MediaGoblin:&lt;br /&gt;
&lt;br /&gt;
* Python 2.6 or 2.7  - http://www.python.org/ (You&#039;ll need Python as well as the dev files for building modules.)&lt;br /&gt;
* python-lxml        - http://lxml.de/&lt;br /&gt;
* git                - http://git-scm.com/&lt;br /&gt;
* SQLAlchemy 0.7.0 or higher   - http://www.sqlalchemy.org/&lt;br /&gt;
* Python Imaging Library (PIL) - http://www.pythonware.com/products/pil/&lt;br /&gt;
* virtualenv         - http://www.virtualenv.org/&lt;br /&gt;
* Python GStreamer Bindings - http://gstreamer.freedesktop.org/modules/gst-python.html&lt;br /&gt;
&lt;br /&gt;
=== GNU/Linux ===&lt;br /&gt;
&lt;br /&gt;
==== Debian and derivatives ====&lt;br /&gt;
&lt;br /&gt;
If you&#039;re running Debian GNU/Linux or a Debian-derived distribution&lt;br /&gt;
such as Debian, Mint, or [http://bugs.foocorp.net/issues/478 Ubuntu 10.10+], running the following should install these&lt;br /&gt;
requirements:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|sudo apt-get install git-core python python-dev python-lxml python-imaging python-virtualenv python-gst0.10 libjpeg8-dev}}&lt;br /&gt;
&lt;br /&gt;
==== Fedora / RedHat(?) ====&lt;br /&gt;
&lt;br /&gt;
On Fedora:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|yum install python-paste-deploy python-paste-script git-core python python-devel python-lxml python-imaging python-virtualenv gstreamer-python}}&lt;br /&gt;
&lt;br /&gt;
=== Mac OS X ===&lt;br /&gt;
&lt;br /&gt;
==== Mac OS X Lion ====&lt;br /&gt;
&lt;br /&gt;
Download the Newest Python.&lt;br /&gt;
&lt;br /&gt;
Git is already installed.&lt;br /&gt;
&lt;br /&gt;
Python-lxml: http://muffinresearch.co.uk/archives/2009/03/05/install-lxml-on-osx/ with sudo&lt;br /&gt;
&lt;br /&gt;
Python Imaging Library (PIL): http://code.google.com/appengine/docs/python/images/installingPIL.html#mac&lt;br /&gt;
&lt;br /&gt;
Libjpeg &amp;amp; Libpng: http://ethan.tira-thompson.org/Mac_OS_X_Ports.html Combo Installer&lt;br /&gt;
&lt;br /&gt;
==== Mac OS X Snow Leopard ====&lt;br /&gt;
&lt;br /&gt;
# You will probably want to install MacPorts this will give you access to many free software packages in the same manner to apt-get and yum: https://www.macports.org/install.php&lt;br /&gt;
# Ensure you install Git and the command line tools: https://help.github.com/articles/set-up-git#platform-mac&lt;br /&gt;
# Once both of those are installed type this in your terminal and enter your password when prompted for it {{Cmd|sudo port install python27 py27-lxml py27-sqlalchemy py27-pil py27-virtualenv py27-gst-python py27-pastescript}}&lt;br /&gt;
&lt;br /&gt;
=== Microsoft Windows ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Thanks wctype!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==== Getting requirements ====&lt;br /&gt;
&lt;br /&gt;
* Python 2.7  -  [http://www.python.org/download/ Download] &amp;lt;!-- http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi --&amp;gt;&lt;br /&gt;
* git - [https://github.com/msysgit/git/downloads Download] &amp;lt;!-- https://github.com/downloads/msysgit/git/Git-1.7.11-preview20120620.exe --&amp;gt;&lt;br /&gt;
* python-lxml - [http://pypi.python.org/pypi/lxml/2.3.5#downloads Tarball] [http://www.lfd.uci.edu/~gohlke/pythonlibs/#pil Binaries] &amp;lt;!-- http://pypi.python.org/packages/source/l/lxml/lxml-2.3.5.tar.gz, http://www.lfd.uci.edu/~gohlke/pythonlibs/z8sp4uqu/lxml-2.3.5.win32-py2.7.exe --&amp;gt;&lt;br /&gt;
* Python Imaging Library (PIL) - [http://www.pythonware.com/products/pil/ Download] &amp;lt;!-- http://effbot.org/downloads/PIL-1.1.7.win32-py2.7.exe] --&amp;gt;&lt;br /&gt;
* virtualenv - [http://pypi.python.org/pypi/virtualenvwrapper-win/1.0.8#downloads Download] &amp;lt;!-- http://pypi.python.org/packages/source/v/virtualenvwrapper-win/virtualenvwrapper-win-1.0.8.zip --&amp;gt;&lt;br /&gt;
* OSSBuild project provides reasonably up-to-date binaries of GStreamer - [https://code.google.com/p/ossbuild/downloads/list Download] &amp;lt;!-- http://ossbuild.googlecode.com/files/GStreamer-WinBuilds-GPL-x86.msi --&amp;gt;&lt;br /&gt;
* py-bcrypt - [https://bitbucket.org/alexandrul/py-bcrypt/downloads/ Download] &amp;lt;!-- https://bitbucket.org/alexandrul/py-bcrypt/downloads/py-bcrypt-0.2.post1.win32-py2.7.exe --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;You can help:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you have instructions for other GNU/Linux distributions, Windows, or Mac OS X to set&lt;br /&gt;
up requirements, [http://mediagoblin.org/join/ let us know]!&lt;br /&gt;
&lt;br /&gt;
== How to set up and maintain an environment for hacking with virtualenv ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Requirements&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No additional requirements.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Create a development environment&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
After installing the requirements, follow these steps:&lt;br /&gt;
&lt;br /&gt;
* Clone the repository: {{Cmd|git clone &amp;lt;nowiki&amp;gt;git://gitorious.org/mediagoblin/mediagoblin.git&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
* Change directories to your new checkout: {{Cmd|cd mediagoblin}}&lt;br /&gt;
* Checkout git submodules: {{Cmd|git submodule init}} {{Cmd|git submodule update}}&lt;br /&gt;
* Set up the in-package virtualenv:&lt;br /&gt;
  (virtualenv --system-site-packages . || virtualenv .) &lt;br /&gt;
* Run setup.py:&lt;br /&gt;
  {{Cmd|./bin/python setup.py develop}}&lt;br /&gt;
* Init the database:&lt;br /&gt;
  {{Cmd|./bin/gmg dbupdate}}&lt;br /&gt;
&lt;br /&gt;
That&#039;s it!&lt;br /&gt;
&lt;br /&gt;
(If you have troubles in the remaining steps, consider try installing&lt;br /&gt;
virtualenv with one of the flags --setuptools, --distribute or possibly --no-site-packages.  Additionally, if your system has python3.X as the default, you might need to do virtualenv --python=python2.7 or --python=python2.6)&lt;br /&gt;
&lt;br /&gt;
If you have problems, please [http://mediagoblin.org/join/ let us know]!&lt;br /&gt;
&lt;br /&gt;
== Updating an existing environment ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Updating for dependency changes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
While hacking on GNU MediaGoblin over time, you&#039;ll eventually have to&lt;br /&gt;
update your development environment because the dependencies have&lt;br /&gt;
changed.&lt;br /&gt;
&lt;br /&gt;
To do that, run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./bin/python setup.py develop --upgrade &amp;amp;&amp;amp; ./bin/gmg dbupdate}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Updating for code changes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Cmd|git pull -u}}&lt;br /&gt;
{{Cmd|git submodule update}}&lt;br /&gt;
&lt;br /&gt;
== Running the server ==&lt;br /&gt;
&lt;br /&gt;
If you want to get things running quickly and without hassle, just&lt;br /&gt;
run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./lazyserver.sh}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This will start up a python server where you can begin playing with&lt;br /&gt;
mediagoblin, listening on 127.0.0.1:6543.  It will also run celery in &amp;quot;always eager&amp;quot; mode so you&lt;br /&gt;
don&#039;t have to start a separate process for it.&lt;br /&gt;
&lt;br /&gt;
By default, the instance is not sending out confirmation mails. Instead they are redirected to the standard output (the console) of lazyserver.sh.&lt;br /&gt;
&lt;br /&gt;
You can change this behavior setting &amp;lt;code&amp;gt;email_debug_mode&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; in mediagoblin.ini&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is fine in development, but if you want to actually run celery&lt;br /&gt;
separately for testing (or deployment purposes), you&#039;ll want to run&lt;br /&gt;
the server independently:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./bin/paster serve paste.ini --reload}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running celeryd ==&lt;br /&gt;
&lt;br /&gt;
If you aren&#039;t using &amp;lt;tt&amp;gt;./lazyserver.sh&amp;lt;/tt&amp;gt; or otherwise aren&#039;t running celery&lt;br /&gt;
in always eager mode, you&#039;ll need to do this if you want your media to&lt;br /&gt;
process and actually show up.  It&#039;s probably a good idea in&lt;br /&gt;
development to have the web server (above) running in one terminal and&lt;br /&gt;
celeryd in another window.&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|&amp;lt;nowiki&amp;gt;CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery ./bin/celeryd&amp;lt;/nowiki&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running the test suite ==&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./runtests.sh}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running a shell ==&lt;br /&gt;
&lt;br /&gt;
If you want a shell with your database pre-setup and an instantiated&lt;br /&gt;
application ready and at your fingertips....&lt;br /&gt;
&lt;br /&gt;
Run:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|./bin/gmg shell}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
== Wiping your user data ==&lt;br /&gt;
&lt;br /&gt;
You can completely wipe all data from the instance by doing:&lt;br /&gt;
&lt;br /&gt;
{{Cmd|rm -rf mediagoblin.db kombu.db celery.db user_dev; ./bin/gmg dbupdate}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Unless you&#039;re doing development and working on and testing creating&lt;br /&gt;
a new instance, you will probably never have to do this.&lt;br /&gt;
&lt;br /&gt;
== Quickstart for Django programmers ==&lt;br /&gt;
&lt;br /&gt;
We&#039;re not using Django, but the codebase is very Django-like in its&lt;br /&gt;
structure.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;routing.py&amp;lt;/tt&amp;gt; is like &amp;lt;tt&amp;gt;urls.py&amp;lt;/tt&amp;gt; in Django&lt;br /&gt;
* &amp;lt;tt&amp;gt;models.py&amp;lt;/tt&amp;gt; has SQLAlchemy ORM definitions&lt;br /&gt;
* &amp;lt;tt&amp;gt;views.py&amp;lt;/tt&amp;gt; is where the views go&lt;br /&gt;
&lt;br /&gt;
We&#039;re using SQLAlchemy, which is semi-similar to the Django ORM, but&lt;br /&gt;
not really because you can get a lot more fine-grained.  The&lt;br /&gt;
[http://docs.sqlalchemy.org/en/latest/orm/tutorial.html SQLAlchemy ORM tutorial] is a great place to start.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;YouCanHelp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If there are other things that you think would help orient someone&lt;br /&gt;
new to GNU MediaGoblin but coming from Django, let us know!&lt;br /&gt;
&lt;br /&gt;
== Showing off your work with PageKite ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;re doing development with MediaGoblin, it&#039;s sometimes helpful to show off your work to gather feedback from other contributors.  A number of the MediaGoblin developers use something called [http://pagekite.net PageKite], which is a fellow free software web service which makes temporarily showing off work on your machine easy.  There&#039;s a [http://pagekite.net/wiki/Howto/UsePageKiteWithMediaGoblin/ tutorial on how to use PageKite and MediaGoblin together] available on the PageKite wiki.&lt;br /&gt;
&lt;br /&gt;
If you are doing a lot of MediaGoblin development, the PageKite people have graciously offered us a good amount of bandwidth at no cost in an effort to help out fellow free software projects.  If you&#039;ve been making significant contributions, PM Chris Webber on freenode (who is paroneayea there) and ask if you can be added to our group plan.&lt;br /&gt;
&lt;br /&gt;
== Bite-sized bugs to start with ==&lt;br /&gt;
&lt;br /&gt;
Now you should visit our latest list of [http://issues.mediagoblin.org/query?status=!closed&amp;amp;keywords=~bitesized bite-sized issues] because squishing bugs is messy fun. If you&#039;re interested in other things to work on, or need help getting started on a bug, let us know on [http://mediagoblin.org/join/ the mailing list] or on the [http://mediagoblin.org/join/ IRC channel].&lt;/div&gt;</summary>
		<author><name>Rodney757</name></author>
	</entry>
</feed>