aboutsummaryrefslogtreecommitdiffstats
path: root/docs/source
diff options
context:
space:
mode:
Diffstat (limited to 'docs/source')
-rw-r--r--docs/source/conf.py3
-rw-r--r--docs/source/devel/codebase.rst (renamed from docs/source/siteadmin/codebase.rst)135
-rw-r--r--docs/source/devel/originaldesigndecisions.rst336
-rw-r--r--docs/source/devel/storage.rst125
-rw-r--r--docs/source/index.rst18
-rw-r--r--docs/source/plugindocs/raven.rst2
-rw-r--r--docs/source/plugindocs/trim_whitespace.rst1
-rw-r--r--docs/source/pluginwriter/api.rst127
-rw-r--r--docs/source/pluginwriter/database.rst111
-rw-r--r--docs/source/siteadmin/deploying.rst70
-rw-r--r--docs/source/siteadmin/media-types.rst112
-rw-r--r--docs/source/siteadmin/plugins.rst22
-rw-r--r--docs/source/siteadmin/production-deployments.rst13
-rw-r--r--docs/source/siteadmin/relnotes.rst160
14 files changed, 1155 insertions, 80 deletions
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 4209acc8..0b2bccac 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -26,7 +26,8 @@ sys.path.insert(0, os.path.abspath(os.path.join('..', '..')))
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = []
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']
+intersphinx_mapping = {'python': ('http://docs.python.org/2.7', None)}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['source/_templates']
diff --git a/docs/source/siteadmin/codebase.rst b/docs/source/devel/codebase.rst
index 3ef91290..122a3297 100644
--- a/docs/source/siteadmin/codebase.rst
+++ b/docs/source/devel/codebase.rst
@@ -34,7 +34,81 @@ various recipes for getting things done.
for where we hang out.
For more information on how to get started hacking on GNU MediaGoblin,
-see `the wiki <http://wiki.mediagoblin.org/>`_.
+see `the wiki <http://wiki.mediagoblin.org/>`_, and specifically, go
+through the
+`Hacking HOWTO <http://wiki.mediagoblin.org/HackingHowto>`_
+which explains generally how to get going with running an instance for
+development.
+
+
+What's where
+============
+
+After you've run checked out mediagoblin and followed the virtualenv
+instantiation instructions, you're faced with the following directory
+tree::
+
+ mediagoblin/
+ |- mediagoblin/ # source code
+ | |- db/ # database setup
+ | |- tools/ # various utilities
+ | |- init/ # "initialization" tools (arguably should be in tools/)
+ | |- tests/ # unit tests
+ | |- templates/ # templates for this application
+ | |- media_types/ # code for processing, displaying different media
+ | |- storage/ # different storage backends
+ | |- gmg_commands/ # command line tools (./bin/gmg)
+ | |- themes/ # pre-bundled themes
+ | |
+ | | # ... some submodules here as well for different sections
+ | | # of the application... here's just a few
+ | |- auth/ # authentication (login/registration) code
+ | |- user_dev/ # user pages (under /u/), including media pages
+ | \- submit/ # submitting media for processing
+ |
+ |- docs/ # documentation
+ |- devtools/ # some scripts for developer convenience
+ |
+ |- user_dev/ # local instance sessions, media, etc
+ |
+ | # the below directories are installed into your virtualenv checkout
+ |
+ |- bin/ # scripts
+ |- develop-eggs/
+ |- lib/ # python libraries installed into your virtualenv
+ |- include/
+ |- mediagoblin.egg-info/
+ \- parts/
+
+
+As you can see, all the code for GNU MediaGoblin is in the
+``mediagoblin`` directory.
+
+Here are some interesting files and what they do:
+
+:routing.py: maps url paths to views
+:views.py: views handle http requests
+:forms.py: wtforms stuff for this submodule
+
+You'll notice that there are several sub-directories: tests,
+templates, auth, submit, ...
+
+``tests`` holds the unit test code.
+
+``templates`` holds all the templates for the output.
+
+``auth`` and ``submit`` are modules that enacpsulate authentication
+and media item submission. If you look in these directories, you'll
+see they have their own ``routing.py``, ``view.py``, and forms.py in
+addition to some other code.
+
+You'll also notice that mediagoblin/db/ contains quite a few things,
+including the following:
+
+:models.py: This is where the database is set up
+:mixin.py: Certain functions appended to models from here
+:migrations.py: When creating a new migration (a change to the
+ database structure), we put it here
Software Stack
@@ -45,7 +119,7 @@ Software Stack
* `Python <http://python.org/>`_: the language we're using to write
this
- * `Nose <http://somethingaboutorange.com/mrl/projects/nose/>`_:
+ * `Py.Test <http://pytest.org/>`_:
for unit tests
* `virtualenv <http://www.virtualenv.org/>`_: for setting up an
@@ -65,13 +139,11 @@ Software Stack
`Paste Script <http://pythonpaste.org/script/>`_: we'll use this for
configuring and launching the application
- * `WebOb <http://pythonpaste.org/webob/>`_: nice abstraction layer
+ * `werkzeug <http://werkzeug.pocoo.org/>`_: nice abstraction layer
from HTTP requests, responses and WSGI bits
- * `Routes <http://routes.groovie.org/>`_: for URL routing
-
- * `Beaker <http://beaker.groovie.org/>`_: for handling sessions and
- caching
+ * `itsdangerous <http://pythonhosted.org/itsdangerous/>`_:
+ for handling sessions
* `Jinja2 <http://jinja.pocoo.org/docs/>`_: the templating engine
@@ -109,52 +181,3 @@ Software Stack
* `JQuery <http://jquery.com/>`_: for groovy JavaScript things
-
-What's where
-============
-
-After you've run checked out mediagoblin and followed the virtualenv
-instantiation instructions, you're faced with the following directory
-tree::
-
- mediagoblin/
- |- mediagoblin/ # source code
- | |- tests/
- | |- templates/
- | |- auth/
- | \- submit/
- |- docs/ # documentation
- |- devtools/ # some scripts for developer convenience
- |
- | # the below directories are installed into your virtualenv checkout
- |
- |- bin/ # scripts
- |- develop-eggs/
- |- lib/ # python libraries installed into your virtualenv
- |- include/
- |- mediagoblin.egg-info/
- |- parts/
- |- user_dev/ # sessions, etc
-
-
-As you can see, all the code for GNU MediaGoblin is in the
-``mediagoblin`` directory.
-
-Here are some interesting files and what they do:
-
-:routing.py: maps url paths to views
-:views.py: views handle http requests
-:models.py: holds the sqlalchemy schemas---these are the data structures
- we're working with
-
-You'll notice that there are several sub-directories: tests,
-templates, auth, submit, ...
-
-``tests`` holds the unit test code.
-
-``templates`` holds all the templates for the output.
-
-``auth`` and ``submit`` are modules that enacpsulate authentication
-and media item submission. If you look in these directories, you'll
-see they have their own ``routing.py``, ``view.py``, and
-``models.py`` in addition to some other code.
diff --git a/docs/source/devel/originaldesigndecisions.rst b/docs/source/devel/originaldesigndecisions.rst
new file mode 100644
index 00000000..2843870c
--- /dev/null
+++ b/docs/source/devel/originaldesigndecisions.rst
@@ -0,0 +1,336 @@
+.. _original-design-decisions-chapter:
+
+===========================
+ Original Design Decisions
+===========================
+
+.. contents:: Sections
+ :local:
+
+
+This chapter talks a bit about design decisions.
+
+Note: This is an outdated document. It's more or less the historical
+reasons for a lot of things. That doesn't mean these decisions have
+stayed the same or we haven't changed our minds on some things!
+
+
+Why GNU MediaGoblin?
+====================
+
+Chris and Will on "Why GNU MediaGoblin":
+
+ Chris came up with the name MediaGoblin. The name is pretty fun.
+ It merges the idea that this is a Media hosting project with
+ Goblin which sort of sounds like gobbling. Here's a piece of
+ software that gobbles up your media for all to see.
+
+ `According to Wikipedia <http://en.wikipedia.org/wiki/Goblin>`_, a
+ goblin is:
+
+ a legendary evil or mischievous illiterate creature, described
+ as grotesquely evil or evil-like phantom
+
+ So are we evil? No. Are we mischievous or illiterate? Not
+ really. So what kind of goblin are we thinking about? We're
+ thinking about these goblins:
+
+ .. figure:: ../_static/goblin.png
+ :alt: Cute goblin with a beret.
+
+ *Figure 1: Cute goblin with a beret. llustrated by Chris
+ Webber*
+
+ .. figure:: ../_static/snugglygoblin.png
+ :scale: 50%
+ :alt: Snuggly goblin with a beret.
+
+ *Figure 2: Snuggly goblin. Illustrated by Karen Rustad*
+
+ Those are pretty cute goblins. Those are the kinds of goblins
+ we're thinking about.
+
+ Chris started doing work on the project after thinking about it
+ for a year. Then, after talking with Matt and Rob, it became an
+ official GNU project. Thus we now call it GNU MediaGoblin.
+
+ That's a lot of letters, though, so in the interest of brevity and
+ facilitating easier casual conversation and balancing that with
+ what's important to us, we have the following rules:
+
+ 1. "GNU MediaGoblin" is the name we're going to use in all official
+ capacities: web site, documentation, press releases, ...
+
+ 2. In casual conversation, it's ok to use more casual names.
+
+ 3. If you're writing about the project, we ask that you call it GNU
+ MediaGoblin.
+
+ 4. If you don't like the name, we kindly ask you to take a deep
+ breath, think a happy thought about cute little goblins playing
+ on a playground and taking cute pictures of themselves, and let
+ it go. (Will added this one.)
+
+
+Why Python
+==========
+
+Chris Webber on "Why Python":
+
+ Because I know Python, love Python, am capable of actually making
+ this thing happen in Python (I've worked on a lot of large free
+ software web applications before in Python, including `Miro
+ Community`_, the `Miro Guide`_, a large portion of `Creative
+ Commons`_, and a whole bunch of things while working at `Imaginary
+ Landscape`_). Me starting a project like this makes sense if it's
+ done in Python.
+
+ You might say that PHP is way more deployable, that Rails has way
+ more cool developers riding around on fixie bikes---and all of
+ those things are true. But I know Python, like Python, and think
+ that Python is pretty great. I do think that deployment in Python
+ is not as good as with PHP, but I think the days of shared hosting
+ are (thankfully) coming to an end, and will probably be replaced
+ by cheap virtual machines spun up on the fly for people who want
+ that sort of stuff, and Python will be a huge part of that future,
+ maybe even more than PHP will. The deployment tools are getting
+ better. Maybe we can use something like Silver Lining. Maybe we
+ can just distribute as ``.debs`` or ``.rpms``. We'll figure it
+ out when we get there.
+
+ Regardless, if I'm starting this project, which I am, it's gonna
+ be in Python.
+
+.. _Miro Community: http://mirocommunity.org/
+.. _Miro Guide: http://miroguide.org/
+.. _Creative Commons: http://creativecommons.org/
+.. _Imaginary Landscape: http://www.imagescape.com/
+
+
+Why WSGI Minimalism
+===================
+
+Chris Webber on "Why WSGI Minimalism":
+
+ If you notice in the technology list I list a lot of components
+ that are very "django-like", but not actually `Django`_
+ components. What can I say, I really like a lot of the ideas in
+ Django! Which leads to the question: why not just use Django?
+
+ While I really like Django's ideas and a lot of its components, I
+ also feel that most of the best ideas in Django I want have been
+ implemented as good or even better outside of Django. I could
+ just use Django and replace the templating system with Jinja2, and
+ the form system with wtforms, and the database with MongoDB and
+ MongoKit, but at that point, how much of Django is really left?
+
+ I also am sometimes saddened and irritated by how coupled all of
+ Django's components are. Loosely coupled yes, but still coupled.
+ WSGI has done a good job of providing a base layer for running
+ applications on and if you know how to do it yourself [1]_, it's
+ not hard or many lines of code at all to bind them together
+ without any framework at all (not even say `Pylons`_, `Pyramid`_
+ or `Flask`_ which I think are still great projects, especially for
+ people who want this sort of thing but have no idea how to get
+ started). And even at this already really early stage of writing
+ MediaGoblin, that glue work is mostly done.
+
+ Not to say I don't think Django isn't great for a lot of things.
+ For a lot of stuff, it's still the best, but not for MediaGoblin,
+ I think.
+
+ One thing that Django does super well though is documentation. It
+ still has some faults, but even with those considered I can hardly
+ think of any other project in Python that has as nice of
+ documentation as Django. It may be worth learning some lessons on
+ documentation from Django [2]_, on that note.
+
+ I'd really like to have a good, thorough hacking-howto and
+ deployment-howto, especially in the former making some notes on
+ how to make it easier for Django hackers to get started.
+
+.. _Django: http://www.djangoproject.com/
+.. _Pylons: http://pylonshq.com/
+.. _Pyramid: http://docs.pylonsproject.org/projects/pyramid/dev/
+.. _Flask: http://flask.pocoo.org/
+
+.. [1] http://pythonpaste.org/webob/do-it-yourself.html
+.. [2] http://pycon.blip.tv/file/4881071/
+
+
+Why MongoDB
+===========
+
+(Note: We don't use MongoDB anymore. This is the original rationale,
+however.)
+
+Chris Webber on "Why MongoDB":
+
+ In case you were wondering, I am not a NOSQL fanboy, I do not go
+ around telling people that MongoDB is web scale. Actually my
+ choice for MongoDB isn't scalability, though scaling up really
+ nicely is a pretty good feature and sets us up well in case large
+ volume sites eventually do use MediaGoblin. But there's another
+ side of scalability, and that's scaling down, which is important
+ for federation, maybe even more important than scaling up in an
+ ideal universe where everyone ran servers out of their own
+ housing. As a memory-mapped database, MongoDB is pretty hungry,
+ so actually I spent a lot of time debating whether the inability
+ to scale down as nicely as something like SQL has with sqlite
+ meant that it was out.
+
+ But I decided in the end that I really want MongoDB, not for
+ scalability, but for flexibility. Schema evolution pains in SQL
+ are almost enough reason for me to want MongoDB, but not quite.
+ The real reason is because I want the ability to eventually handle
+ multiple media types through MediaGoblin, and also allow for
+ plugins, without the rigidity of tables making that difficult. In
+ other words, something like::
+
+ {"title": "Me talking until you are bored",
+ "description": "blah blah blah",
+ "media_type": "audio",
+ "media_data": {
+ "length": "2:30",
+ "codec": "OGG Vorbis"},
+ "plugin_data": {
+ "licensing": {
+ "license": "http://creativecommons.org/licenses/by-sa/3.0/"}}}
+
+
+ Being able to just dump media-specific information in a media_data
+ hashtable is pretty great, and even better is having a plugin
+ system where you can just let plugins have their own entire
+ key-value space cleanly inside the document that doesn't interfere
+ with anyone else's stuff. If we were to let plugins to deposit
+ their own information inside the database, either we'd let plugins
+ create their own tables which makes SQL migrations even harder
+ than they already are, or we'd probably end up creating a table
+ with a column for key, a column for value, and a column for type
+ in one huge table called "plugin_data" or something similar. (Yo
+ dawg, I heard you liked plugins, so I put a database in your
+ database so you can query while you query.) Gross.
+
+ I also don't want things to be too loose so that we forget or lose
+ the structure of things, and that's one reason why I want to use
+ MongoKit, because we can cleanly define a much structure as we
+ want and verify that documents match that structure generally
+ without adding too much bloat or overhead (MongoKit is a pretty
+ lightweight wrapper and doesn't inject extra MongoKit-specific
+ stuff into the database, which is nice and nicer than many other
+ ORMs in that way).
+
+
+Why Sphinx for documentation
+============================
+
+Will Kahn-Greene on "Why Sphinx":
+
+ `Sphinx`_ is a fantastic tool for organizing documentation for a
+ Python-based project that makes it pretty easy to write docs that
+ are readable in source form and can be "compiled" into HTML, LaTeX
+ and other formats.
+
+ There are other doc systems out there, but given that GNU
+ MediaGoblin is being written in Python and I've done a ton of
+ documentation using Sphinx, it makes sense to use Sphinx for now.
+
+.. _Sphinx: http://sphinx.pocoo.org/
+
+
+Why AGPLv3 and CC0?
+===================
+
+Chris, Brett, Will, Rob, Matt, et al curated into a story where
+everyone is the hero by Will on "Why AGPLv3 and CC0":
+
+ The `AGPL v3`_ preserves the freedoms guaranteed by the GPL v3 in
+ the context of software as a service. Using this license ensures
+ that users of the service have the ability to examine the source,
+ deploy their own instance, and implement their own version. This
+ is really important to us and a core mission component of this
+ project. Thus we decided that the software parts should be under
+ this license.
+
+ However, the project is made up of more than just software:
+ there's CSS, images, and other output-related things. We wanted
+ the templates/images/css side of the project all permissive and
+ permissive in the same absolutely permissive way. We're waiving
+ our copyrights to non-software things under the CC0 waiver.
+
+ That brings us to the templates where there's some code and some
+ output. The template engine we're using is called Jinja2. It
+ mixes HTML markup with Python code to render the output of the
+ software. We decided the templates are part of the output of the
+ software and not the software itself. We wanted the output of the
+ software to be licensed in a hassle-free way so that when someone
+ deploys their own GNU MediaGoblin instance with their own
+ templates, they don't have to deal with the copyleft aspects of
+ the AGPLv3 and we'd be fine with that because the changes they're
+ making are identity-related. So at first we decided to waive our
+ copyrights to the templates with a CC0 waiver and then add an
+ exception to the AGPLv3 for the software such that the templates
+ can make calls into the software and yet be a separately licensed
+ work. However, Brett brought up the question of whether this
+ allows some unscrupulous person to make changes to the software
+ through the templates in such a way that they're not bound by the
+ AGPLv3: i.e. a loophole. We thought about this loophole and
+ between this and the extra legalese involved in the exception to
+ the AGPLv3, we decided that it's just way simpler if the templates
+ were also licensed under the AGPLv3.
+
+ Then we have the licensing for the documentation. Given that the
+ documentation is tied to the software content-wise, we don't feel
+ like we have to worry about ensuring freedom of the documentation
+ or worry about attribution concerns. Thus we're waiving our
+ copyrights to the documentation under CC0 as well.
+
+ Lastly, we have branding. This covers logos and other things that
+ are distinctive to GNU MediaGoblin that we feel represents this
+ project. Since we don't currently have any branding, this is an
+ open issue, but we're thinking we'll go with a CC BY-SA license.
+
+ By licensing in this way, we make sure that users of the software
+ receive the freedoms that the AGPLv3 ensures regardless of what
+ fate befalls this project.
+
+ So to summarize:
+
+ * software (Python, JavaScript, HTML templates): licensed
+ under AGPLv3
+ * non-software things (CSS, images, video): copyrights waived
+ under CC0 because this is output of the software
+ * documentation: copyrights waived under CC0 because it's not part
+ of the software
+ * branding assets: we're kicking this can down the road, but
+ probably CC BY-SA
+
+ This is all codified in the ``COPYING`` file.
+
+.. _AGPL v3: http://www.gnu.org/licenses/agpl.html
+.. _CC0 v1: http://creativecommons.org/publicdomain/zero/1.0/
+
+
+Why (non-mandatory) copyright assignment?
+=========================================
+
+Chris Webber on "Why copyright assignment?":
+
+ GNU MediaGoblin is a GNU project with non-mandatory but heavily
+ encouraged copyright assignment to the FSF. Most, if not all, of
+ the core contributors to GNU MediaGoblin will have done a
+ copyright assignment, but unlike some other GNU projects, it isn't
+ required here. We think this is the best choice for GNU
+ MediaGoblin: it ensures that the Free Software Foundation may
+ protect the software by enforcing the AGPL if the FSF sees fit,
+ but it also means that we can immediately merge in changes from a
+ new contributor. It also means that some significant non-FSF
+ contributors might also be able to enforce the AGPL if seen fit.
+
+ Again, assignment is not mandatory, but it is heavily encouraged,
+ even incentivized: significant contributors who do a copyright
+ assignment to the FSF are eligible to have a unique goblin drawing
+ produced for them by the project's main founder, Christopher Allan
+ Webber. See `the wiki <http://wiki.mediagoblin.org/>`_ for details.
+
+
diff --git a/docs/source/devel/storage.rst b/docs/source/devel/storage.rst
new file mode 100644
index 00000000..215f9579
--- /dev/null
+++ b/docs/source/devel/storage.rst
@@ -0,0 +1,125 @@
+=========
+ Storage
+=========
+
+The storage systems attached to your app
+----------------------------------------
+
+Dynamic content: queue_store and public_store
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Two instances of the StorageInterface come attached to your app. These
+are:
+
++ **queue_store:** When a user submits a fresh piece of media for
+ their gallery, before the Processing stage, that piece of media sits
+ here in the queue_store. (It's possible that we'll rename this to
+ "private_store" and start storing more non-publicly-stored stuff in
+ the future...). This is a StorageInterface implementation
+ instance. Visitors to your site probably cannot see it... it isn't
+ designed to be seen, anyway.
+
++ **public_store:** After your media goes through processing it gets
+ moved to the public store. This is also a StorageInterface
+ implelementation, and is for stuff that's intended to be seen by
+ site visitors.
+
+The workbench
+~~~~~~~~~~~~~
+
+In addition, there's a "workbench" used during
+processing... it's just for temporary files during
+processing, and also for making local copies of stuff that
+might be on remote storage interfaces while transitionally
+moving/converting from the queue_store to the public store.
+See the workbench module documentation for more.
+
+.. automodule:: mediagoblin.tools.workbench
+ :members:
+ :show-inheritance:
+
+
+Static assets / staticdirect
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+On top of all that, there is some static media that comes bundled with your
+application. This stuff is kept in:
+
+ mediagoblin/static/
+
+These files are for mediagoblin base assets. Things like the CSS files,
+logos, etc. You can mount these at whatever location is appropriate to you
+(see the direct_remote_path option in the config file) so if your users
+are keeping their static assets at http://static.mgoblin.example.org/ but
+their actual site is at http://mgoblin.example.org/, you need to be able
+to get your static files in a where-it's-mounted agnostic way. There's a
+"staticdirector" attached to the request object. It's pretty easy to use;
+just look at this bit taken from the
+mediagoblin/templates/mediagoblin/base.html main template:
+
+ <link rel="stylesheet" type="text/css"
+ href="Template:Request.staticdirect('/css/extlib/text.css')"/>
+
+see? Not too hard. As expected, if you configured direct_remote_path to be
+http://static.mgoblin.example.org/ you'll get back
+http://static.mgoblin.example.org/css/extlib/text.css just as you'd
+probably expect.
+
+StorageInterface and implementations
+------------------------------------
+
+The guts of StorageInterface and friends
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+So, the StorageInterface!
+
+So, the public and queue stores both use StorageInterface implementations
+... but what does that mean? It's not too hard.
+
+Open up:
+
+ mediagoblin/storage.py
+
+In here you'll see a couple of things. First of all, there's the
+StorageInterface class. What you'll see is that this is just a very simple
+python class. A few of the methods actually implement things, but for the
+most part, they don't. What really matters about this class is the
+docstrings. Each expected method is documented as to how it should be
+constructed. Want to make a new StorageInterface? Simply subclass it. Want
+to know how to use the methods of your storage system? Read these docs,
+they span all implementations.
+
+There are a couple of implementations of these classes bundled in
+storage.py as well. The most simple of these is BasicFileStorage, which is
+also the default storage system used. As expected, this stores files
+locally on your machine.
+
+There's also a CloudFileStorage system. This provides a mapping to
+[OpenStack's swift http://swift.openstack.org/] storage system (used by
+RackSpace Cloud files and etc).
+
+Between these two examples you should be able to get a pretty good idea of
+how to write your own storage systems, for storing data across your
+beowulf cluster of radioactive monkey brains, whatever.
+
+Writing code to store stuff
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+So what does coding for StorageInterface implementations actually look
+like? It's pretty simple, really. For one thing, the design is fairly
+inspired by [Django's file storage API
+https://docs.djangoproject.com/en/dev/ref/files/storage/]... with some
+differences.
+
+Basically, you access files on "file paths", which aren't exactly like
+unix file paths, but are close. If you wanted to store a file on a path
+like dir1/dir2/filename.jpg you'd actually write that file path like:
+
+['dir1', 'dir2', 'filename.jpg']
+
+This way we can be *sure* that each component is actually a component of
+the path that's expected... we do some filename cleaning on each component.
+
+Your StorageInterface should pass in and out "file like objects". In other
+words, they should provide .read() and .write() at minimum, and probably
+also .seek() and .close().
diff --git a/docs/source/index.rst b/docs/source/index.rst
index ac8bd110..7f692d57 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -44,7 +44,6 @@ MediaGoblin website. It is written for site administrators.
siteadmin/relnotes
siteadmin/theming
siteadmin/plugins
- siteadmin/codebase
.. _core-plugin-section:
@@ -58,6 +57,8 @@ Part 2: Core plugin documentation
plugindocs/flatpagesfile
plugindocs/sampleplugin
plugindocs/oauth
+ plugindocs/trim_whitespace
+ plugindocs/raven
Part 3: Plugin Writer's Guide
@@ -70,6 +71,21 @@ This guide covers writing new GNU MediaGoblin plugins.
pluginwriter/foreward
pluginwriter/quickstart
+ pluginwriter/database
+ pluginwriter/api
+
+
+Part 4: Developer's Zone
+========================
+
+This chapter contains various information for developers.
+
+.. toctree::
+ :maxdepth: 1
+
+ devel/codebase
+ devel/storage
+ devel/originaldesigndecisions
Indices and tables
diff --git a/docs/source/plugindocs/raven.rst b/docs/source/plugindocs/raven.rst
new file mode 100644
index 00000000..71e284d0
--- /dev/null
+++ b/docs/source/plugindocs/raven.rst
@@ -0,0 +1,2 @@
+.. _raven-setup: Set up the raven plugin
+.. include:: ../../../mediagoblin/plugins/raven/README.rst
diff --git a/docs/source/plugindocs/trim_whitespace.rst b/docs/source/plugindocs/trim_whitespace.rst
new file mode 100644
index 00000000..eb38e0e5
--- /dev/null
+++ b/docs/source/plugindocs/trim_whitespace.rst
@@ -0,0 +1 @@
+.. include:: ../../../mediagoblin/plugins/trim_whitespace/README.rst
diff --git a/docs/source/pluginwriter/api.rst b/docs/source/pluginwriter/api.rst
new file mode 100644
index 00000000..5e0568fd
--- /dev/null
+++ b/docs/source/pluginwriter/api.rst
@@ -0,0 +1,127 @@
+.. MediaGoblin Documentation
+
+ Written in 2013 by MediaGoblin contributors
+
+ To the extent possible under law, the author(s) have dedicated all
+ copyright and related and neighboring rights to this software to
+ the public domain worldwide. This software is distributed without
+ any warranty.
+
+ You should have received a copy of the CC0 Public Domain
+ Dedication along with this software. If not, see
+ <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+
+==========
+Plugin API
+==========
+
+This documents the general plugin API.
+
+Please note, at this point OUR PLUGIN HOOKS MAY AND WILL CHANGE.
+Authors are encouraged to develop plugins and work with the
+MediaGoblin community to keep them up to date, but this API will be a
+moving target for a few releases.
+
+Please check the release notes for updates!
+
+:mod:`pluginapi` Module
+-----------------------
+
+.. automodule:: mediagoblin.tools.pluginapi
+ :members: get_config, register_routes, register_template_path,
+ register_template_hooks, get_hook_templates,
+ hook_handle, hook_runall, hook_transform
+
+Configuration
+-------------
+
+Your plugin may define its own configuration defaults.
+
+Simply add to the directory of your plugin a config_spec.ini file. An
+example might look like::
+
+ [plugin_spec]
+ some_string = string(default="blork")
+ some_int = integer(default=50)
+
+This means that when people enable your plugin in their config you'll
+be able to provide defaults as well as type validation.
+
+
+Context Hooks
+-------------
+
+View specific hooks
++++++++++++++++++++
+
+You can hook up to almost any template called by any specific view
+fairly easily. As long as the view directly or indirectly uses the
+method ``render_to_response`` you can access the context via a hook
+that has a key in the format of the tuple::
+
+ (view_symbolic_name, view_template_path)
+
+Where the "view symbolic name" is the same parameter used in
+``request.urlgen()`` to look up the view. So say we're wanting to add
+something to the context of the user's homepage. We look in
+mediagoblin/user_pages/routing.py and see::
+
+ add_route('mediagoblin.user_pages.user_home',
+ '/u/<string:user>/',
+ 'mediagoblin.user_pages.views:user_home')
+
+Aha! That means that the name is ``mediagoblin.user_pages.user_home``.
+Okay, so then we look at the view at the
+``mediagoblin.user_pages.user_home`` method::
+
+ @uses_pagination
+ def user_home(request, page):
+ # [...] whole bunch of stuff here
+ return render_to_response(
+ request,
+ 'mediagoblin/user_pages/user.html',
+ {'user': user,
+ 'user_gallery_url': user_gallery_url,
+ 'media_entries': media_entries,
+ 'pagination': pagination})
+
+Nice! So the template appears to be
+``mediagoblin/user_pages/user.html``. Cool, that means that the key
+is::
+
+ ("mediagoblin.user_pages.user_home",
+ "mediagoblin/user_pages/user.html")
+
+The context hook uses ``hook_transform()`` so that means that if we're
+hooking into it, our hook will both accept one argument, ``context``,
+and should return that modified object, like so::
+
+ def add_to_user_home_context(context):
+ context['foo'] = 'bar'
+ return context
+
+ hooks = {
+ ("mediagoblin.user_pages.user_home",
+ "mediagoblin/user_pages/user.html"): add_to_user_home_context}
+
+
+Global context hooks
+++++++++++++++++++++
+
+If you need to add something to the context of *every* view, it is not
+hard; there are two hooks hook that also uses hook_transform (like the
+above) but make available what you are providing to *every* view.
+
+Note that there is a slight, but critical, difference between the two.
+
+The most general one is the ``'template_global_context'`` hook. This
+one is run only once, and is read into the global context... all views
+will get access to what are in this dict.
+
+The slightly more expensive but more powerful one is
+``'template_context_prerender'``. This one is not added to the global
+context... it is added to the actual context of each individual
+template render right before it is run! Because of this you also can
+do some powerful and crazy things, such as checking the request object
+or other parts of the context before passing them on.
diff --git a/docs/source/pluginwriter/database.rst b/docs/source/pluginwriter/database.rst
new file mode 100644
index 00000000..58edf3a0
--- /dev/null
+++ b/docs/source/pluginwriter/database.rst
@@ -0,0 +1,111 @@
+.. MediaGoblin Documentation
+
+ Written in 2013 by MediaGoblin contributors
+
+ To the extent possible under law, the author(s) have dedicated all
+ copyright and related and neighboring rights to this software to
+ the public domain worldwide. This software is distributed without
+ any warranty.
+
+ You should have received a copy of the CC0 Public Domain
+ Dedication along with this software. If not, see
+ <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+
+========
+Database
+========
+
+
+Accessing Existing Data
+=======================
+
+If your plugin wants to access existing data, this is quite
+straight forward. Just import the appropiate models and use
+the full power of SQLAlchemy. Take a look at the (upcoming)
+database section in the Developer's Chapter.
+
+
+Creating new Tables
+===================
+
+If your plugin needs some new space to store data, you
+should create a new table. Please do not modify core
+tables. Not doing so might seem inefficient and possibly
+is. It will help keep things sane and easier to upgrade
+versions later.
+
+So if you create a new plugin and need new tables, create a
+file named ``models.py`` in your plugin directory. You
+might take a look at the core's db.models for some ideas.
+Here's a simple one:
+
+.. code-block:: python
+
+ from mediagoblin.db.base import Base
+ from sqlalchemy import Column, Integer, Unicode, ForeignKey
+
+ class MediaSecurity(Base):
+ __tablename__ = "yourplugin__media_security"
+
+ # The primary key *and* reference to the main media_entry
+ media_entry = Column(Integer, ForeignKey('core__media_entries.id'),
+ primary_key=True)
+ get_media_entry = relationship("MediaEntry",
+ backref=backref("security_rating", cascade="all, delete-orphan"))
+
+ rating = Column(Unicode)
+
+ MODELS = [MediaSecurity]
+
+That's it.
+
+Some notes:
+
+* Make sure all your ``__tablename__`` start with your
+ plugin's name so the tables of various plugins can't
+ conflict in the database. (Conflicts in python naming are
+ much easier to fix later).
+* Try to get your database design as good as possible in
+ the first attempt. Changing the database design later,
+ when people already have data using the old design, is
+ possible (see next chapter), but it's not easy.
+
+
+Changing the Database Schema Later
+==================================
+
+If your plugin is in use and instances use it to store some
+data, changing the database design is a tricky thing.
+
+1. Make up your mind how the new schema should look like.
+2. Change ``models.py`` to contain the new schema. Keep a
+ copy of the old version around for your personal
+ reference later.
+3. Now make up your mind (possibly using your old and new
+ ``models.py``) what steps in SQL are needed to convert
+ the old schema to the new one.
+ This is called a "migration".
+4. Create a file ``migrations.py`` that will contain all
+ your migrations and add your new migration.
+
+Take a look at the core's ``db/migrations.py`` for some
+good examples on what you might be able to do. Here's a
+simple one to add one column:
+
+.. code-block:: python
+
+ from mediagoblin.db.migration_tools import RegisterMigration, inspect_table
+ from sqlalchemy import MetaData, Column, Integer
+
+ MIGRATIONS = {}
+
+ @RegisterMigration(1, MIGRATIONS)
+ def add_license_preference(db):
+ metadata = MetaData(bind=db.bind)
+
+ security_table = inspect_table(metadata, 'yourplugin__media_security')
+
+ col = Column('security_level', Integer)
+ col.create(security_table)
+ db.commit()
diff --git a/docs/source/siteadmin/deploying.rst b/docs/source/siteadmin/deploying.rst
index a270c723..9bcc0637 100644
--- a/docs/source/siteadmin/deploying.rst
+++ b/docs/source/siteadmin/deploying.rst
@@ -32,6 +32,11 @@ GNU/Linux distro.
install. If instead you want to join in as a contributor, see our
`Hacking HOWTO <http://wiki.mediagoblin.org/HackingHowto>`_ instead.
+ There are also many ways to install servers... for the sake of
+ simplicity, our instructions below describe installing with nginx.
+ For more recipes, including Apache, see
+ `our wiki <http://wiki.mediagoblin.org/Deployment>`_.
+
Prepare System
--------------
@@ -165,7 +170,7 @@ And set up the in-package virtualenv::
If you have problems here, consider trying to install virtualenv
with the ``--distribute`` or ``--no-site-packages`` options. If
- your system's default Python is in the 3.x series you man need to
+ your system's default Python is in the 3.x series you may need to
run ``virtualenv`` with the ``--python=python2.7`` or
``--python=python2.6`` options.
@@ -173,22 +178,50 @@ The above provides an in-package install of ``virtualenv``. While this
is counter to the conventional ``virtualenv`` configuration, it is
more reliable and considerably easier to configure and illustrate. If
you're familiar with Python packaging you may consider deploying with
-your preferred the method.
+your preferred method.
Assuming you are going to deploy with FastCGI, you should also install
flup::
./bin/easy_install flup
+(Sometimes this breaks because flup's site is flakey. If it does for
+you, try)::
+
+ ./bin/easy_install https://pypi.python.org/pypi/flup/1.0.3.dev-20110405
+
This concludes the initial configuration of the development
environment. In the future, when you update your
codebase, you should also run::
./bin/python setup.py develop --upgrade && ./bin/gmg dbupdate
+Note: If you are running an active site, depending on your server
+configuration, you may need to stop it first or the dbupdate command
+may hang (and it's certainly a good idea to restart it after the
+update)
+
+
Deploy MediaGoblin Services
---------------------------
+Edit site configuration
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A few basic properties must be set before MediaGoblin will work. First
+make a copy of ``mediagoblin.ini`` for editing so the original config
+file isn't lost::
+
+ cp mediagoblin.ini mediagoblin_local.ini
+
+Then:
+ - Set ``email_sender_address`` to the address you wish to be used as
+ the sender for system-generated emails
+ - Edit ``direct_remote_path``, ``base_dir``, and ``base_url`` if
+ your mediagoblin directory is not the root directory of your
+ vhost.
+
+
Configure MediaGoblin to use the PostgreSQL database
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -224,11 +257,11 @@ browser to confirm that the service is operable.
.. _webserver-config:
-Connect the Webserver to MediaGoblin with FastCGI
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-This section describes how to configure MediaGoblin to work via
-FastCGI. Our configuration example will use nginx, however, you may
+FastCGI and nginx
+~~~~~~~~~~~~~~~~~
+
+This configuration example will use nginx, however, you may
use any webserver of your choice as long as it supports the FastCGI
protocol. If you do not already have a web server, consider nginx, as
the configuration files may be more clear than the
@@ -271,6 +304,10 @@ this ``nginx.conf`` file should be modeled on the following::
# Change this to update the upload size limit for your users
client_max_body_size 8m;
+ # prevent attacks (someone uploading a .txt file that the browser
+ # interprets as an HTML file, etc.)
+ add_header X-Content-Type-Options nosniff;
+
server_name mediagoblin.example.org www.mediagoblin.example.org;
access_log /var/log/nginx/mediagoblin.example.access.log;
error_log /var/log/nginx/mediagoblin.example.error.log;
@@ -325,3 +362,24 @@ Visit the site you've set up in your browser by visiting
smaller deployments. However, for larger production deployments
with larger processing requirements, see the
":doc:`production-deployments`" documentation.
+
+
+Apache
+~~~~~~
+
+Instructions and scripts for running MediaGoblin on an Apache server
+can be found on the `MediaGoblin wiki <http://wiki.mediagoblin.org/Deployment>`_.
+
+
+Security Considerations
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. warning::
+
+ The directory ``user_dev/crypto/`` contains some very
+ sensitive files.
+ Especially the ``itsdangeroussecret.bin`` is very important
+ for session security. Make sure not to leak its contents anywhere.
+ If the contents gets leaked nevertheless, delete your file
+ and restart the server, so that it creates a new secret key.
+ All previous sessions will be invalifated then.
diff --git a/docs/source/siteadmin/media-types.rst b/docs/source/siteadmin/media-types.rst
index 5653217f..210094b9 100644
--- a/docs/source/siteadmin/media-types.rst
+++ b/docs/source/siteadmin/media-types.rst
@@ -43,6 +43,15 @@ video media types, then the list would look like this::
media_types = mediagoblin.media_types.image, mediagoblin.media_types.video
+Note that after enabling new media types, you must run dbupdate like so::
+
+ ./bin/gmg dbupdate
+
+If you are running an active site, depending on your server
+configuration, you may need to stop it first (and it's certainly a
+good idea to restart it after the update).
+
+
How does MediaGoblin decide which media type to use for a file?
===============================================================
@@ -62,12 +71,27 @@ Video
To enable video, first install gstreamer and the python-gstreamer
bindings (as well as whatever gstremaer extensions you want,
-good/bad/ugly). On Debianoid systems::
+good/bad/ugly). On Debianoid systems
- sudo apt-get install python-gst0.10 gstreamer0.10-plugins-{base,bad,good,ugly} \
+.. code-block:: bash
+
+ sudo apt-get install python-gst0.10 \
+ gstreamer0.10-plugins-base \
+ gstreamer0.10-plugins-bad \
+ gstreamer0.10-plugins-good \
+ gstreamer0.10-plugins-ugly \
gstreamer0.10-ffmpeg
+Add ``mediagoblin.media_types.video`` to the ``media_types`` list in your
+``mediagoblin_local.ini`` and restart MediaGoblin.
+
+Run
+
+.. code-block:: bash
+
+ ./bin/gmg dbupdate
+
Now you should be able to submit videos, and mediagoblin should
transcode them.
@@ -92,7 +116,9 @@ To install these on Debianoid systems, run::
The ``scikits.audiolab`` package you will install in the next step depends on the
``libsndfile1-dev`` package, so we should install it.
-On Debianoid systems, run::
+On Debianoid systems, run
+
+.. code-block:: bash
sudo apt-get install libsndfile1-dev
@@ -108,8 +134,15 @@ Then install ``scikits.audiolab`` for the spectrograms::
./bin/pip install scikits.audiolab
Add ``mediagoblin.media_types.audio`` to the ``media_types`` list in your
-``mediagoblin_local.ini`` and restart MediaGoblin. You should now be able to
-upload and listen to audio files!
+``mediagoblin_local.ini`` and restart MediaGoblin.
+
+Run
+
+.. code-block:: bash
+
+ ./bin/gmg dbupdate
+
+You should now be able to upload and listen to audio files!
Ascii art
@@ -117,7 +150,9 @@ Ascii art
To enable ascii art support, first install the
`chardet <http://pypi.python.org/pypi/chardet>`_
-library, which is necessary for creating thumbnails of ascii art::
+library, which is necessary for creating thumbnails of ascii art
+
+.. code-block:: bash
./bin/easy_install chardet
@@ -131,4 +166,69 @@ the list would look like this::
media_types = mediagoblin.media_types.image, mediagoblin.media_types.ascii
+Run
+
+.. code-block:: bash
+
+ ./bin/gmg dbupdate
+
Now any .txt file you uploaded will be processed as ascii art!
+
+
+STL / 3d model support
+======================
+
+To enable the "STL" 3d model support plugin, first make sure you have
+a recentish `Blender <http://blender.org>`_ installed and available on
+your execution path. This feature has been tested with Blender 2.63.
+It may work on some earlier versions, but that is not guaranteed (and
+is surely not to work prior to Blender 2.5X).
+
+Add ``mediagoblin.media_types.stl`` to the ``media_types`` list in your
+``mediagoblin_local.ini`` and restart MediaGoblin.
+
+Run
+
+.. code-block:: bash
+
+ ./bin/gmg dbupdate
+
+You should now be able to upload .obj and .stl files and MediaGoblin
+will be able to present them to your wide audience of admirers!
+
+PDF and Document
+================
+
+To enable the "PDF and Document" support plugin, you need pdftocairo, pdfinfo,
+unoconv with headless support. All executables must be on your execution path.
+
+To install this on Fedora:
+
+.. code-block:: bash
+
+ sudo yum install -y poppler-utils unoconv libreoffice-headless
+
+pdf.js relies on git submodules, so be sure you have fetched them:
+
+.. code-block:: bash
+
+ git submodule init
+ git submodule update
+
+This feature has been tested on Fedora with:
+ poppler-utils-0.20.2-9.fc18.x86_64
+ unoconv-0.5-2.fc18.noarch
+ libreoffice-headless-3.6.5.2-8.fc18.x86_64
+
+It may work on some earlier versions, but that is not guaranteed.
+
+Add ``mediagoblin.media_types.pdf`` to the ``media_types`` list in your
+``mediagoblin_local.ini`` and restart MediaGoblin.
+
+Run
+
+.. code-block:: bash
+
+ ./bin/gmg dbupdate
+
+
diff --git a/docs/source/siteadmin/plugins.rst b/docs/source/siteadmin/plugins.rst
index 75562d4b..baca381d 100644
--- a/docs/source/siteadmin/plugins.rst
+++ b/docs/source/siteadmin/plugins.rst
@@ -44,29 +44,33 @@ If the plugin is available on the `Python Package Index
pip install <plugin-name>
For example, if we wanted to install the plugin named
-"mediagoblin-restrictfive", we would do::
+"mediagoblin-licenses" (which allows you to customize the licenses you
+offer for your media), we would do::
- pip install mediagoblin-restrictfive
+ pip install mediagoblin-licenses
.. Note::
If you're using a virtual environment, make sure to activate the
- virtual environment before installing with pip. Otherwise the
- plugin may get installed in a different environment than the one
- MediaGoblin is installed in.
+ virtual environment before installing with pip. Otherwise the plugin
+ may get installed in a different environment than the one MediaGoblin
+ is installed in. Also make sure, you use e.g. pip-2.7 if your default
+ python (and thus pip) is python 3 (e.g. in Ubuntu).
Once you've installed the plugin software, you need to tell
MediaGoblin that this is a plugin you want MediaGoblin to use. To do
that, you edit the ``mediagoblin.ini`` file and add the plugin as a
subsection of the plugin section.
-For example, say the "mediagoblin-restrictfive" plugin had the Python
-package path ``restrictfive``, then you would add ``restrictfive`` to
+For example, say the "mediagoblin-licenses" plugin has the Python
+package path ``mediagoblin_licenses``, then you would add ``mediagoblin_licenses`` to
the ``plugins`` section as a subsection::
[plugins]
- [[restrictfive]]
+ [[mediagoblin_licenses]]
+ license_01=abbrev1, name1, http://url1
+ license_02=abbrev2, name1, http://url2
Configuring plugins
@@ -112,7 +116,7 @@ Removing plugins
To remove a plugin, use ``pip uninstall``. For example::
- pip uninstall mediagoblin-restrictfive
+ pip uninstall mediagoblin-licenses
.. Note::
diff --git a/docs/source/siteadmin/production-deployments.rst b/docs/source/siteadmin/production-deployments.rst
index 356fab7f..1a32d95e 100644
--- a/docs/source/siteadmin/production-deployments.rst
+++ b/docs/source/siteadmin/production-deployments.rst
@@ -52,7 +52,7 @@ as the basis for your script: ::
Separate Celery
---------------
-While the ``./lazyserer.sh`` configuration provides an efficient way to
+While the ``./lazyserver.sh`` configuration provides an efficient way to
start using a MediaGoblin instance, it is not suitable for production
deployments for several reasons:
@@ -77,6 +77,17 @@ Modify your existing MediaGoblin and application init scripts, if
necessary, to prevent them from starting their own ``celeryd``
processes.
+.. _sentry:
+
+Set up sentry to monitor exceptions
+-----------------------------------
+
+We have a plugin for `raven`_ integration, see the ":doc:`/plugindocs/raven`"
+documentation.
+
+.. _`raven`: http://raven.readthedocs.org
+
+
.. _init-script:
Use an Init Script
diff --git a/docs/source/siteadmin/relnotes.rst b/docs/source/siteadmin/relnotes.rst
index 1b70b31c..04863ec6 100644
--- a/docs/source/siteadmin/relnotes.rst
+++ b/docs/source/siteadmin/relnotes.rst
@@ -19,6 +19,166 @@ This chapter has important information for releases in it.
If you're upgrading from a previous release, please read it
carefully, or at least skim over it.
+0.3.3
+=====
+
+**Do this to upgrade**
+
+1. Make sure to run ``bin/gmg dbupdate`` after upgrading.
+2. OpenStreetMap is now a plugin, so if you want to use it, add the
+ following to your config file:
+
+ .. code-block:: ini
+
+ [plugins]
+ [[mediagoblin.plugins.geolocation]]
+
+If you have your own theme, you may need to make some adjustments to
+it as some theme related things may have changed in this release. If
+you run into problems, don't hesitate to
+`contact us <http://mediagoblin.org/pages/join.html>`_
+(IRC is often best).
+
+**New features**
+
+* New dropdown menu for accessing various features.
+
+* Significantly improved URL generation. Now mediagoblin won't give
+ up on making a slug if it looks like there will be a duplicate;
+ it'll try extra hard to generate a meaningful one instead.
+
+ Similarly, linking to an id no longer can possibly conflict with
+ linking to a slug; /u/username/m/id:35/ is the kind of reference we
+ now use to linking to entries with ids. However, old links with
+ entries that linked to ids should work just fine with our migration.
+ The only urls that might break in this release are ones using colons
+ or equal signs.
+
+* New template hooks for plugin authoring.
+
+* As a demonstration of new template hooks for plugin authoring,
+ openstreetmap support now moved to a plugin!
+
+* Method to add media to collections switched from icon of paperclip
+ to button with "add to collection" text.
+
+* Bug where videos often failed to produce a proper thumbnail fixed!
+
+* Copying around files in MediaGoblin now much more efficient, doesn't
+ waste gobs of memory.
+
+* Video transcoding now optional for videos that meet certain
+ criteria. By default, MediaGoblin will not transcode webm videos
+ that are smaller in resolution than the MediaGoblin defaults, and
+ MediaGoblin can also be configured to allow theora files to not be
+ transcoded as well.
+
+* Per-user license preference option; always want your uploads to be
+ BY-SA and tired of changing that field? You can now set your
+ license preference in your user settings.
+
+* Video player now responsive; better for mobile!
+
+* You can now delete your account from the user preferences page if
+ you so wish.
+
+**Other changes**
+
+* Plugin writers: Internal restructuring led to mediagoblin.db.sql* be
+ mediagoblin.db.* starting from 0.3.3
+
+* Dependency list has been reduced not requiring the "webob" package anymore.
+
+* And many small fixes/improvements, too numerous to list!
+
+
+0.3.2
+=====
+
+This will be the last release that is capable of converting from an earlier
+MongoDB-based MediaGoblin instance to the newer SQL-based system.
+
+**Do this to upgrade**
+
+ # directory of your mediagoblin install
+ cd /srv/mediagoblin.example.org
+
+ # copy source for this release
+ git fetch
+ git checkout tags/v0.3.2
+
+ # perform any needed database updates
+ bin/gmg dbupdate
+
+ # restart your servers however you do that, e.g.,
+ sudo service mediagoblin-paster restart
+ sudo service mediagoblin-celeryd restart
+
+
+**New features**
+
+* **3d model support!**
+
+ You can now upload STL and OBJ files and display them in
+ MediaGoblin. Requires a recent-ish Blender; for details see:
+ :ref:`deploying-chapter`
+
+* **trim_whitespace**
+
+ We bundle the optional plugin trim_whitespace which reduces the size
+ of the delivered html output by reducing redundant whitespace.
+
+ See :ref:`core-plugin-section` for plugin documentation
+
+* **A new API!**
+
+ It isn't well documented yet but we do have an API. There is an
+ `android application in progress <https://gitorious.org/mediagoblin/mediagoblin-android>`_
+ which makes use of it, and there are some demo applications between
+ `automgtic <https://github.com/jwandborg/automgtic>`_, an
+ automatic media uploader for your desktop
+ and `OMGMG <https://github.com/jwandborg/omgmg>`_, an example of
+ a web application hooking up to the API.
+
+ This is a plugin, so you have to enable it in your mediagoblin
+ config file by adding a section under [plugins] like::
+
+ [plugins]
+ [[mediagoblin.plugins.api]]
+
+ Note that the API works but is not nailed down... the way it is
+ called may change in future releases.
+
+* **OAuth login support**
+
+ For applications that use OAuth to connect to the API.
+
+ This is a plugin, so you have to enable it in your mediagoblin
+ config file by adding a section under [plugins] like::
+
+ [plugins]
+ [[mediagoblin.plugins.oauth]]
+
+* **Collections**
+
+ We now have user-curated collections support. These are arbitrary
+ galleries that are customizable by users. You can add media to
+ these by clicking on the paperclip icon when logged in and looking
+ at a media entry.
+
+* **OpenStreetMap licensing display improvements**
+
+ More accurate display of OSM licensing, and less disruptive: you
+ click to "expand" the display of said licensing.
+
+ Geolocation is also now on by default.
+
+* **Miscelaneous visual improvements**
+
+ We've made a number of small visual improvements including newer and
+ nicer looking thumbnails and improved checkbox placement.
+
+
0.3.1
=====