From 5058cd51000a5ed3093816b6f786aed7126a15ba Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sun, 17 Mar 2013 17:39:31 -0700 Subject: Fix sphinx warnsing in docs. Add -W to sphinx options to avoid warnings in the future. --- docs/source/plugindocs/raven.rst | 1 - docs/source/siteadmin/relnotes.rst | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'docs/source') diff --git a/docs/source/plugindocs/raven.rst b/docs/source/plugindocs/raven.rst index 71e284d0..ae96f3f8 100644 --- a/docs/source/plugindocs/raven.rst +++ b/docs/source/plugindocs/raven.rst @@ -1,2 +1 @@ -.. _raven-setup: Set up the raven plugin .. include:: ../../../mediagoblin/plugins/raven/README.rst diff --git a/docs/source/siteadmin/relnotes.rst b/docs/source/siteadmin/relnotes.rst index 84ec09b5..f0be8ecb 100644 --- a/docs/source/siteadmin/relnotes.rst +++ b/docs/source/siteadmin/relnotes.rst @@ -28,8 +28,8 @@ carefully, or at least skim over it. 2. OpenStreetMap is now a plugin, so if you want to use it, add the following to your config file:: - [plugins] - [[mediagoblin.plugins.geolocation]] + [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 -- cgit v1.2.3 From fd5c35e54cd3c22788f583dae4ad1a04b13c07f3 Mon Sep 17 00:00:00 2001 From: Jim Campbell Date: Mon, 13 May 2013 01:04:42 -0500 Subject: docs: started refactoring of the deployment docs. several updates to make the configuration steps more explicit. --- docs/source/siteadmin/deploying.rst | 83 +++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 21 deletions(-) (limited to 'docs/source') diff --git a/docs/source/siteadmin/deploying.rst b/docs/source/siteadmin/deploying.rst index f2f71e01..326d2243 100644 --- a/docs/source/siteadmin/deploying.rst +++ b/docs/source/siteadmin/deploying.rst @@ -1,6 +1,6 @@ .. MediaGoblin Documentation - Written in 2011, 2012 by MediaGoblin contributors + Written in 2011, 2012, 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 @@ -77,7 +77,7 @@ Configure PostgreSQL If you don't want/need postgres, skip this section. -These are the packages needed for Debian Wheezy (testing):: +These are the packages needed for Debian Wheezy (stable):: sudo apt-get install postgresql postgresql-client python-psycopg2 @@ -121,25 +121,62 @@ where the first ``mediagoblin`` is the database owner and the second Drop Privileges for MediaGoblin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -As MediaGoblin does not require special permissions or elevated -access, you should run MediaGoblin under an existing non-root user or -preferably create a dedicated user for the purpose of running -MediaGoblin. Consult your distribution's documentation on how to -create "system account" or dedicated service user. Ensure that it is -not possible to log in to your system with as this user. +MediaGoblin does not require special permissions or elevated +access to run. As such, the prefered way to run MediaGoblin is to +create a dedicated, unpriviledged system user for sole the purpose of running +MediaGoblin. Running MediaGoblin processes under an unpriviledged system user +helps to keep it more secure. + +The following command (entered as root or with sudo) will create a +system account with a username of ``mediagoblin``. You may choose a different +username if you wish.:: + + ``# adduser --system mediagoblin`` + +No password will be assigned to this account, and you will not be able +to log in as this user. To switch to this account, enter either:: + + ``sudo su - mediagoblin`` (if you have sudo permissions) + +or + + ``su - mediagoblin`` (if you have to use root permissions) + +You may get a warning similar to this when entering these commands:: + + ``warning: cannot change directory to /home/mediagoblin: No such file or directory`` + +You can disregard this warning. To return to your regular user account after +using the system account, just enter ``exit``. + +.. note:: + + Unless otherwise noted, the remainder of this document assumes that all + operations are performed using this unpriviledged account. + +.. _create-mediagoblin-directory: + +Create a MediaGoblin Directory +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You should create a working directory for MediaGoblin. This document assumes your local git repository will be located at -``/srv/mediagoblin.example.org/mediagoblin/`` for this documentation. -Substitute your prefer ed local deployment path as needed. +``/srv/mediagoblin.example.org/mediagoblin/``. +Substitute your prefered local deployment path as needed. + +Setting up the working directory requires that we first create the directory +with elevated priviledges, and then assign ownership of the directory +to the unpriviledged system account. -This document assumes that all operations are performed as this -user. To drop privileges to this user, run the following command:: +To do this, enter either of the following commands, changing the defaults +to suit your particular requirements:: - su - [mediagoblin] + ``sudo mkdir -p /srv/mediagoblin.example.org && sudo chown -hR mediagoblin:mediagoblin /srv/mediagobin.example.org`` + +or (as the root user) + + ``# mkdir -p /srv/mediagoblin.example.org && chown -hR mediagoblin:mediagoblin /srv/mediagobin.example.org`` -Where, "``[mediagoblin]``" is the username of the system user that will -run MediaGoblin. Install MediaGoblin and Virtualenv ---------------------------------- @@ -151,17 +188,20 @@ Install MediaGoblin and Virtualenv branch of the git repository. Eventually production deployments will want to transition to running from more consistent releases. -Issue the following commands, to create and change the working -directory. Modify these commands to reflect your own environment:: +We will now clone the MediaGoblin source code repository and setup and +configure the necessary services. Modify these commands to +suit your own environment. As a reminder, you should enter these +commands using your unpriviledged system account. - mkdir -p /srv/mediagoblin.example.org/ - cd /srv/mediagoblin.example.org/ +Change to the MediaGoblin directory that you just created:: + + cd /srv/mediagoblin.example.org Clone the MediaGoblin repository:: git clone git://gitorious.org/mediagoblin/mediagoblin.git -And set up the in-package virtualenv:: +Set up the in-package virtualenv:: cd mediagoblin (virtualenv --system-site-packages . || virtualenv .) && ./bin/python setup.py develop @@ -358,4 +398,5 @@ Security Considerations 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. + All previous sessions will be invalidated. + -- cgit v1.2.3 From 6a93bb4ef7d832419b2c607af20384556b5cbeea Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Tue, 9 Jul 2013 12:31:01 -0700 Subject: basic_auth documentation --- docs/source/plugindocs/basic_auth.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/source/plugindocs/basic_auth.rst (limited to 'docs/source') diff --git a/docs/source/plugindocs/basic_auth.rst b/docs/source/plugindocs/basic_auth.rst new file mode 100644 index 00000000..83492ac2 --- /dev/null +++ b/docs/source/plugindocs/basic_auth.rst @@ -0,0 +1,2 @@ +.. include:: ../../../mediagoblin/plugins/basic_auth/README.rst + -- cgit v1.2.3 From 2c4cdd096f77772ae1f07a163e68c033c0fe1b2c Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Tue, 9 Jul 2013 12:34:13 -0700 Subject: added openid docs --- docs/source/plugindocs/openid.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/source/plugindocs/openid.rst (limited to 'docs/source') diff --git a/docs/source/plugindocs/openid.rst b/docs/source/plugindocs/openid.rst new file mode 100644 index 00000000..045bf9d0 --- /dev/null +++ b/docs/source/plugindocs/openid.rst @@ -0,0 +1,2 @@ +.. include:: ../../../mediagoblin/plugins/openid/README.rst + -- cgit v1.2.3 From bd0ece0557d7ac4cbbf77617b125060b8c083892 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Tue, 9 Jul 2013 12:57:57 -0700 Subject: added basic_auth and openid docs to index and link them together --- docs/source/index.rst | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/source') diff --git a/docs/source/index.rst b/docs/source/index.rst index c8a3f040..f6bc5561 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -59,6 +59,8 @@ Part 2: Core plugin documentation plugindocs/oauth plugindocs/trim_whitespace plugindocs/raven + plugindocs/basic_auth + plugindocs/openid Part 3: Plugin Writer's Guide -- cgit v1.2.3 From 26d2cce85ef629a58d80def85fcda8e324d5d182 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Tue, 9 Jul 2013 13:31:32 -0700 Subject: added docs for the persona plugin --- docs/source/index.rst | 1 + docs/source/plugindocs/persona.rst | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 docs/source/plugindocs/persona.rst (limited to 'docs/source') diff --git a/docs/source/index.rst b/docs/source/index.rst index f6bc5561..0e7d0c2b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -61,6 +61,7 @@ Part 2: Core plugin documentation plugindocs/raven plugindocs/basic_auth plugindocs/openid + plugindocs/persona Part 3: Plugin Writer's Guide diff --git a/docs/source/plugindocs/persona.rst b/docs/source/plugindocs/persona.rst new file mode 100644 index 00000000..2524127d --- /dev/null +++ b/docs/source/plugindocs/persona.rst @@ -0,0 +1,2 @@ +.. include:: ../../../mediagoblin/plugins/persona/README.rst + -- cgit v1.2.3 From d194770dd24c70cf1306d1287ec2cf82f07e2107 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Wed, 10 Jul 2013 13:29:58 -0700 Subject: added docs explaining the authentication hooks --- docs/source/index.rst | 1 + docs/source/pluginwriter/authhooks.rst | 86 ++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 docs/source/pluginwriter/authhooks.rst (limited to 'docs/source') diff --git a/docs/source/index.rst b/docs/source/index.rst index 0e7d0c2b..723dfaf8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -77,6 +77,7 @@ This guide covers writing new GNU MediaGoblin plugins. pluginwriter/database pluginwriter/api pluginwriter/tests + pluginwriter/authhooks Part 4: Developer's Zone diff --git a/docs/source/pluginwriter/authhooks.rst b/docs/source/pluginwriter/authhooks.rst new file mode 100644 index 00000000..9721d729 --- /dev/null +++ b/docs/source/pluginwriter/authhooks.rst @@ -0,0 +1,86 @@ +====================== + Authentication Hooks +====================== + +This documents the hooks that are currently available for authentication +plugins. If you need new hooks for your plugin, go ahead a submit a patch. + +What hooks are available? +========================= + +'authentication' +---------------- + +This hook just needs to return ``True`` as this is how +the MediaGoblin app knows that an authentication plugin is enabled. + + +'auth_extra_validation' +----------------------- + +This hook is used to provide any additional validation of the registration +form when using ``mediagoblin.auth.tools.register_user()``. This hook runs +through all enabled auth plugins. + + +'auth_create_user' +------------------ + +This hook is used by ``mediagoblin.auth.tools.register_user()`` so plugins can +store the necessary information when creating a user. This hook runs through +all enabled auth plugins. + +'auth_get_user' +--------------- + +This hook is used by ``mediagoblin.auth.tools.check_login_simple()``. Your +plugin should return a ``User`` object given a username. + +'auth_no_pass_redirect' +----------------------- + +This hook is called in ``mediagoblin.auth.views`` in both the ``login`` and +``register`` views. This hook should return the name of your plugin, so that +if :ref:`basic_auth-chapter` is not enabled, the user will be redirected to the +correct login and registration views for your plugin. + +The code assumes that it can generate a valid url given +``mediagoblin.plugins.{{ your_plugin_here }}.login`` and +``mediagoblin.plugins.{{ your_plugin_here }}.register``. This is only needed if +you will not be using the ``login`` and ``register`` views in +``mediagoblin.auth.views``. + +'auth_get_login_form' +--------------------- + +This hook is called in ``mediagoblin.auth.views.login()``. If you are not using +that view, then you do not need this hook. This hook should take a ``request`` +object and return the ``LoginForm`` for your plugin. + +'auth_get_registration_form' +---------------------------- + +This hook is called in ``mediagoblin.auth.views.register()``. If you are not +using that view, then you do not need this hook. This hook should take a +``request`` object and return the ``RegisterForm`` for your plugin. + +'auth_gen_password_hash' +------------------------ + +This hook should accept a ``raw_pass`` and an ``extra_salt`` and return a +hashed password to be stored in ``User.pw_hash``. + +'auth_check_password' +--------------------- + +This hook should accept a ``raw_pass``, a ``stored_hash``, and an ``extra_salt``. +Your plugin should then check that the ``raw_pass`` hashes to the same thing as +the ``stored_hash`` and return either ``True`` or ``False``. + +'auth_fake_login_attempt' +------------------------- + +This hook is called in ``mediagoblin.auth.tools.check_login_simple``. It is +called if a user is not found and should do something that takes the same amount +of time as your ``check_password`` function. This is to help prevent timining +attacks. -- cgit v1.2.3 From be7f90b3f537190d199989625f75d334dbca7080 Mon Sep 17 00:00:00 2001 From: xray7224 Date: Mon, 1 Jul 2013 19:13:07 +0100 Subject: Adds the docs for client registration --- docs/source/api/client_register.rst | 158 ++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 docs/source/api/client_register.rst (limited to 'docs/source') diff --git a/docs/source/api/client_register.rst b/docs/source/api/client_register.rst new file mode 100644 index 00000000..088eb51d --- /dev/null +++ b/docs/source/api/client_register.rst @@ -0,0 +1,158 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 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 + . + +==================== +Registering a Client +==================== + +To use the GNU MediaGoblin API you need to use the dynamic client registration. This has been adapted from the `OpenID specification `_, this is the only part of OpenID that is being used to serve the purpose to provide the client registration which is used in OAuth. + +The endpoint is ``/api/client/register`` + +The parameters are: + +type + **required** - This must be either *client_associate* (for new registration) or *client_update* + +client_id + **update only** - This should only be used updating client information, this is the client_id given when you register + +client_secret + **update only** - This should only be used updating client information, this is the client_secret given when you register + +contacts + **optional** - This a space seporated list of email addresses to contact of people responsible for the client + +application_type + **required** - This is the type of client you are making, this must be either *web* or *native* + +application_name + **optional** - This is the name of your client + +logo_url + **optional** - This is a URL of the logo image for your client + +redirect_uri + **optional** - This is a space seporated list of pre-registered URLs for use at the Authorization Server + + +Response +-------- + +You will get back a response:: + +client_id + This identifies a client + +client_secret + This is the secret. + +expires_at + This is time that the client credentials expire. If this is 0 the client registration does not expire. + +======= +Example +======= + +Register Client +--------------- + +To register a client for the first time, this is the minimum you must supply:: + + { + "type": "client_associate", + "application_type": "native" + } + +A Response will look like:: + + { + "client_secret": "hJtfhaQzgKerlLVdaeRAgmbcstSOBLRfgOinMxBCHcb", + "expires_at": 0, + "client_id": "vwljdhUMhhNbdKizpjZlxv" + } + + +Updating Client +--------------- + +Using the response we got above we can update the information and add new information we may have opted not to supply:: + + { + "type": "client_update", + "client_id": "vwljdhUMhhNbdKizpjZlxv", + "client_secret": "hJtfhaQzgKerlLVdaeRAgmbcstSOBLRfgOinMxBCHcb", + "application_type": "web", + "application_name": "MyClient!", + "logo_url": "https://myclient.org/images/my_logo.png", + "contacts": "myemail@someprovider.com another_developer@provider.net", + } + +The response will just return back the client_id and client_secret you sent:: + + { + "client_id": "vwljdhUMhhNbdKizpjZlxv", + "client_secret": "hJtfhaQzgKerlLVdaeRAgmbcstSOBLRfgOinMxBCHcb", + "expires_at": 0 + } + + +====== +Errors +====== + +There are a number of errors you could get back, This explains what could cause some of them: + +Could not decode JSON + This is caused when you have an error in your JSON, you may want to use a JSON validator to ensure that your JSON is correct. + +Unknown Content-Type + You should sent a Content-Type header with when you make a request, this should be either application/json or www-form-urlencoded. This is caused when a unknown Content-Type is used. + +No registration type provided + This is when you leave out the ``type``. This should either be client_update or client_associate + +Unknown application_type. + This is when you have provided a ``type`` however this isn't one of the known types. + +client_id is required to update. + When you try and update you need to specify the client_id, this will be what you were given when you initially registered the client. + +client_secret is required to update. + When you try to update you need to specify the client_secrer, this will be what you were given when you initially register the client. + +Unauthorized. + This is when you are trying to update however the client_id and/or client_secret you have submitted are incorrect. + +Only set client_id for update. + This should only be given when you update. + +Only set client_secret for update. + This should only be given when you update. + +Logo URL is not a valid URL + This is when the URL specified did not meet the validation. + +contacts must be a string of space-separated email addresses. + ``contacts`` should be a string (not a list), ensure each email is seporated by a space + +Email is not a valid email + This is when you have submitted an invalid email address + +redirect_uris must be space-separated URLs. + ``redirect_uris`` should be a string (not a list), ensure each URL is seporated by a space + +URI is not a valid URI + This is when your URI is invalid. + + -- cgit v1.2.3 From d41c6a5349db0ac573e8f0d29d239febc705f7c9 Mon Sep 17 00:00:00 2001 From: xray7224 Date: Mon, 8 Jul 2013 20:35:03 +0100 Subject: Adds oauth support up until authorization --- docs/source/api/client_register.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/source') diff --git a/docs/source/api/client_register.rst b/docs/source/api/client_register.rst index 088eb51d..4ad7908e 100644 --- a/docs/source/api/client_register.rst +++ b/docs/source/api/client_register.rst @@ -113,8 +113,8 @@ Errors There are a number of errors you could get back, This explains what could cause some of them: -Could not decode JSON - This is caused when you have an error in your JSON, you may want to use a JSON validator to ensure that your JSON is correct. +Could not decode data + This is caused when you have an error in the encoding of your data. Unknown Content-Type You should sent a Content-Type header with when you make a request, this should be either application/json or www-form-urlencoded. This is caused when a unknown Content-Type is used. -- cgit v1.2.3 From 86ba41688332e3f71779f76c486889a7a099fa91 Mon Sep 17 00:00:00 2001 From: xray7224 Date: Tue, 16 Jul 2013 19:19:49 +0100 Subject: Adds some tests for the OAuth and some docs --- docs/source/api/oauth.rst | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/source/api/oauth.rst (limited to 'docs/source') diff --git a/docs/source/api/oauth.rst b/docs/source/api/oauth.rst new file mode 100644 index 00000000..003ad492 --- /dev/null +++ b/docs/source/api/oauth.rst @@ -0,0 +1,36 @@ +.. MediaGoblin Documentation + + Written in 2011, 2012 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 + . + +============== +Authentication +============== + +GNU MediaGoblin uses OAuth1 to authenticate requests to the API. There are many +libraries out there for OAuth1, you're likely not going to have to do much. There +is a library for the GNU MediaGoblin called `PyPump `_. +We are not using OAuth2 as we want to stay completely compatable with GNU MediaGoblin. + + +We use :doc:`client_register` to get the client ID and secret. + +Endpoints +--------- + +These are the endpoints you need to use for the oauth requests: + +`/oauth/request_token` is for getting the request token. + +`/oauth/authorize` is to send the user to to authorize your application. + +`/oauth/access_token` is for getting the access token to use in requests. + -- cgit v1.2.3 From 99d79749c44f3cb37faf4152762f9847292b7c0a Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 25 Jul 2013 15:15:49 -0500 Subject: Set up in-package virtualenv via make --- docs/source/siteadmin/deploying.rst | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'docs/source') diff --git a/docs/source/siteadmin/deploying.rst b/docs/source/siteadmin/deploying.rst index 50fc05c5..05cf172d 100644 --- a/docs/source/siteadmin/deploying.rst +++ b/docs/source/siteadmin/deploying.rst @@ -163,12 +163,23 @@ Clone the MediaGoblin repository and set up the git submodules:: cd mediagoblin git submodule init && git submodule update -And set up the in-package virtualenv:: +Set up the in-package virtualenv via make: - (virtualenv --system-site-packages . || virtualenv .) && ./bin/python setup.py develop + ./bootstrap.sh && ./configure && make .. note:: + Prefer not to use make, or want to use the "old way" of installing + MediaGoblin (maybe you know how to use virtualenv and python + packaging)? You still can! All that the above make script is doing + is installing an in-package virtualenv and running + + ./bin/python setup.py develop + +.. :: + + (NOTE: Is this still relevant?) + 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 may need to -- cgit v1.2.3 From 9b60486894e437b90592ec5354f76d7c40ffd6b6 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Wed, 31 Jul 2013 15:16:52 -0700 Subject: minor styling updates to docs --- docs/source/siteadmin/deploying.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'docs/source') diff --git a/docs/source/siteadmin/deploying.rst b/docs/source/siteadmin/deploying.rst index a892bbd4..2f68912d 100644 --- a/docs/source/siteadmin/deploying.rst +++ b/docs/source/siteadmin/deploying.rst @@ -131,20 +131,20 @@ The following command (entered as root or with sudo) will create a system account with a username of ``mediagoblin``. You may choose a different username if you wish.:: - ``# adduser --system mediagoblin`` + adduser --system mediagoblin No password will be assigned to this account, and you will not be able to log in as this user. To switch to this account, enter either:: - ``sudo su - mediagoblin`` (if you have sudo permissions) + sudo su - mediagoblin (if you have sudo permissions) -or +or:: - ``su - mediagoblin`` (if you have to use root permissions) + su - mediagoblin (if you have to use root permissions) You may get a warning similar to this when entering these commands:: - ``warning: cannot change directory to /home/mediagoblin: No such file or directory`` + warning: cannot change directory to /home/mediagoblin: No such file or directory You can disregard this warning. To return to your regular user account after using the system account, just enter ``exit``. @@ -171,11 +171,11 @@ to the unpriviledged system account. To do this, enter either of the following commands, changing the defaults to suit your particular requirements:: - ``sudo mkdir -p /srv/mediagoblin.example.org && sudo chown -hR mediagoblin:mediagoblin /srv/mediagobin.example.org`` + sudo mkdir -p /srv/mediagoblin.example.org && sudo chown -hR mediagoblin:mediagoblin /srv/mediagobin.example.org -or (as the root user) +or (as the root user):: - ``# mkdir -p /srv/mediagoblin.example.org && chown -hR mediagoblin:mediagoblin /srv/mediagobin.example.org`` + mkdir -p /srv/mediagoblin.example.org && chown -hR mediagoblin:mediagoblin /srv/mediagobin.example.org Install MediaGoblin and Virtualenv -- cgit v1.2.3