aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/source/siteadmin/relnotes.rst11
m---------extlib/sandyseventiesspeedboat0
-rw-r--r--mediagoblin/_version.py2
-rw-r--r--mediagoblin/app.py4
-rw-r--r--mediagoblin/config_spec.ini4
-rw-r--r--mediagoblin/db/models.py16
-rw-r--r--mediagoblin/federation/routing.py8
-rw-r--r--mediagoblin/federation/views.py158
-rw-r--r--mediagoblin/gmg_commands/users.py2
-rw-r--r--mediagoblin/media_types/raw_image/processing.py6
-rw-r--r--mediagoblin/media_types/video/processing.py2
-rw-r--r--mediagoblin/templates/mediagoblin/federation/host-meta.xml22
-rw-r--r--mediagoblin/tools/response.py7
-rw-r--r--setup.py1
14 files changed, 193 insertions, 50 deletions
diff --git a/docs/source/siteadmin/relnotes.rst b/docs/source/siteadmin/relnotes.rst
index 6892e71e..ff701b1f 100644
--- a/docs/source/siteadmin/relnotes.rst
+++ b/docs/source/siteadmin/relnotes.rst
@@ -27,10 +27,17 @@ carefully, or at least skim over it.
**Do this to upgrade**
1. Update to the latest release. If checked out from git, run:
- ``git fetch && git checkout -q v0.7.0 && git submodule update``
+ ``git fetch && git checkout -q v0.7.0 && git submodule init && git submodule update``
2. Make sure to run
``./bin/python setup.py develop --upgrade && ./bin/gmg dbupdate``
+(NOTE: earlier versions of the 0.7.0 release instructions left out the
+``git submodule init`` step! If you did an upgrade earlier based on
+these instructions and your theme looks weirdly aligned, try running
+the following:)
+
+ ``git submodule init && git submodule update``
+
That's it, probably! If you run into problems, don't hesitate to
`contact us <http://mediagoblin.org/pages/join.html>`_
(IRC is often best).
@@ -87,7 +94,7 @@ That's it, probably! If you run into problems, don't hesitate to
but existant!) RTL language support!
**Known issues:**
- - Webfinger is now json by default; in the spec it should be xml by
+ - The host-meta is now json by default; in the spec it should be xml by
default. We have done this because of compatibility with the pump
API. We are checking with upstream to see if there is a way to
resolve this discrepancy.
diff --git a/extlib/sandyseventiesspeedboat b/extlib/sandyseventiesspeedboat
-Subproject 994294e59a5248e29af4418903ce4fb40bd67be
+Subproject 8873d9b559a4c5b3bb90997227d5455f8730fd4
diff --git a/mediagoblin/_version.py b/mediagoblin/_version.py
index a0cf5ed3..ed7dd40c 100644
--- a/mediagoblin/_version.py
+++ b/mediagoblin/_version.py
@@ -23,4 +23,4 @@
# see http://www.python.org/dev/peps/pep-0386/
-__version__ = "0.7.0"
+__version__ = "0.7.1.dev"
diff --git a/mediagoblin/app.py b/mediagoblin/app.py
index 6923e198..8027ad87 100644
--- a/mediagoblin/app.py
+++ b/mediagoblin/app.py
@@ -93,7 +93,9 @@ class MediaGoblinApp(object):
self.db = setup_database(app_config['run_migrations'])
# Quit app if need to run dbupdate
- check_db_up_to_date()
+ ## NOTE: This is currently commented out due to session errors..
+ ## We'd like to re-enable!
+ # check_db_up_to_date()
# Register themes
self.theme_registry, self.current_theme = register_themes(app_config)
diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini
index b5c957c8..f3f3f7ab 100644
--- a/mediagoblin/config_spec.ini
+++ b/mediagoblin/config_spec.ini
@@ -110,7 +110,9 @@ user_privilege_scheme = string(default="uploader,commenter,reporter")
# Frequency garbage collection will run (setting to 0 or false to disable)
# Setting units are minutes.
-garbage_collection = integer(default=60)
+## NOTE: This is temporarily disabled, but we want to set it back:
+## garbage_collection = integer(default=60)
+garbage_collection = integer(default=0)
[jinja2]
# Jinja2 supports more directives than the minimum required by mediagoblin.
diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py
index b910e522..2ff30d22 100644
--- a/mediagoblin/db/models.py
+++ b/mediagoblin/db/models.py
@@ -20,7 +20,6 @@ TODO: indexes on foreignkeys, where useful.
import logging
import datetime
-import base64
from sqlalchemy import Column, Integer, Unicode, UnicodeText, DateTime, \
Boolean, ForeignKey, UniqueConstraint, PrimaryKeyConstraint, \
@@ -727,6 +726,14 @@ class Collection(Base, CollectionMixin):
return CollectionItem.query.filter_by(
collection=self.id).order_by(order_col)
+ def __repr__(self):
+ safe_title = self.title.encode('ascii', 'replace')
+ return '<{classname} #{id}: {title} by {creator}>'.format(
+ id=self.id,
+ classname=self.__class__.__name__,
+ creator=self.creator,
+ title=safe_title)
+
class CollectionItem(Base, CollectionItemMixin):
__tablename__ = "core__collection_items"
@@ -756,6 +763,13 @@ class CollectionItem(Base, CollectionItemMixin):
"""A dict like view on this object"""
return DictReadAttrProxy(self)
+ def __repr__(self):
+ return '<{classname} #{id}: Entry {entry} in {collection}>'.format(
+ id=self.id,
+ classname=self.__class__.__name__,
+ collection=self.collection,
+ entry=self.media_entry)
+
class ProcessingMetaData(Base):
__tablename__ = 'core__processing_metadata'
diff --git a/mediagoblin/federation/routing.py b/mediagoblin/federation/routing.py
index c1c5a264..e9fa6252 100644
--- a/mediagoblin/federation/routing.py
+++ b/mediagoblin/federation/routing.py
@@ -73,7 +73,13 @@ add_route(
)
add_route(
+ "mediagoblin.webfinger.well-known.webfinger",
+ "/.well-known/webfinger",
+ "mediagoblin.federation.views:lrdd_lookup"
+)
+
+add_route(
"mediagoblin.webfinger.whoami",
"/api/whoami",
"mediagoblin.federation.views:whoami"
-)
+) \ No newline at end of file
diff --git a/mediagoblin/federation/views.py b/mediagoblin/federation/views.py
index 3d6953a7..724d349c 100644
--- a/mediagoblin/federation/views.py
+++ b/mediagoblin/federation/views.py
@@ -23,7 +23,8 @@ from werkzeug.datastructures import FileStorage
from mediagoblin.decorators import oauth_required
from mediagoblin.federation.decorators import user_has_privilege
from mediagoblin.db.models import User, MediaEntry, MediaComment
-from mediagoblin.tools.response import redirect, json_response, json_error
+from mediagoblin.tools.response import redirect, json_response, json_error, \
+ render_to_response
from mediagoblin.meddleware.csrf import csrf_exempt
from mediagoblin.submit.lib import new_upload_entry, api_upload_request, \
api_add_to_feed
@@ -70,14 +71,14 @@ def profile_endpoint(request):
def user_endpoint(request):
""" This is /api/user/<username> - This will get the user """
user, user_profile = get_profile(request)
-
+
if user is None:
username = request.matchdict["username"]
return json_error(
"No such 'user' with username '{0}'".format(username),
status=404
)
-
+
return json_response({
"nickname": user.username,
"updated": user.created.isoformat(),
@@ -418,42 +419,129 @@ def object_comments(request):
return json_response(comments)
##
-# Well known
+# RFC6415 - Web Host Metadata
##
def host_meta(request):
- """ /.well-known/host-meta - provide URLs to resources """
- links = []
+ """
+ This provides the host-meta URL information that is outlined
+ in RFC6415. By default this should provide XRD+XML however
+ if the client accepts JSON we will provide that over XRD+XML.
+ The 'Accept' header is used to decude this.
- links.append({
- "ref": "registration_endpoint",
- "href": request.urlgen(
- "mediagoblin.oauth.client_register",
- qualified=True
- ),
- })
- links.append({
- "ref": "http://apinamespace.org/oauth/request_token",
- "href": request.urlgen(
- "mediagoblin.oauth.request_token",
- qualified=True
- ),
- })
- links.append({
- "ref": "http://apinamespace.org/oauth/authorize",
- "href": request.urlgen(
- "mediagoblin.oauth.authorize",
- qualified=True
- ),
- })
- links.append({
- "ref": "http://apinamespace.org/oauth/access_token",
- "href": request.urlgen(
- "mediagoblin.oauth.access_token",
- qualified=True
- ),
- })
+ A client should use this endpoint to determine what URLs to
+ use for OAuth endpoints.
+ """
+
+ links = [
+ {
+ "rel": "lrdd",
+ "type": "application/json",
+ "href": request.urlgen(
+ "mediagoblin.webfinger.well-known.webfinger",
+ qualified=True
+ )
+ },
+ {
+ "rel": "registration_endpoint",
+ "href": request.urlgen(
+ "mediagoblin.oauth.client_register",
+ qualified=True
+ ),
+ },
+ {
+ "rel": "http://apinamespace.org/oauth/request_token",
+ "href": request.urlgen(
+ "mediagoblin.oauth.request_token",
+ qualified=True
+ ),
+ },
+ {
+ "rel": "http://apinamespace.org/oauth/authorize",
+ "href": request.urlgen(
+ "mediagoblin.oauth.authorize",
+ qualified=True
+ ),
+ },
+ {
+ "rel": "http://apinamespace.org/oauth/access_token",
+ "href": request.urlgen(
+ "mediagoblin.oauth.access_token",
+ qualified=True
+ ),
+ },
+ {
+ "rel": "http://apinamespace.org/activitypub/whoami",
+ "href": request.urlgen(
+ "mediagoblin.webfinger.whoami",
+ qualified=True
+ ),
+ },
+ ]
+
+ if "application/json" in request.accept_mimetypes:
+ return json_response({"links": links})
+
+ # provide XML+XRD
+ return render_to_response(
+ request,
+ "mediagoblin/federation/host-meta.xml",
+ {"links": links},
+ mimetype="application/xrd+xml"
+ )
+
+def lrdd_lookup(request):
+ """
+ This is the lrdd endpoint which can lookup a user (or
+ other things such as activities). This is as specified by
+ RFC6415.
+
+ The cleint must provide a 'resource' as a GET parameter which
+ should be the query to be looked up.
+ """
+
+ if "resource" not in request.args:
+ return json_error("No resource parameter", status=400)
+
+ resource = request.args["resource"]
+
+ if "@" in resource:
+ # Lets pull out the username
+ resource = resource[5:] if resource.startswith("acct:") else resource
+ username, host = resource.split("@", 1)
+
+ # Now lookup the user
+ user = User.query.filter_by(username=username).first()
+
+ if user is None:
+ return json_error(
+ "Can't find 'user' with username '{0}'".format(username))
+
+ return json_response([
+ {
+ "rel": "http://webfinger.net/rel/profile-page",
+ "href": user.url_for_self(request.urlgen),
+ "type": "text/html"
+ },
+ {
+ "rel": "self",
+ "href": request.urlgen(
+ "mediagoblin.federation.user",
+ username=user.username,
+ qualified=True
+ )
+ },
+ {
+ "rel": "activity-outbox",
+ "href": request.urlgen(
+ "mediagoblin.federation.feed",
+ username=user.username,
+ qualified=True
+ )
+ }
+ ])
+ else:
+ return json_error("Unrecognized resource parameter", status=404)
- return json_response({"links": links})
def whoami(request):
""" /api/whoami - HTTP redirect to API profile """
diff --git a/mediagoblin/gmg_commands/users.py b/mediagoblin/gmg_commands/users.py
index 71149497..d34f50e2 100644
--- a/mediagoblin/gmg_commands/users.py
+++ b/mediagoblin/gmg_commands/users.py
@@ -129,7 +129,7 @@ def deleteuser(args):
db = mg_globals.database
user = db.User.query.filter_by(
- username=unicode(args.username.lower())).one()
+ username=unicode(args.username.lower())).first()
if user:
user.delete()
print 'The user %s has been deleted' % args.username
diff --git a/mediagoblin/media_types/raw_image/processing.py b/mediagoblin/media_types/raw_image/processing.py
index 83b01559..5ff54cf3 100644
--- a/mediagoblin/media_types/raw_image/processing.py
+++ b/mediagoblin/media_types/raw_image/processing.py
@@ -29,7 +29,7 @@ from mediagoblin.processing import (
_log = logging.getLogger(__name__)
MEDIA_TYPE = 'mediagoblin.media_types.raw_image'
-ACCEPTED_EXTENSIONS = ['nef',]
+ACCEPTED_EXTENSIONS = ['nef', 'cr2']
# The entire function have to be copied
@@ -67,8 +67,8 @@ class InitialRawProcessor(InitialProcessor):
# Extract the biggest preview and write it as our working image
md.previews[-1].write_to_file(
self.process_filename.encode('utf-8'))
- self.process_filename += ".jpg"
- _log.debug('Wrote new file from {0} to preview (jpg) {1}'.format(
+ self.process_filename += '.jpg'
+ _log.debug(u'Wrote new file from {0} to preview (jpg) {1}'.format(
self._original_raw, self.process_filename))
# Override the namebuilder with our new jpg-based name
diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py
index c21c74b3..a7716592 100644
--- a/mediagoblin/media_types/video/processing.py
+++ b/mediagoblin/media_types/video/processing.py
@@ -44,7 +44,7 @@ class VideoTranscodingFail(BaseProcessingFail):
general_message = _(u'Video transcoding failed')
-EXCLUDED_EXTS = ["nef"]
+EXCLUDED_EXTS = ["nef", "cr2"]
def sniff_handler(media_file, filename):
name, ext = os.path.splitext(filename)
diff --git a/mediagoblin/templates/mediagoblin/federation/host-meta.xml b/mediagoblin/templates/mediagoblin/federation/host-meta.xml
new file mode 100644
index 00000000..7970a0d2
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/federation/host-meta.xml
@@ -0,0 +1,22 @@
+{# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2014 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/>.
+-#}
+<?xml version='1.0' encoding='UTF-8'?>
+<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
+ {% for link in links %}
+ <Link rel="{{ link.rel }}" href="{{ link.href }}" />
+ {% endfor %}
+</XRD> \ No newline at end of file
diff --git a/mediagoblin/tools/response.py b/mediagoblin/tools/response.py
index 57552963..88270265 100644
--- a/mediagoblin/tools/response.py
+++ b/mediagoblin/tools/response.py
@@ -29,11 +29,12 @@ class Response(wz_Response):
default_mimetype = u'text/html'
-def render_to_response(request, template, context, status=200):
+def render_to_response(request, template, context, status=200, mimetype=None):
"""Much like Django's shortcut.render()"""
return Response(
render_template(request, template, context),
- status=status)
+ status=status,
+ mimetype=mimetype)
def render_error(request, status=500, title=_('Oops!'),
err_msg=_('An error occured')):
@@ -164,7 +165,7 @@ def json_error(error_str, status=400, *args, **kwargs):
code to 400.
"""
return json_response({"error": error_str}, status=status, *args, **kwargs)
-
+
def form_response(data, *args, **kwargs):
"""
Responds using application/x-www-form-urlencoded and returns a werkzeug
diff --git a/setup.py b/setup.py
index e2e84f2b..468ea294 100644
--- a/setup.py
+++ b/setup.py
@@ -115,6 +115,7 @@ try:
url="http://mediagoblin.org/",
download_url="http://mediagoblin.org/download/",
long_description=open(READMEFILE).read(),
+ description='MediaGoblin is a web application for publishing all kinds of media',
classifiers=[
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",