Merge branch 'master' into test_submission_views_365

This commit is contained in:
Chris Moylan 2011-06-28 23:05:03 -05:00
commit 4ce57ac85d
20 changed files with 515 additions and 78 deletions

View File

@ -40,10 +40,6 @@ def setup_celery_from_config(app_config, global_config,
- set_environ: if set, this will CELERY_CONFIG_MODULE to the - set_environ: if set, this will CELERY_CONFIG_MODULE to the
settings_module settings_module
""" """
if app_config.get('celery_setup_elsewhere') == True:
# Don't setup celery based on our config file.
return
if global_config.has_key('celery'): if global_config.has_key('celery'):
celery_conf = global_config['celery'] celery_conf = global_config['celery']
else: else:

View File

@ -23,7 +23,8 @@ from mediagoblin.celery_setup import setup_celery_from_config
OUR_MODULENAME = __name__ OUR_MODULENAME = __name__
def setup_self(check_environ_for_conf=True, module_name=OUR_MODULENAME): def setup_self(check_environ_for_conf=True, module_name=OUR_MODULENAME,
default_conf_file='mediagoblin.ini'):
""" """
Transform this module into a celery config module by reading the Transform this module into a celery config module by reading the
mediagoblin config file. Set the environment variable mediagoblin config file. Set the environment variable
@ -36,9 +37,9 @@ def setup_self(check_environ_for_conf=True, module_name=OUR_MODULENAME):
""" """
if check_environ_for_conf: if check_environ_for_conf:
mgoblin_conf_file = os.path.abspath( mgoblin_conf_file = os.path.abspath(
os.environ.get('MEDIAGOBLIN_CONFIG', 'mediagoblin.ini')) os.environ.get('MEDIAGOBLIN_CONFIG', default_conf_file))
else: else:
mgoblin_conf_file = 'mediagoblin.ini' mgoblin_conf_file = default_conf_file
if not os.path.exists(mgoblin_conf_file): if not os.path.exists(mgoblin_conf_file):
raise IOError( raise IOError(
@ -48,6 +49,7 @@ def setup_self(check_environ_for_conf=True, module_name=OUR_MODULENAME):
# this is the module that gets set up. # this is the module that gets set up.
os.environ['CELERY_CONFIG_MODULE'] = module_name os.environ['CELERY_CONFIG_MODULE'] = module_name
app.MediaGoblinApp(mgoblin_conf_file, setup_celery=False) app.MediaGoblinApp(mgoblin_conf_file, setup_celery=False)
setup_celery_from_config( setup_celery_from_config(
mg_globals.app_config, mg_globals.global_config, mg_globals.app_config, mg_globals.global_config,
settings_module=module_name, settings_module=module_name,

View File

@ -16,11 +16,15 @@
import os import os
from mediagoblin.tests.tools import TEST_APP_CONFIG
from mediagoblin.celery_setup.from_celery import setup_self from mediagoblin.celery_setup.from_celery import setup_self
OUR_MODULENAME = __name__ OUR_MODULENAME = __name__
CELERY_SETUP = False
if os.environ.get('CELERY_CONFIG_MODULE') == OUR_MODULENAME: if os.environ.get('CELERY_CONFIG_MODULE') == OUR_MODULENAME:
setup_self(check_environ_for_conf=False, module_name=OUR_MODULENAME) setup_self(check_environ_for_conf=False, module_name=OUR_MODULENAME,
default_conf_file=TEST_APP_CONFIG)
CELERY_SETUP = True

118
mediagoblin/db/indexes.py Normal file
View File

@ -0,0 +1,118 @@
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011 Free Software Foundation, Inc
#
# 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/>.
"""
Indexes for the local database.
To add new indexes
------------------
Indexes are recorded in the following format:
ACTIVE_INDEXES = {
'collection_name': {
'identifier': { # key identifier used for possibly deprecating later
'index': [index_foo_goes_here]}}
... and anything else being parameters to the create_index function
(including unique=True, etc)
Current indexes must be registered in ACTIVE_INDEXES... deprecated
indexes should be marked in DEPRECATED_INDEXES.
Remember, ordering of compound indexes MATTERS. Read below for more.
REQUIRED READING:
- http://kylebanker.com/blog/2010/09/21/the-joy-of-mongodb-indexes/
- http://www.mongodb.org/display/DOCS/Indexes
- http://www.mongodb.org/display/DOCS/Indexing+Advice+and+FAQ
To remove deprecated indexes
----------------------------
Removing deprecated indexes is easier, just do:
INACTIVE_INDEXES = {
'collection_name': [
'deprecated_index_identifier1', 'deprecated_index_identifier2']}
... etc.
If an index has been deprecated that identifier should NEVER BE USED
AGAIN. Eg, if you previously had 'awesomepants_unique', you shouldn't
use 'awesomepants_unique' again, you should create a totally new name
or at worst use 'awesomepants_unique2'.
"""
from pymongo import ASCENDING, DESCENDING
################
# Active indexes
################
ACTIVE_INDEXES = {}
# MediaEntry indexes
# ------------------
MEDIAENTRY_INDEXES = {
'uploader_slug_unique': {
# Matching an object to an uploader + slug.
# MediaEntries are unique on these two combined, eg:
# /u/${myuser}/m/${myslugname}/
'index': [('uploader', ASCENDING),
('slug', ASCENDING)],
'unique': True},
'created': {
# A global index for all media entries created, in descending
# order. This is used for the site's frontpage.
'index': [('created', DESCENDING)]},
'uploader_created': {
# Indexing on uploaders and when media entries are created.
# Used for showing a user gallery, etc.
'index': [('uploader', ASCENDING),
('created', DESCENDING)]}}
ACTIVE_INDEXES['media_entries'] = MEDIAENTRY_INDEXES
# User indexes
# ------------
USER_INDEXES = {
'username_unique': {
# Index usernames, and make sure they're unique.
# ... I guess we might need to adjust this once we're federated :)
'index': 'username',
'unique': True},
'created': {
# All most recently created users
'index': 'created'}}
ACTIVE_INDEXES['users'] = USER_INDEXES
####################
# Deprecated indexes
####################
DEPRECATED_INDEXES = {}

View File

@ -108,11 +108,6 @@ class MediaEntry(Document):
migration_handler = migrations.MediaEntryMigration migration_handler = migrations.MediaEntryMigration
indexes = [
# Referene uniqueness of slugs by uploader
{'fields': ['uploader', 'slug'],
'unique': True}]
def main_mediafile(self): def main_mediafile(self):
pass pass

View File

@ -14,8 +14,88 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Utilities for database operations.
Some note on migration and indexing tools:
We store information about what the state of the database is in the
'mediagoblin' document of the 'app_metadata' collection. Keys in that
document relevant to here:
- 'migration_number': The integer representing the current state of
the migrations
"""
import copy
# Imports that other modules might use # Imports that other modules might use
from pymongo import DESCENDING from pymongo import DESCENDING
from pymongo.errors import InvalidId from pymongo.errors import InvalidId
from mongokit import ObjectId from mongokit import ObjectId
from mediagoblin.db.indexes import ACTIVE_INDEXES, DEPRECATED_INDEXES
def add_new_indexes(database, active_indexes=ACTIVE_INDEXES):
"""
Add any new indexes to the database.
Args:
- database: pymongo or mongokit database instance.
- active_indexes: indexes to possibly add in the pattern of:
{'collection_name': {
'identifier': {
'index': [index_foo_goes_here],
'unique': True}}
where 'index' is the index to add and all other options are
arguments for collection.create_index.
Returns:
A list of indexes added in form ('collection', 'index_name')
"""
indexes_added = []
for collection_name, indexes in active_indexes.iteritems():
collection = database[collection_name]
collection_indexes = collection.index_information().keys()
for index_name, index_data in indexes.iteritems():
if not index_name in collection_indexes:
# Get a copy actually so we don't modify the actual
# structure
index_data = copy.copy(index_data)
index = index_data.pop('index')
collection.create_index(
index, name=index_name, **index_data)
indexes_added.append((collection_name, index_name))
return indexes_added
def remove_deprecated_indexes(database, deprecated_indexes=DEPRECATED_INDEXES):
"""
Remove any deprecated indexes from the database.
Args:
- database: pymongo or mongokit database instance.
- deprecated_indexes: the indexes to deprecate in the pattern of:
{'collection': ['index_identifier1', 'index_identifier2']}
Returns:
A list of indexes removed in form ('collection', 'index_name')
"""
indexes_removed = []
for collection_name, index_names in deprecated_indexes.iteritems():
collection = database[collection_name]
collection_indexes = collection.index_information().keys()
for index_name in index_names:
if index_name in collection_indexes:
collection.drop_index(index_name)
indexes_removed.append((collection_name, index_name))
return indexes_removed

View File

@ -16,6 +16,7 @@
from mediagoblin.db import migrations from mediagoblin.db import migrations
from mediagoblin.db import util as db_util
from mediagoblin.gmg_commands import util as commands_util from mediagoblin.gmg_commands import util as commands_util
@ -27,8 +28,17 @@ def migrate_parser_setup(subparser):
def migrate(args): def migrate(args):
mgoblin_app = commands_util.setup_app(args) mgoblin_app = commands_util.setup_app(args)
print "Applying migrations..."
# Clear old indexes
print "== Clearing old indexes... =="
removed_indexes = db_util.remove_deprecated_indexes(mgoblin_app.db)
for collection, index_name in removed_indexes:
print "Removed index '%s' in collection '%s'" % (
index_name, collection)
# Migrate
print "== Applying migrations... =="
for model_name in migrations.MIGRATE_CLASSES: for model_name in migrations.MIGRATE_CLASSES:
model = getattr(mgoblin_app.db, model_name) model = getattr(mgoblin_app.db, model_name)
@ -38,4 +48,10 @@ def migrate(args):
migration = model.migration_handler(model) migration = model.migration_handler(model)
migration.migrate_all(collection=model.collection) migration.migrate_all(collection=model.collection)
print "... done." # Add new indexes
print "== Adding new indexes... =="
new_indexes = db_util.add_new_indexes(mgoblin_app.db)
for collection, index_name in new_indexes:
print "Added index '%s' to collection '%s'" % (
index_name, collection)

34
mediagoblin/messages.py Normal file
View File

@ -0,0 +1,34 @@
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011 Free Software Foundation, Inc
#
# 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/>.
DEBUG = 'debug'
INFO = 'info'
SUCCESS = 'success'
WARNING = 'warning'
ERROR = 'error'
def add_message(request, level, text):
messages = request.session.setdefault('messages', [])
messages.append({'level': level, 'text': text})
request.session.save()
def fetch_messages(request, clear_from_session=True):
messages = request.session.get('messages')
if messages and clear_from_session:
# Save that we removed the messages from the session
request.session['messages'] = []
request.session.save()
return messages

View File

@ -4,6 +4,12 @@ body {
font-family: sans-serif; font-family: sans-serif;
padding:none; padding:none;
margin:0px; margin:0px;
height:100%;
}
form {
margin:0px;
padding:0px;
} }
/* Carter One font */ /* Carter One font */
@ -38,6 +44,11 @@ label {
/* website structure */ /* website structure */
.mediagoblin_body {
position:relative;
min-height:100%;
}
.mediagoblin_header { .mediagoblin_header {
width:100%; width:100%;
height:36px; height:36px;
@ -46,6 +57,63 @@ label {
margin-bottom:40px; margin-bottom:40px;
} }
.mediagoblin_footer {
width:100%;
height:26px;
background-color:#393939;
bottom:0px;
padding-top:8px;
position:absolute;
text-align:center;
font-size:14px;
color:#999;
}
.mediagoblin_content {
padding-bottom:74px;
}
ul.mediagoblin_messages {
list-style:none inside;
color:#393932;
margin:2px;
padding:2px;
}
ul.mediagoblin_messages li {
background-color:#d4d4d4;
border-style:solid;
border-width:3px;
border-color:#959595;
margin:5px;
padding:8px;
}
ul.mediagoblin_messages li.message_success {
background-color: #88d486;
border-color: #5bba59;
}
ul.mediagoblin_messages li.message_warning {
background-color: #d4c686;
border-color: #baa959;
}
ul.mediagoblin_messages li.message_error {
background-color: #d48686;
border-color: #ba5959;
}
ul.mediagoblin_messages li.message_info {
background-color: #86b9d4;
border-color: #5998ba;
}
ul.mediagoblin_messages li.message_debug {
background-color: #aa86d4;
border-color: #8659ba;
}
a.mediagoblin_logo { a.mediagoblin_logo {
width:34px; width:34px;
height:25px; height:25px;
@ -119,8 +187,8 @@ a.mediagoblin_logo:hover {
font-size:28px; font-size:28px;
} }
.form_field_input input { .form_field_input input, .form_field_input textarea {
width:300px; width:100%;
font-size:18px; font-size:18px;
} }
@ -159,11 +227,12 @@ ul.media_thumbnail {
li.media_thumbnail { li.media_thumbnail {
width:200px; width:200px;
height:133px; height:200px;
display:-moz-inline-stack; display:-moz-inline-stack;
display:inline-block; display:inline-block;
vertical-align:top; vertical-align:top;
margin:0px 10px 10px 0px; margin:0px 10px 10px 0px;
text-align:center;
zoom:1; zoom:1;
. *display:inline; . *display:inline;
} }

View File

@ -28,34 +28,49 @@
<body> <body>
{% block mediagoblin_body %} {% block mediagoblin_body %}
<div class="mediagoblin_body">
{% block mediagoblin_header %} {% block mediagoblin_header %}
<div class="mediagoblin_header"> <div class="mediagoblin_header">
<div class="container_12"> <div class="container_12">
<div class="grid_12"> <div class="grid_12">
{% block mediagoblin_logo %} {% block mediagoblin_logo %}
<a class="mediagoblin_logo" href="{{ request.urlgen('index') }}"></a> <a class="mediagoblin_logo" href="{{ request.urlgen('index') }}"></a>
{% endblock %}{% block mediagoblin_header_title %}{% endblock %} {% endblock %}{% block mediagoblin_header_title %}{% endblock %}
<div class="mediagoblin_header_right"> <div class="mediagoblin_header_right">
{% if request.user %} {% if request.user %}
<a href="{{ request.urlgen('mediagoblin.user_pages.user_home', <a href="{{ request.urlgen('mediagoblin.user_pages.user_home',
user= request.user['username']) }}"> user= request.user['username']) }}">
{{ request.user['username'] }}</a>'s account {{ request.user['username'] }}</a>'s account
(<a href="{{ request.urlgen('mediagoblin.auth.logout') }}">logout</a>) (<a href="{{ request.urlgen('mediagoblin.auth.logout') }}">logout</a>)
{% else %} {% else %}
<a href="{{ request.urlgen('mediagoblin.auth.login') }}"> <a href="{{ request.urlgen('mediagoblin.auth.login') }}">
Login</a> Login</a>
{% endif %} {% endif %}
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
{% endblock %} {% endblock %}
<div class="container_12">
{% include "mediagoblin/utils/messages.html" %}
<div class="container_12 mediagoblin_content">
<div class="grid_12"> <div class="grid_12">
{% block mediagoblin_content %} {% block mediagoblin_content %}
{% endblock mediagoblin_content %} {% endblock mediagoblin_content %}
</div> </div>
</div> </div>
{% block mediagoblin_footer %}
<div class="mediagoblin_footer">
<div class="container_12">
<div class="grid_12">
Powered by <a href="http://mediagoblin.org">MediaGoblin</a>, a <a href="http://gnu.org/">GNU project</a>
</div>
</div>
</div>
{% endblock %}
{% endblock mediagoblin_body %} {% endblock mediagoblin_body %}
</div>
</body> </body>
</html> </html>

View File

@ -27,13 +27,15 @@
method="POST" enctype="multipart/form-data"> method="POST" enctype="multipart/form-data">
<div class="grid_6 prefix_1 suffix_1 edit_box form_box"> <div class="grid_6 prefix_1 suffix_1 edit_box form_box">
<h1>Editing {{ media.title }}</h1> <h1>Editing {{ media.title }}</h1>
<div style="text-align: center;" >
<img src="{{ request.app.public_store.file_url(
media['media_files']['thumb']) }}" />
</div>
{{ wtforms_util.render_divs(form) }} {{ wtforms_util.render_divs(form) }}
<div class="form_submit_buttons"> <div class="form_submit_buttons">
<a href="{{ media.url_for_self(request.urlgen) }}">Cancel</a> <a href="{{ media.url_for_self(request.urlgen) }}">Cancel</a>
<input type="submit" value="Save changes" class="button" /> <input type="submit" value="Save changes" class="button" />
</div> </div>
<img src="{{ request.app.public_store.file_url(
media['media_files']['thumb']) }}" />
</div> </div>
</form> </form>

View File

@ -25,7 +25,9 @@
method="POST" enctype="multipart/form-data"> method="POST" enctype="multipart/form-data">
<div class="grid_6 prefix_1 suffix_1 form_box"> <div class="grid_6 prefix_1 suffix_1 form_box">
<h1>Submit yer media</h1> <h1>Submit yer media</h1>
{{ wtforms_util.render_divs(submit_form) }} {{ wtforms_util.render_field_div(submit_form.title) }}
{{ wtforms_util.render_textarea_div(submit_form.description) }}
{{ wtforms_util.render_field_div(submit_form.file) }}
<div class="form_submit_buttons"> <div class="form_submit_buttons">
<input type="submit" value="Submit" class="button" /> <input type="submit" value="Submit" class="button" />
</div> </div>

View File

@ -20,15 +20,16 @@
{% block mediagoblin_head %} {% block mediagoblin_head %}
<link rel="alternate" type="application/atom+xml" <link rel="alternate" type="application/atom+xml"
href="{{ request.urlgen( href="{{ request.urlgen(
'mediagoblin.user_pages.atom_feed', 'mediagoblin.user_pages.atom_feed',
user=user.username) }}"> user=user.username) }}">
{% endblock mediagoblin_head %} {% endblock mediagoblin_head %}
{% block mediagoblin_content -%} {% block mediagoblin_content -%}
{% if user %} {% if user %}
<h1><a href="{{ request.urlgen( <h1>
'mediagoblin.user_pages.user_home', <a href="{{ request.urlgen(
user=user.username) }}">{{ user.username }}</a>'s media</h1> 'mediagoblin.user_pages.user_home',
user=user.username) }}">{{ user.username }}</a>'s media</h1>
{% include "mediagoblin/utils/object_gallery.html" %} {% include "mediagoblin/utils/object_gallery.html" %}

View File

@ -25,16 +25,18 @@
</h1> </h1>
<img class="media_image" src="{{ request.app.public_store.file_url( <img class="media_image" src="{{ request.app.public_store.file_url(
media.media_files.main) }}" /> media.media_files.main) }}" />
<p>
Uploaded on
{{ "%4d-%02d-%02d"|format(media.created.year,
media.created.month, media.created.day) }}
by
<a href="{{ request.urlgen('mediagoblin.user_pages.user_home',
user= media.uploader().username) }}">
{{- media.uploader().username }}</a>
</p>
{% autoescape False %} {% autoescape False %}
<p>{{ media.description_html }}</p> <p>{{ media.description_html }}</p>
{% endautoescape %} {% endautoescape %}
<p>Uploaded on
{{ "%4d-%02d-%02d"|format(media.created.year,
media.created.month, media.created.day) }}
by
<a href="{{ request.urlgen('mediagoblin.user_pages.user_home',
user= media.uploader().username) }}">
{{- media.uploader().username }}</a></p>
{% if media['uploader'] == request.user['_id'] %} {% if media['uploader'] == request.user['_id'] %}
<p><a href="{{ request.urlgen('mediagoblin.edit.edit_media', <p><a href="{{ request.urlgen('mediagoblin.edit.edit_media',
user= media.uploader().username, user= media.uploader().username,

View File

@ -0,0 +1,32 @@
{#
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011 Free Software Foundation, Inc
#
# 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/>.
#}
{# Display any queued messages #}
{% set messages = fetch_messages(request) %}
{% if messages %}
<div class="container_12 mediagoblin_messages">
<div class="grid_12">
<ul class="mediagoblin_messages">
{% for msg in messages %}
<li class="message_{{ msg.level }}">{{ msg.text }}</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}

View File

@ -16,23 +16,47 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
#} #}
{# Generically render a field #}
{% macro render_field_div(field) %}
<div class="form_field_box">
<div class="form_field_label">{{ field.label }}</div>
{% if field.description -%}
<div class="form_field_description">{{ field.description }}</div>
{%- endif %}
<div class="form_field_input">{{ field }}</div>
{%- if field.errors -%}
{% for error in field.errors %}
<div class="form_field_error">
{{ error }}
</div>
{% endfor %}
{%- endif %}
</div>
{%- endmacro %}
{# Generically render a textarea
# ... mostly the same thing except it includes rows and cols #}
{% macro render_textarea_div(field, rows=8, cols=20) %}
<div class="form_field_box">
<div class="form_field_label">{{ field.label }}</div>
{% if field.description -%}
<div class="form_field_description">{{ field.description }}</div>
{%- endif %}
<div class="form_field_input">{{ field(rows=rows, cols=cols) }}</div>
{%- if field.errors -%}
{% for error in field.errors %}
<div class="form_field_error">
{{ error }}
</div>
{% endfor %}
{%- endif %}
</div>
{%- endmacro %}
{# Auto-render a form as a series of divs #} {# Auto-render a form as a series of divs #}
{% macro render_divs(form) -%} {% macro render_divs(form) -%}
{% for field in form %} {% for field in form %}
<div class="form_field_box"> {{ render_field_div(field) }}
<div class="form_field_label">{{ field.label }}</div>
{% if field.description -%}
<div class="form_field_description">{{ field.description }}</div>
{%- endif %}
<div class="form_field_input">{{ field }}</div>
{%- if field.errors -%}
{% for error in field.errors %}
<div class="form_field_error">
{{ error }}
</div>
{% endfor %}
{%- endif %}
</div>
{% endfor %} {% endfor %}
{%- endmacro %} {%- endmacro %}

View File

@ -0,0 +1,44 @@
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011 Free Software Foundation, Inc
#
# 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.messages import fetch_messages, add_message
from mediagoblin.tests.tools import setup_fresh_app
from mediagoblin import util
@setup_fresh_app
def test_messages(test_app):
"""
Added messages should show up in the request.session,
fetched messages should be the same as the added ones,
and fetching should clear the message list.
"""
# Aquire a request object
test_app.get('/')
context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
request = context['request']
# The message queue should be empty
assert request.session.get('messages', []) == []
# Adding a message should modify the session accordingly
add_message(request, 'herp_derp', 'First!')
test_msg_queue = [{'text': 'First!', 'level': 'herp_derp'}]
assert request.session['messages'] == test_msg_queue
# fetch_messages should return and empty the queue
assert fetch_messages(request) == test_msg_queue
assert request.session.get('messages') == []

View File

@ -7,6 +7,9 @@ email_sender_address = "notice@mediagoblin.example.org"
email_debug_mode = true email_debug_mode = true
db_name = __mediagoblin_tests__ db_name = __mediagoblin_tests__
# Celery shouldn't be set up by the paste app factory as it's set up # Celery shouldn't be set up by the application as it's setup via
# elsewhere # mediagoblin.celery_setup.from_celery
celery_setup_elsewhere = true celery_setup_elsewhere = true
[celery]
celery_always_eager = true

View File

@ -21,9 +21,8 @@ import os, shutil
from paste.deploy import loadapp from paste.deploy import loadapp
from webtest import TestApp from webtest import TestApp
from mediagoblin import util, mg_globals from mediagoblin import util
from mediagoblin.config import read_mediagoblin_config from mediagoblin.config import read_mediagoblin_config
from mediagoblin.celery_setup import setup_celery_from_config
from mediagoblin.decorators import _make_safe from mediagoblin.decorators import _make_safe
from mediagoblin.db.open import setup_connection_and_db_from_config from mediagoblin.db.open import setup_connection_and_db_from_config
@ -36,7 +35,6 @@ TEST_APP_CONFIG = pkg_resources.resource_filename(
TEST_USER_DEV = pkg_resources.resource_filename( TEST_USER_DEV = pkg_resources.resource_filename(
'mediagoblin.tests', 'test_user_dev') 'mediagoblin.tests', 'test_user_dev')
MGOBLIN_APP = None MGOBLIN_APP = None
CELERY_SETUP = False
USER_DEV_DIRECTORIES_TO_SETUP = [ USER_DEV_DIRECTORIES_TO_SETUP = [
'media/public', 'media/queue', 'media/public', 'media/queue',
@ -60,8 +58,10 @@ def suicide_if_bad_celery_environ():
def get_test_app(dump_old_app=True): def get_test_app(dump_old_app=True):
suicide_if_bad_celery_environ() suicide_if_bad_celery_environ()
# Leave this imported as it sets up celery.
from mediagoblin.celery_setup import from_tests
global MGOBLIN_APP global MGOBLIN_APP
global CELERY_SETUP
# Just return the old app if that exists and it's okay to set up # Just return the old app if that exists and it's okay to set up
# and return # and return
@ -103,13 +103,6 @@ def get_test_app(dump_old_app=True):
app = TestApp(test_app) app = TestApp(test_app)
MGOBLIN_APP = app MGOBLIN_APP = app
# setup celery
if not CELERY_SETUP:
setup_celery_from_config(
mg_globals.app_config, mg_globals.global_config,
set_environ=True)
CELERY_SETUP = True
return app return app

View File

@ -32,6 +32,7 @@ from lxml.html.clean import Cleaner
import markdown import markdown
from mediagoblin import mg_globals from mediagoblin import mg_globals
from mediagoblin import messages
from mediagoblin.db.util import ObjectId from mediagoblin.db.util import ObjectId
TESTS_ENABLED = False TESTS_ENABLED = False
@ -104,6 +105,10 @@ def get_jinja_env(template_loader, locale):
mg_globals.translations.gettext, mg_globals.translations.gettext,
mg_globals.translations.ngettext) mg_globals.translations.ngettext)
# All templates will know how to ...
# ... fetch all waiting messages and remove them from the queue
template_env.globals['fetch_messages'] = messages.fetch_messages
if exists(locale): if exists(locale):
SETUP_JINJA_ENVS[locale] = template_env SETUP_JINJA_ENVS[locale] = template_env