Merge branch 'master' of gitorious.org:mediagoblin/mediagoblin into metadata

Conflicts:
	mediagoblin/gmg_commands/__init__.py
This commit is contained in:
tilly-Q 2014-05-13 15:24:59 -04:00
commit 1d09e8b4f1
16 changed files with 146 additions and 18 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
/build/
/eggs/
/lib/
/lib64
/local/
/include/
/parts/

View File

@ -19,6 +19,7 @@ Thank you!
* Asheesh Laroia
* Bassam Kurdali
* Bernhard Keller
* Berker Peksag
* Boris Bobrov
* Brandon Invergo
* Brett Smith

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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',

View File

@ -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.'

View File

@ -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') }}"/>

View File

@ -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).

View File

@ -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' %}

View File

@ -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)

View File

@ -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)

View File

@ -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)