diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | docs/source/siteadmin/commandline-upload.rst | 8 | ||||
-rw-r--r-- | mediagoblin.ini | 1 | ||||
-rw-r--r-- | mediagoblin/auth/__init__.py | 1 | ||||
-rw-r--r-- | mediagoblin/auth/tools.py | 14 | ||||
-rw-r--r-- | mediagoblin/config_spec.ini | 3 | ||||
-rw-r--r-- | mediagoblin/db/mixin.py | 6 | ||||
-rw-r--r-- | mediagoblin/gmg_commands/__init__.py | 6 | ||||
-rw-r--r-- | mediagoblin/gmg_commands/deletemedia.py | 38 | ||||
-rw-r--r-- | mediagoblin/plugins/metadata_display/templates/mediagoblin/plugins/metadata_display/bits/metadata_extra_head.html | 2 | ||||
-rw-r--r-- | mediagoblin/plugins/trim_whitespace/README.rst | 15 | ||||
-rw-r--r-- | mediagoblin/templates/mediagoblin/base.html | 1 | ||||
-rw-r--r-- | mediagoblin/tests/__init__.py | 41 | ||||
-rw-r--r-- | mediagoblin/tests/test_modelmethods.py | 24 | ||||
-rw-r--r-- | mediagoblin/tools/metadata.py | 2 |
16 files changed, 146 insertions, 18 deletions
@@ -7,6 +7,7 @@ /build/ /eggs/ /lib/ +/lib64 /local/ /include/ /parts/ @@ -19,6 +19,7 @@ Thank you! * Asheesh Laroia * Bassam Kurdali * Bernhard Keller +* Berker Peksag * Boris Bobrov * Brandon Invergo * Brett Smith diff --git a/docs/source/siteadmin/commandline-upload.rst b/docs/source/siteadmin/commandline-upload.rst index d67c19dd..742c0cb2 100644 --- a/docs/source/siteadmin/commandline-upload.rst +++ b/docs/source/siteadmin/commandline-upload.rst @@ -63,16 +63,16 @@ The csv file ============ The media:location column ------------------------- -The media:location column is the one column that is absolutely necessary for +The media:location column is the one column that is absolutely necessary for uploading your media. This gives a path to each piece of media you upload. This -can either a path to a local file or a direct link to remote media (with the +can either a path to a local file or a direct link to remote media (with the link in http format). As you can see in the example above the (fake) media was stored remotely on "www.example.net". Other columns ------------- Other columns can be used to provide detailed metadata about each media entry. -Our metadata system accepts any information provided for in the +Our metadata system accepts any information provided for in the `RDFa Core Initial Context`_, and the batchupload script recognizes all of the resources provided within it. @@ -89,4 +89,4 @@ information of uploaded media entries. - **dc:description** sets a description of your media entry. If this is left blank the media entry's description will not be filled in. - **dc:rights** will set a license for your media entry `if` the data provided is a valid URI. If this is left blank 'All Rights Reserved' will be selected. -You can of course, change these values later. +You can of course, change these values later. diff --git a/mediagoblin.ini b/mediagoblin.ini index fe9d5cd2..4f94b6e4 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -35,6 +35,7 @@ allow_reporting = true ## If you want the terms of service displayed, you can uncomment this # show_tos = true +user_privilege_scheme = "uploader,commenter,reporter" [storage:queuestore] base_dir = %(here)s/user_dev/media/queue diff --git a/mediagoblin/auth/__init__.py b/mediagoblin/auth/__init__.py index be5d0eed..f518a09d 100644 --- a/mediagoblin/auth/__init__.py +++ b/mediagoblin/auth/__init__.py @@ -25,7 +25,6 @@ def create_user(register_form): results = hook_runall("auth_create_user", register_form) return results[0] - def extra_validation(register_form): from mediagoblin.auth.tools import basic_extra_validation diff --git a/mediagoblin/auth/tools.py b/mediagoblin/auth/tools.py index 88716e1c..39df85af 100644 --- a/mediagoblin/auth/tools.py +++ b/mediagoblin/auth/tools.py @@ -132,11 +132,7 @@ def register_user(request, register_form): user = auth.create_user(register_form) # give the user the default privileges - default_privileges = [ - Privilege.query.filter(Privilege.privilege_name==u'commenter').first(), - Privilege.query.filter(Privilege.privilege_name==u'uploader').first(), - Privilege.query.filter(Privilege.privilege_name==u'reporter').first()] - user.all_privileges += default_privileges + user.all_privileges += get_default_privileges(user) user.save() # log the user in @@ -151,6 +147,14 @@ def register_user(request, register_form): return None +def get_default_privileges(user): + instance_privilege_scheme = mg_globals.app_config['user_privilege_scheme'] + default_privileges = [Privilege.query.filter( + Privilege.privilege_name==privilege_name).first() + for privilege_name in instance_privilege_scheme.split(',')] + default_privileges = [privilege for privilege in default_privileges if not privilege == None] + + return default_privileges def check_login_simple(username, password): user = auth.get_user(username=username) diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index cc1ac637..ba2b4519 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -89,6 +89,9 @@ upload_limit = integer(default=None) # Max file size (in Mb) max_file_size = integer(default=None) +# Privilege scheme +user_privilege_scheme = string(default="uploader,commenter,reporter") + [jinja2] # Jinja2 supports more directives than the minimum required by mediagoblin. # This setting allows users creating custom templates to specify a list of diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index 25ce6642..048cc07c 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -46,6 +46,12 @@ class UserMixin(object): def bio_html(self): return cleaned_markdown_conversion(self.bio) + def url_for_self(self, urlgen, **kwargs): + """Generate a URL for this User's home page.""" + return urlgen('mediagoblin.user_pages.user_home', + user=self.username, **kwargs) + + class GenerateSlugMixin(object): """ Mixin to add a generate_slug method to objects. diff --git a/mediagoblin/gmg_commands/__init__.py b/mediagoblin/gmg_commands/__init__.py index 55e85116..fd546aac 100644 --- a/mediagoblin/gmg_commands/__init__.py +++ b/mediagoblin/gmg_commands/__init__.py @@ -53,10 +53,14 @@ SUBCOMMAND_MAP = { 'setup': 'mediagoblin.gmg_commands.addmedia:parser_setup', 'func': 'mediagoblin.gmg_commands.addmedia:addmedia', 'help': 'Reprocess media entries'}, + 'deletemedia': { + 'setup': 'mediagoblin.gmg_commands.deletemedia:parser_setup', + 'func': 'mediagoblin.gmg_commands.deletemedia:deletemedia', + 'help': 'Delete media entries'}, 'batchaddmedia': { 'setup': 'mediagoblin.gmg_commands.batchaddmedia:parser_setup', 'func': 'mediagoblin.gmg_commands.batchaddmedia:batchaddmedia', - 'help': 'Add many media entries at once'} + 'help': 'Add many media entries at once'}, # 'theme': { # 'setup': 'mediagoblin.gmg_commands.theme:theme_parser_setup', # 'func': 'mediagoblin.gmg_commands.theme:theme', diff --git a/mediagoblin/gmg_commands/deletemedia.py b/mediagoblin/gmg_commands/deletemedia.py new file mode 100644 index 00000000..d08e76cc --- /dev/null +++ b/mediagoblin/gmg_commands/deletemedia.py @@ -0,0 +1,38 @@ +# 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.gmg_commands import util as commands_util + + +def parser_setup(subparser): + subparser.add_argument('media_ids', + help='Comma separated list of media IDs to will be deleted.') + + +def deletemedia(args): + app = commands_util.setup_app(args) + + media_ids = set(map(int, args.media_ids.split(','))) + found_medias = set() + filter_ids = app.db.MediaEntry.id.in_(media_ids) + medias = app.db.MediaEntry.query.filter(filter_ids).all() + for media in medias: + found_medias.add(media.id) + media.delete() + print 'Media ID %d has been deleted.' % media.id + for media in media_ids - found_medias: + print 'Can\'t find a media with ID %d.' % media + print 'Done.' diff --git a/mediagoblin/plugins/metadata_display/templates/mediagoblin/plugins/metadata_display/bits/metadata_extra_head.html b/mediagoblin/plugins/metadata_display/templates/mediagoblin/plugins/metadata_display/bits/metadata_extra_head.html index 84eedf18..4a380299 100644 --- a/mediagoblin/plugins/metadata_display/templates/mediagoblin/plugins/metadata_display/bits/metadata_extra_head.html +++ b/mediagoblin/plugins/metadata_display/templates/mediagoblin/plugins/metadata_display/bits/metadata_extra_head.html @@ -1,3 +1,3 @@ <link rel="stylesheet" type="text/css" - href="{{ request.staticdirect('css/metadata_display.css', + href="{{ request.staticdirect('css/metadata_display.css', 'metadata_display') }}"/> diff --git a/mediagoblin/plugins/trim_whitespace/README.rst b/mediagoblin/plugins/trim_whitespace/README.rst index b55ce35e..db9a0c53 100644 --- a/mediagoblin/plugins/trim_whitespace/README.rst +++ b/mediagoblin/plugins/trim_whitespace/README.rst @@ -3,17 +3,22 @@ ======================= Mediagoblin templates are written with 80 char limit for better -readability. However that means that the html output is very verbose -containing LOTS of whitespace. This plugin inserts a Middleware that -filters out whitespace from the returned HTML in the Response() objects. +readability. However that means that the HTML output is very verbose +containing *lots* of whitespace. This plugin inserts a middleware that +filters out whitespace from the returned HTML in the ``Response()`` +objects. -Simply enable this plugin by putting it somewhere where python can reach it and put it's path into the [plugins] section of your mediagoblin.ini or mediagoblin_local.ini like for example this: +Simply enable this plugin by putting it somewhere where Python can reach +it and put it's path into the ``[plugins]`` section of your +``mediagoblin.ini`` or ``mediagoblin_local.ini`` like for example this: + +.. code-block:: ini [plugins] [[mediagoblin.plugins.trim_whitespace]] There is no further configuration required. If this plugin is enabled, -all text/html documents should not have lots of whitespace in between +all *text/html* documents should not have lots of whitespace in between elements, although it does a very naive filtering right now (just keep the first whitespace and delete all subsequent ones). diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index b4c7eb8b..28b9c63c 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -165,6 +165,7 @@ <a href="{{ request.urlgen('mediagoblin.moderation.reports') }}"> {%- trans %}Report management panel{% endtrans -%} </a> + {% template_hook("moderation_powers") %} </p> {% endif %} {% include 'mediagoblin/fragments/header_notifications.html' %} diff --git a/mediagoblin/tests/__init__.py b/mediagoblin/tests/__init__.py index cf200791..fbf3fc6c 100644 --- a/mediagoblin/tests/__init__.py +++ b/mediagoblin/tests/__init__.py @@ -14,9 +14,50 @@ # 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 pytest + +from mediagoblin.db.models import User +from mediagoblin.tests.tools import fixture_add_user +from mediagoblin.tools import template + def setup_package(): import warnings from sqlalchemy.exc import SAWarning warnings.simplefilter("error", SAWarning) + + +class MGClientTestCase: + + usernames = None + + @pytest.fixture(autouse=True) + def setup(self, test_app): + self.test_app = test_app + + if self.usernames is None: + msg = ('The usernames attribute should be overridden ' + 'in the subclass') + raise pytest.skip(msg) + for username, options in self.usernames: + fixture_add_user(username, **options) + + def user(self, username): + return User.query.filter(User.username == username).first() + + def _do_request(self, url, *context_keys, **kwargs): + template.clear_test_template_context() + response = self.test_app.request(url, **kwargs) + context_data = template.TEMPLATE_TEST_CONTEXT + for key in context_keys: + context_data = context_data[key] + return response, context_data + + def do_get(self, url, *context_keys, **kwargs): + kwargs['method'] = 'GET' + return self._do_request(url, *context_keys, **kwargs) + + def do_post(self, url, *context_keys, **kwargs): + kwargs['method'] = 'POST' + return self._do_request(url, *context_keys, **kwargs) diff --git a/mediagoblin/tests/test_modelmethods.py b/mediagoblin/tests/test_modelmethods.py index 86513c76..ca436c76 100644 --- a/mediagoblin/tests/test_modelmethods.py +++ b/mediagoblin/tests/test_modelmethods.py @@ -20,9 +20,11 @@ from mediagoblin.db.base import Session from mediagoblin.db.models import MediaEntry, User, Privilege +from mediagoblin.tests import MGClientTestCase from mediagoblin.tests.tools import fixture_add_user import mock +import pytest class FakeUUID(object): @@ -30,6 +32,8 @@ class FakeUUID(object): UUID_MOCK = mock.Mock(return_value=FakeUUID()) +REQUEST_CONTEXT = ['mediagoblin/root.html', 'request'] + class TestMediaEntrySlugs(object): def _setup(self): @@ -204,3 +208,23 @@ def test_media_data_init(test_app): print repr(obj) assert obj_in_session == 0 + +class TestUserUrlForSelf(MGClientTestCase): + + usernames = [(u'lindsay', dict(privileges=[u'active']))] + + def test_url_for_self(self): + _, request = self.do_get('/', *REQUEST_CONTEXT) + + assert self.user(u'lindsay').url_for_self(request.urlgen) == '/u/lindsay/' + + def test_url_for_self_not_callable(self): + _, request = self.do_get('/', *REQUEST_CONTEXT) + + def fake_urlgen(): + pass + + with pytest.raises(TypeError) as excinfo: + self.user(u'lindsay').url_for_self(fake_urlgen()) + assert excinfo.errisinstance(TypeError) + assert 'object is not callable' in str(excinfo) diff --git a/mediagoblin/tools/metadata.py b/mediagoblin/tools/metadata.py index 3f10e9d1..b0cad9da 100644 --- a/mediagoblin/tools/metadata.py +++ b/mediagoblin/tools/metadata.py @@ -131,7 +131,7 @@ def load_context(url): stores internally, load them from disk. """ if url in _CONTEXT_CACHE: - return _CONTEXT_CACHE[url] + return _CONTEXT_CACHE[url] # See if it's one of our basic ones document = BUILTIN_CONTEXTS.get(url, None) |