aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'mediagoblin/plugins')
-rw-r--r--mediagoblin/plugins/api/tools.py3
-rw-r--r--mediagoblin/plugins/api/views.py8
-rw-r--r--mediagoblin/plugins/geolocation/__init__.py35
-rw-r--r--mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html59
-rw-r--r--mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map_js_head.html25
-rw-r--r--mediagoblin/plugins/oauth/README.rst4
-rw-r--r--mediagoblin/plugins/oauth/forms.py7
-rw-r--r--mediagoblin/plugins/oauth/templates/oauth/authorize.html2
-rw-r--r--mediagoblin/plugins/oauth/views.py8
-rw-r--r--mediagoblin/plugins/piwigo/README.rst23
-rw-r--r--mediagoblin/plugins/piwigo/__init__.py37
-rw-r--r--mediagoblin/plugins/piwigo/forms.py28
-rw-r--r--mediagoblin/plugins/piwigo/tools.py107
-rw-r--r--mediagoblin/plugins/piwigo/views.py167
-rw-r--r--mediagoblin/plugins/raven/README.rst17
-rw-r--r--mediagoblin/plugins/raven/__init__.py92
16 files changed, 607 insertions, 15 deletions
diff --git a/mediagoblin/plugins/api/tools.py b/mediagoblin/plugins/api/tools.py
index e5878258..92411f4b 100644
--- a/mediagoblin/plugins/api/tools.py
+++ b/mediagoblin/plugins/api/tools.py
@@ -69,7 +69,8 @@ def json_response(serializable, _disable_cors=False, *args, **kw):
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With'}
- (response.headers.set(key, value) for key, value in cors_headers)
+ for key, value in cors_headers.iteritems():
+ response.headers.set(key, value)
return response
diff --git a/mediagoblin/plugins/api/views.py b/mediagoblin/plugins/api/views.py
index 2055a663..fde76fe4 100644
--- a/mediagoblin/plugins/api/views.py
+++ b/mediagoblin/plugins/api/views.py
@@ -18,7 +18,6 @@ import json
import logging
from os.path import splitext
-from werkzeug.datastructures import FileStorage
from werkzeug.exceptions import BadRequest, Forbidden
from werkzeug.wrappers import Response
@@ -27,7 +26,8 @@ from mediagoblin.meddleware.csrf import csrf_exempt
from mediagoblin.media_types import sniff_media
from mediagoblin.plugins.api.tools import api_auth, get_entry_serializable, \
json_response
-from mediagoblin.submit.lib import prepare_queue_task, run_process_media
+from mediagoblin.submit.lib import check_file_field, prepare_queue_task, \
+ run_process_media
_log = logging.getLogger(__name__)
@@ -45,9 +45,7 @@ def post_entry(request):
_log.debug('Must POST against post_entry')
raise BadRequest()
- if not 'file' in request.files \
- or not isinstance(request.files['file'], FileStorage) \
- or not request.files['file'].stream:
+ if not check_file_field(request, 'file'):
_log.debug('File field not found')
raise BadRequest()
diff --git a/mediagoblin/plugins/geolocation/__init__.py b/mediagoblin/plugins/geolocation/__init__.py
new file mode 100644
index 00000000..5d14590e
--- /dev/null
+++ b/mediagoblin/plugins/geolocation/__init__.py
@@ -0,0 +1,35 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools import pluginapi
+import os
+
+PLUGIN_DIR = os.path.dirname(__file__)
+
+def setup_plugin():
+ config = pluginapi.get_config('mediagoblin.plugins.geolocation')
+
+ # Register the template path.
+ pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates'))
+
+ pluginapi.register_template_hooks(
+ {"image_sideinfo": "mediagoblin/plugins/geolocation/map.html",
+ "image_head": "mediagoblin/plugins/geolocation/map_js_head.html"})
+
+
+hooks = {
+ 'setup': setup_plugin
+ }
diff --git a/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html b/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html
new file mode 100644
index 00000000..70f837ff
--- /dev/null
+++ b/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map.html
@@ -0,0 +1,59 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+
+{% block geolocation_map %}
+ {% if media.media_data.gps_latitude is defined
+ and media.media_data.gps_latitude
+ and media.media_data.gps_longitude is defined
+ and media.media_data.gps_longitude %}
+ <h3>{% trans %}Location{% endtrans %}</h3>
+ <div>
+ {%- set lon = media.media_data.gps_longitude %}
+ {%- set lat = media.media_data.gps_latitude %}
+ {%- set osm_url = "http://openstreetmap.org/?mlat={lat}&mlon={lon}".format(lat=lat, lon=lon) %}
+ <div id="tile-map" style="width: 100%; height: 196px;">
+ <input type="hidden" id="gps-longitude"
+ value="{{ lon }}" />
+ <input type="hidden" id="gps-latitude"
+ value="{{ lat }}" />
+ </div>
+ <script> <!-- pop up full OSM license when clicked -->
+ $(document).ready(function(){
+ $("#osm_license_link").click(function () {
+ $("#osm_attrib").slideToggle("slow");
+ });
+ });
+ </script>
+ <div id="osm_attrib" class="hidden"><ul><li>
+ Data &copy;<a
+ href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>
+ contributors
+ </li><li>Imaging &copy;<a
+ href="http://mapquest.com">MapQuest</a></li><li>Maps powered by
+ <a href="http://leafletjs.com/"> Leaflet</a></li></ul>
+ </div>
+ <p>
+ <small>
+ {% trans -%}
+ View on <a href="{{ osm_url }}">OpenStreetMap</a>
+ {%- endtrans %}
+ </small>
+ </p>
+ </div>
+ {% endif %}
+{% endblock %}
diff --git a/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map_js_head.html b/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map_js_head.html
new file mode 100644
index 00000000..aca0f730
--- /dev/null
+++ b/mediagoblin/plugins/geolocation/templates/mediagoblin/plugins/geolocation/map_js_head.html
@@ -0,0 +1,25 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#}
+
+<link rel="stylesheet"
+ href="{{ request.staticdirect('/extlib/leaflet/leaflet.css') }}" />
+
+<script type="text/javascript"
+ src="{{ request.staticdirect('/extlib/leaflet/leaflet.js') }}"></script>
+<script type="text/javascript"
+ src="{{ request.staticdirect('/js/geolocation-map.js') }}"></script>
diff --git a/mediagoblin/plugins/oauth/README.rst b/mediagoblin/plugins/oauth/README.rst
index 405a67e2..753b180f 100644
--- a/mediagoblin/plugins/oauth/README.rst
+++ b/mediagoblin/plugins/oauth/README.rst
@@ -7,6 +7,10 @@
Development has been entirely focused on Making It Work(TM). Use this
plugin with caution.
+ Additionally, this and the API may break... consider it pre-alpha.
+ There's also a known issue that the OAuth client doesn't do
+ refresh tokens so this might result in issues for users.
+
The OAuth plugin enables third party web applications to authenticate as one or
more GNU MediaGoblin users in a safe way in order retrieve, create and update
content stored on the GNU MediaGoblin instance.
diff --git a/mediagoblin/plugins/oauth/forms.py b/mediagoblin/plugins/oauth/forms.py
index 2a956dad..d0a4e9b8 100644
--- a/mediagoblin/plugins/oauth/forms.py
+++ b/mediagoblin/plugins/oauth/forms.py
@@ -23,10 +23,9 @@ from mediagoblin.tools.translate import fake_ugettext_passthrough as _
class AuthorizationForm(wtforms.Form):
- client_id = wtforms.HiddenField(_(u'Client ID'),
- [wtforms.validators.Required()])
- next = wtforms.HiddenField(_(u'Next URL'),
- [wtforms.validators.Required()])
+ client_id = wtforms.HiddenField(u'',
+ validators=[wtforms.validators.Required()])
+ next = wtforms.HiddenField(u'', validators=[wtforms.validators.Required()])
allow = wtforms.SubmitField(_(u'Allow'))
deny = wtforms.SubmitField(_(u'Deny'))
diff --git a/mediagoblin/plugins/oauth/templates/oauth/authorize.html b/mediagoblin/plugins/oauth/templates/oauth/authorize.html
index 647fa41f..8a00c925 100644
--- a/mediagoblin/plugins/oauth/templates/oauth/authorize.html
+++ b/mediagoblin/plugins/oauth/templates/oauth/authorize.html
@@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#}
{% extends "mediagoblin/base.html" %}
-{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+{% import "mediagoblin/utils/wtforms.html" as wtforms_util %}
{% block mediagoblin_content %}
<form action="{{ request.urlgen('mediagoblin.plugins.oauth.authorize_client') }}"
diff --git a/mediagoblin/plugins/oauth/views.py b/mediagoblin/plugins/oauth/views.py
index c7b2a332..ea45c209 100644
--- a/mediagoblin/plugins/oauth/views.py
+++ b/mediagoblin/plugins/oauth/views.py
@@ -45,11 +45,11 @@ def register_client(request):
if request.method == 'POST' and form.validate():
client = OAuthClient()
- client.name = unicode(request.form['name'])
- client.description = unicode(request.form['description'])
- client.type = unicode(request.form['type'])
+ client.name = unicode(form.name.data)
+ client.description = unicode(form.description.data)
+ client.type = unicode(form.type.data)
client.owner_id = request.user.id
- client.redirect_uri = unicode(request.form['redirect_uri'])
+ client.redirect_uri = unicode(form.redirect_uri.data)
client.generate_identifier()
client.generate_secret()
diff --git a/mediagoblin/plugins/piwigo/README.rst b/mediagoblin/plugins/piwigo/README.rst
new file mode 100644
index 00000000..0c71ffbc
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/README.rst
@@ -0,0 +1,23 @@
+===================
+ piwigo api plugin
+===================
+
+.. danger::
+ This plugin does not work.
+ It might make your instance unstable or even insecure.
+ So do not use it, unless you want to help to develop it.
+
+.. warning::
+ You should not depend on this plugin in any way for now.
+ It might even go away without any notice.
+
+Okay, so if you still want to test this plugin,
+add the following to your mediagoblin_local.ini:
+
+.. code-block:: ini
+
+ [plugins]
+ [[mediagoblin.plugins.piwigo]]
+
+Then try to connect using some piwigo client.
+There should be some logging, that might help.
diff --git a/mediagoblin/plugins/piwigo/__init__.py b/mediagoblin/plugins/piwigo/__init__.py
new file mode 100644
index 00000000..73326e9e
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/__init__.py
@@ -0,0 +1,37 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+
+from mediagoblin.tools import pluginapi
+
+_log = logging.getLogger(__name__)
+
+
+def setup_plugin():
+ _log.info('Setting up piwigo...')
+
+ routes = [
+ ('mediagoblin.plugins.piwigo.wsphp',
+ '/api/piwigo/ws.php',
+ 'mediagoblin.plugins.piwigo.views:ws_php'),
+ ]
+
+ pluginapi.register_routes(routes)
+
+hooks = {
+ 'setup': setup_plugin
+}
diff --git a/mediagoblin/plugins/piwigo/forms.py b/mediagoblin/plugins/piwigo/forms.py
new file mode 100644
index 00000000..5bb12e62
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/forms.py
@@ -0,0 +1,28 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+import wtforms
+
+
+class AddSimpleForm(wtforms.Form):
+ image = wtforms.FileField()
+ name = wtforms.TextField(
+ validators=[wtforms.validators.Length(min=0, max=500)])
+ comment = wtforms.TextField()
+ # tags = wtforms.FieldList(wtforms.TextField())
+ category = wtforms.IntegerField()
+ level = wtforms.IntegerField()
diff --git a/mediagoblin/plugins/piwigo/tools.py b/mediagoblin/plugins/piwigo/tools.py
new file mode 100644
index 00000000..85d77310
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/tools.py
@@ -0,0 +1,107 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+
+import lxml.etree as ET
+from werkzeug.exceptions import MethodNotAllowed
+
+from mediagoblin.tools.response import Response
+
+
+_log = logging.getLogger(__name__)
+
+
+class PwgNamedArray(list):
+ def __init__(self, l, item_name, as_attrib=()):
+ self.item_name = item_name
+ self.as_attrib = as_attrib
+ list.__init__(self, l)
+
+ def fill_element_xml(self, el):
+ for it in self:
+ n = ET.SubElement(el, self.item_name)
+ if isinstance(it, dict):
+ _fill_element_dict(n, it, self.as_attrib)
+ else:
+ _fill_element(n, it)
+
+
+def _fill_element_dict(el, data, as_attr=()):
+ for k, v in data.iteritems():
+ if k in as_attr:
+ if not isinstance(v, basestring):
+ v = str(v)
+ el.set(k, v)
+ else:
+ n = ET.SubElement(el, k)
+ _fill_element(n, v)
+
+
+def _fill_element(el, data):
+ if isinstance(data, bool):
+ if data:
+ el.text = "1"
+ else:
+ el.text = "0"
+ elif isinstance(data, basestring):
+ el.text = data
+ elif isinstance(data, int):
+ el.text = str(data)
+ elif isinstance(data, dict):
+ _fill_element_dict(el, data)
+ elif isinstance(data, PwgNamedArray):
+ data.fill_element_xml(el)
+ else:
+ _log.warn("Can't convert to xml: %r", data)
+
+
+def response_xml(result):
+ r = ET.Element("rsp")
+ r.set("stat", "ok")
+ _fill_element(r, result)
+ return Response(ET.tostring(r, encoding="utf-8", xml_declaration=True),
+ mimetype='text/xml')
+
+
+class CmdTable(object):
+ _cmd_table = {}
+
+ def __init__(self, cmd_name, only_post=False):
+ assert not cmd_name in self._cmd_table
+ self.cmd_name = cmd_name
+ self.only_post = only_post
+
+ def __call__(self, to_be_wrapped):
+ assert not self.cmd_name in self._cmd_table
+ self._cmd_table[self.cmd_name] = (to_be_wrapped, self.only_post)
+ return to_be_wrapped
+
+ @classmethod
+ def find_func(cls, request):
+ if request.method == "GET":
+ cmd_name = request.args.get("method")
+ else:
+ cmd_name = request.form.get("method")
+ entry = cls._cmd_table.get(cmd_name)
+ if not entry:
+ return entry
+ _log.debug("Found method %s", cmd_name)
+ func, only_post = entry
+ if only_post and request.method != "POST":
+ _log.warn("Method %s only allowed for POST", cmd_name)
+ raise MethodNotAllowed()
+ return func
diff --git a/mediagoblin/plugins/piwigo/views.py b/mediagoblin/plugins/piwigo/views.py
new file mode 100644
index 00000000..3dee09cd
--- /dev/null
+++ b/mediagoblin/plugins/piwigo/views.py
@@ -0,0 +1,167 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+import re
+
+from werkzeug.exceptions import MethodNotAllowed, BadRequest
+from werkzeug.wrappers import BaseResponse
+
+from mediagoblin import mg_globals
+from mediagoblin.meddleware.csrf import csrf_exempt
+from mediagoblin.tools.response import render_404
+from .tools import CmdTable, PwgNamedArray, response_xml
+from .forms import AddSimpleForm
+
+
+_log = logging.getLogger(__name__)
+
+
+@CmdTable("pwg.session.login", True)
+def pwg_login(request):
+ username = request.form.get("username")
+ password = request.form.get("password")
+ _log.info("Login for %r/%r...", username, password)
+ return True
+
+
+@CmdTable("pwg.session.logout")
+def pwg_logout(request):
+ _log.info("Logout")
+ return True
+
+
+@CmdTable("pwg.getVersion")
+def pwg_getversion(request):
+ return "2.5.0 (MediaGoblin)"
+
+
+@CmdTable("pwg.session.getStatus")
+def pwg_session_getStatus(request):
+ return {'username': "fake_user"}
+
+
+@CmdTable("pwg.categories.getList")
+def pwg_categories_getList(request):
+ catlist = ({'id': -29711,
+ 'uppercats': "-29711",
+ 'name': "All my images"},)
+ return {
+ 'categories': PwgNamedArray(
+ catlist,
+ 'category',
+ (
+ 'id',
+ 'url',
+ 'nb_images',
+ 'total_nb_images',
+ 'nb_categories',
+ 'date_last',
+ 'max_date_last',
+ )
+ )
+ }
+
+
+@CmdTable("pwg.images.exist")
+def pwg_images_exist(request):
+ return {}
+
+
+@CmdTable("pwg.images.addSimple", True)
+def pwg_images_addSimple(request):
+ form = AddSimpleForm(request.form)
+ if not form.validate():
+ _log.error("addSimple: form failed")
+ raise BadRequest()
+ dump = []
+ for f in form:
+ dump.append("%s=%r" % (f.name, f.data))
+ _log.info("addimple: %r %s %r", request.form, " ".join(dump), request.files)
+
+ return {'image_id': 123456, 'url': ''}
+
+
+md5sum_matcher = re.compile(r"^[0-9a-fA-F]{32}$")
+
+def fetch_md5(request, parm_name, optional_parm=False):
+ val = request.form.get(parm_name)
+ if (val is None) and (not optional_parm):
+ _log.error("Parameter %s missing", parm_name)
+ raise BadRequest("Parameter %s missing" % parm_name)
+ if not md5sum_matcher.match(val):
+ _log.error("Parameter %s=%r has no valid md5 value", parm_name, val)
+ raise BadRequest("Parameter %s is not md5" % parm_name)
+ return val
+
+
+@CmdTable("pwg.images.addChunk", True)
+def pwg_images_addChunk(request):
+ o_sum = fetch_md5(request, 'original_sum')
+ typ = request.form.get('type')
+ pos = request.form.get('position')
+ data = request.form.get('data')
+
+ # Validate params:
+ pos = int(pos)
+ if not typ in ("file", "thumb"):
+ _log.error("type %r not allowed for now", typ)
+ return False
+
+ _log.info("addChunk for %r, type %r, position %d, len: %d",
+ o_sum, typ, pos, len(data))
+ if typ == "thumb":
+ _log.info("addChunk: Ignoring thumb, because we create our own")
+ return True
+
+ return True
+
+
+def possibly_add_cookie(request, response):
+ # TODO: We should only add a *real* cookie, if
+ # authenticated. And if there is no cookie already.
+ if True:
+ response.set_cookie(
+ 'pwg_id',
+ "some_fake_for_now",
+ path=request.environ['SCRIPT_NAME'],
+ domain=mg_globals.app_config.get('csrf_cookie_domain'),
+ secure=(request.scheme.lower() == 'https'),
+ httponly=True)
+
+
+@csrf_exempt
+def ws_php(request):
+ if request.method not in ("GET", "POST"):
+ _log.error("Method %r not supported", request.method)
+ raise MethodNotAllowed()
+
+ func = CmdTable.find_func(request)
+ if not func:
+ _log.warn("wsphp: Unhandled %s %r %r", request.method,
+ request.args, request.form)
+ return render_404(request)
+
+ result = func(request)
+
+ if isinstance(result, BaseResponse):
+ return result
+
+ response = response_xml(result)
+
+ possibly_add_cookie(request, response)
+
+ return response
diff --git a/mediagoblin/plugins/raven/README.rst b/mediagoblin/plugins/raven/README.rst
new file mode 100644
index 00000000..4006060d
--- /dev/null
+++ b/mediagoblin/plugins/raven/README.rst
@@ -0,0 +1,17 @@
+==============
+ raven plugin
+==============
+
+.. _raven-setup:
+
+Warning: this plugin is somewhat experimental.
+
+Set up the raven plugin
+=======================
+
+1. Add the following to your MediaGoblin .ini file in the ``[plugins]`` section::
+
+ [[mediagoblin.plugins.raven]]
+ sentry_dsn = <YOUR SENTRY DSN>
+ # Logging is very high-volume, set to 0 if you want to turn off logging
+ setup_logging = 1
diff --git a/mediagoblin/plugins/raven/__init__.py b/mediagoblin/plugins/raven/__init__.py
new file mode 100644
index 00000000..8cfaed0a
--- /dev/null
+++ b/mediagoblin/plugins/raven/__init__.py
@@ -0,0 +1,92 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import logging
+
+from mediagoblin.tools import pluginapi
+
+_log = logging.getLogger(__name__)
+
+
+def get_client():
+ from raven import Client
+ config = pluginapi.get_config('mediagoblin.plugins.raven')
+
+ sentry_dsn = config.get('sentry_dsn')
+
+ client = None
+
+ if sentry_dsn:
+ _log.info('Setting up raven from plugin config: {0}'.format(
+ sentry_dsn))
+ client = Client(sentry_dsn)
+ elif os.environ.get('SENTRY_DSN'):
+ _log.info('Setting up raven from SENTRY_DSN environment variable: {0}'\
+ .format(os.environ.get('SENTRY_DSN')))
+ client = Client() # Implicitly looks for SENTRY_DSN
+
+ if not client:
+ _log.error('Could not set up client, missing sentry DSN')
+ return None
+
+ return client
+
+
+def setup_celery():
+ from raven.contrib.celery import register_signal
+
+ client = get_client()
+
+ register_signal(client)
+
+
+def setup_logging():
+ config = pluginapi.get_config('mediagoblin.plugins.raven')
+
+ conf_setup_logging = False
+ if config.get('setup_logging'):
+ conf_setup_logging = bool(int(config.get('setup_logging')))
+
+ if not conf_setup_logging:
+ return
+
+ from raven.handlers.logging import SentryHandler
+ from raven.conf import setup_logging
+
+ client = get_client()
+
+ _log.info('Setting up raven logging handler')
+
+ setup_logging(SentryHandler(client))
+
+
+def wrap_wsgi(app):
+ from raven.middleware import Sentry
+
+ client = get_client()
+
+ _log.info('Attaching raven middleware...')
+
+ return Sentry(app, client)
+
+
+hooks = {
+ 'setup': setup_logging,
+ 'wrap_wsgi': wrap_wsgi,
+ 'celery_logging_setup': setup_logging,
+ 'celery_setup': setup_celery,
+ }