diff options
-rw-r--r-- | docs/source/siteadmin/relnotes.rst | 11 | ||||
m--------- | extlib/sandyseventiesspeedboat | 0 | ||||
-rw-r--r-- | mediagoblin/_version.py | 2 | ||||
-rw-r--r-- | mediagoblin/app.py | 4 | ||||
-rw-r--r-- | mediagoblin/config_spec.ini | 4 | ||||
-rw-r--r-- | mediagoblin/db/models.py | 16 | ||||
-rw-r--r-- | mediagoblin/federation/routing.py | 8 | ||||
-rw-r--r-- | mediagoblin/federation/views.py | 158 | ||||
-rw-r--r-- | mediagoblin/gmg_commands/users.py | 2 | ||||
-rw-r--r-- | mediagoblin/media_types/raw_image/processing.py | 6 | ||||
-rw-r--r-- | mediagoblin/media_types/video/processing.py | 2 | ||||
-rw-r--r-- | mediagoblin/templates/mediagoblin/federation/host-meta.xml | 22 | ||||
-rw-r--r-- | mediagoblin/tools/response.py | 7 | ||||
-rw-r--r-- | setup.py | 1 |
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 @@ -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", |