diff options
Diffstat (limited to 'mediagoblin')
21 files changed, 219 insertions, 94 deletions
diff --git a/mediagoblin/app.py b/mediagoblin/app.py index 57e09e49..e9177eff 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -39,7 +39,6 @@ from mediagoblin.init import (get_jinja_loader, get_staticdirector, from mediagoblin.tools.pluginapi import PluginManager, hook_transform from mediagoblin.tools.crypto import setup_crypto from mediagoblin.auth.tools import check_auth_enabled, no_auth_logout -from mediagoblin import notifications _log = logging.getLogger(__name__) @@ -199,8 +198,6 @@ class MediaGoblinApp(object): # Log user out if authentication_disabled no_auth_logout(request) - request.notifications = notifications - mg_request.setup_user_in_request(request) request.controller_name = None diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index d2ada163..81dadd25 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -75,6 +75,12 @@ theme = string() plugin_web_path = string(default="/plugin_static/") plugin_linked_assets_dir = string(default="%(here)s/user_dev/plugin_static/") +[jinja2] +# Jinja2 supports more directives than the minimum required by mediagoblin. +# This setting allows users creating custom templates to specify a list of +# additional extensions they want to use. example value: +# extensions = jinja2.ext.loopcontrols , jinja2.ext.with_ +extensions = string_list(default=list()) [storage:publicstore] storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage") @@ -116,7 +122,7 @@ vp8_quality = integer(default=8) vorbis_quality = float(default=0.3) # Autoplay the video when page is loaded? -auto_play = boolean(default=True) +auto_play = boolean(default=False) [[skip_transcode]] mime_types = string_list(default=list("video/webm")) diff --git a/mediagoblin/db/migration_tools.py b/mediagoblin/db/migration_tools.py index aa22ef94..e75f3757 100644 --- a/mediagoblin/db/migration_tools.py +++ b/mediagoblin/db/migration_tools.py @@ -29,7 +29,7 @@ class MigrationManager(object): to the latest migrations, etc. """ - def __init__(self, name, models, migration_registry, session, + def __init__(self, name, models, foundations, migration_registry, session, printer=simple_printer): """ Args: @@ -40,6 +40,7 @@ class MigrationManager(object): """ self.name = unicode(name) self.models = models + self.foundations = foundations self.session = session self.migration_registry = migration_registry self._sorted_migrations = None @@ -140,6 +141,18 @@ class MigrationManager(object): self.session.bind, tables=[model.__table__ for model in self.models]) + def populate_table_foundations(self): + """ + Create the table foundations (default rows) as layed out in FOUNDATIONS + in mediagoblin.db.models + """ + for Model, rows in self.foundations.items(): + self.printer(u' + Laying foundations for %s table\n' % + (Model.__name__)) + for parameters in rows: + new_row = Model(**parameters) + self.session.add(new_row) + def create_new_migration_record(self): """ Create a new migration record for this migration set @@ -202,9 +215,9 @@ class MigrationManager(object): self.init_tables() # auto-set at latest migration number - self.create_new_migration_record() - + self.create_new_migration_record() self.printer(u"done.\n") + self.populate_table_foundations() self.set_current_migration() return u'inited' diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 74dea44e..f0cbce2a 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -651,6 +651,21 @@ MODELS = [ MediaAttachmentFile, ProcessingMetaData, Notification, CommentNotification, ProcessingNotification, CommentSubscription] +""" + Foundations are the default rows that are created immediately after the tables + are initialized. Each entry to this dictionary should be in the format of: + ModelConstructorObject:List of Dictionaries + (Each Dictionary represents a row on the Table to be created, containing each + of the columns' names as a key string, and each of the columns' values as a + value) + + ex. [NOTE THIS IS NOT BASED OFF OF OUR USER TABLE] + user_foundations = [{'name':u'Joanna', 'age':24}, + {'name':u'Andrea', 'age':41}] + + FOUNDATIONS = {User:user_foundations} +""" +FOUNDATIONS = {} ###################################################### # Special, migrations-tracking table diff --git a/mediagoblin/gmg_commands/dbupdate.py b/mediagoblin/gmg_commands/dbupdate.py index 00007567..961752f6 100644 --- a/mediagoblin/gmg_commands/dbupdate.py +++ b/mediagoblin/gmg_commands/dbupdate.py @@ -32,14 +32,15 @@ def dbupdate_parse_setup(subparser): class DatabaseData(object): - def __init__(self, name, models, migrations): + def __init__(self, name, models, foundations, migrations): self.name = name self.models = models + self.foundations = foundations self.migrations = migrations def make_migration_manager(self, session): return MigrationManager( - self.name, self.models, self.migrations, session) + self.name, self.models, self.foundations, self.migrations, session) def gather_database_data(plugins): @@ -54,10 +55,11 @@ def gather_database_data(plugins): # Add main first from mediagoblin.db.models import MODELS as MAIN_MODELS from mediagoblin.db.migrations import MIGRATIONS as MAIN_MIGRATIONS + from mediagoblin.db.models import FOUNDATIONS as MAIN_FOUNDATIONS managed_dbdata.append( DatabaseData( - u'__main__', MAIN_MODELS, MAIN_MIGRATIONS)) + u'__main__', MAIN_MODELS, MAIN_FOUNDATIONS, MAIN_MIGRATIONS)) for plugin in plugins: try: @@ -83,13 +85,26 @@ forgotten to add it? ({1})'.format(plugin, exc)) migrations = {} except AttributeError as exc: - _log.debug('Cloud not find MIGRATIONS in {0}.migrations, have you \ + _log.debug('Could not find MIGRATIONS in {0}.migrations, have you \ forgotten to add it? ({1})'.format(plugin, exc)) migrations = {} + try: + foundations = import_component('{0}.models:FOUNDATIONS'.format(plugin)) + except ImportError as exc: + _log.debug('No foundations found for {0}: {1}'.format( + plugin, + exc)) + + foundations = {} + except AttributeError as exc: + _log.debug('Could not find FOUNDATIONS in {0}.models, have you \ +forgotten to add it? ({1})'.format(plugin, exc)) + foundations = {} + if models: managed_dbdata.append( - DatabaseData(plugin, models, migrations)) + DatabaseData(plugin, models, foundations, migrations)) return managed_dbdata @@ -111,7 +126,7 @@ def run_dbupdate(app_config, global_config): def run_all_migrations(db, app_config, global_config): """ - Initializes or migrates a database that already has a + Initializes or migrates a database that already has a connection setup and also initializes or migrates all extensions based on the config files. diff --git a/mediagoblin/media_types/audio/__init__.py b/mediagoblin/media_types/audio/__init__.py index 90f842ba..c7ed8d2d 100644 --- a/mediagoblin/media_types/audio/__init__.py +++ b/mediagoblin/media_types/audio/__init__.py @@ -19,6 +19,9 @@ from mediagoblin.media_types.audio.processing import process_audio, \ sniff_handler from mediagoblin.tools import pluginapi +# Why isn't .ogg in this list? It's still detected, but via sniffing, +# .ogg files could be either video or audio... sniffing determines which. + ACCEPTED_EXTENSIONS = ["mp3", "flac", "wav", "m4a"] MEDIA_TYPE = 'mediagoblin.media_types.audio' diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 5386ba60..857c1647 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -14,7 +14,7 @@ # 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 tempfile import NamedTemporaryFile +import os.path import logging import datetime @@ -73,79 +73,77 @@ def process_video(proc_state): queued_filename = proc_state.get_queued_filename() name_builder = FilenameBuilder(queued_filename) - medium_filepath = create_pub_filepath( - entry, name_builder.fill('{basename}-640p.webm')) + medium_basename = name_builder.fill('{basename}-640p.webm') + medium_filepath = create_pub_filepath(entry, medium_basename) - thumbnail_filepath = create_pub_filepath( - entry, name_builder.fill('{basename}.thumbnail.jpg')) + thumbnail_basename = name_builder.fill('{basename}.thumbnail.jpg') + thumbnail_filepath = create_pub_filepath(entry, thumbnail_basename) # Create a temporary file for the video destination (cleaned up with workbench) - tmp_dst = NamedTemporaryFile(dir=workbench.dir, delete=False) - with tmp_dst: - # Transcode queued file to a VP8/vorbis file that fits in a 640x640 square - progress_callback = ProgressCallback(entry) + tmp_dst = os.path.join(workbench.dir, medium_basename) + # Transcode queued file to a VP8/vorbis file that fits in a 640x640 square + progress_callback = ProgressCallback(entry) - dimensions = ( - mgg.global_config['media:medium']['max_width'], - mgg.global_config['media:medium']['max_height']) + dimensions = ( + mgg.global_config['media:medium']['max_width'], + mgg.global_config['media:medium']['max_height']) - # Extract metadata and keep a record of it - metadata = transcoders.VideoTranscoder().discover(queued_filename) - store_metadata(entry, metadata) + # Extract metadata and keep a record of it + metadata = transcoders.VideoTranscoder().discover(queued_filename) + store_metadata(entry, metadata) - # Figure out whether or not we need to transcode this video or - # if we can skip it - if skip_transcode(metadata): - _log.debug('Skipping transcoding') + # Figure out whether or not we need to transcode this video or + # if we can skip it + if skip_transcode(metadata): + _log.debug('Skipping transcoding') - dst_dimensions = metadata['videowidth'], metadata['videoheight'] + dst_dimensions = metadata['videowidth'], metadata['videoheight'] # Push original file to public storage - _log.debug('Saving original...') - proc_state.copy_original(queued_filepath[-1]) + _log.debug('Saving original...') + proc_state.copy_original(queued_filepath[-1]) - did_transcode = False - else: - transcoder = transcoders.VideoTranscoder() + did_transcode = False + else: + transcoder = transcoders.VideoTranscoder() - transcoder.transcode(queued_filename, tmp_dst.name, - vp8_quality=video_config['vp8_quality'], - vp8_threads=video_config['vp8_threads'], - vorbis_quality=video_config['vorbis_quality'], - progress_callback=progress_callback, - dimensions=dimensions) + transcoder.transcode(queued_filename, tmp_dst, + vp8_quality=video_config['vp8_quality'], + vp8_threads=video_config['vp8_threads'], + vorbis_quality=video_config['vorbis_quality'], + progress_callback=progress_callback, + dimensions=dimensions) - dst_dimensions = transcoder.dst_data.videowidth,\ - transcoder.dst_data.videoheight + dst_dimensions = transcoder.dst_data.videowidth,\ + transcoder.dst_data.videoheight - # Push transcoded video to public storage - _log.debug('Saving medium...') - mgg.public_store.copy_local_to_storage(tmp_dst.name, medium_filepath) - _log.debug('Saved medium') + # Push transcoded video to public storage + _log.debug('Saving medium...') + mgg.public_store.copy_local_to_storage(tmp_dst, medium_filepath) + _log.debug('Saved medium') - entry.media_files['webm_640'] = medium_filepath + entry.media_files['webm_640'] = medium_filepath - did_transcode = True + did_transcode = True - # Save the width and height of the transcoded video - entry.media_data_init( - width=dst_dimensions[0], - height=dst_dimensions[1]) + # Save the width and height of the transcoded video + entry.media_data_init( + width=dst_dimensions[0], + height=dst_dimensions[1]) # Temporary file for the video thumbnail (cleaned up with workbench) - tmp_thumb = NamedTemporaryFile(dir=workbench.dir, suffix='.jpg', delete=False) - - with tmp_thumb: - # Create a thumbnail.jpg that fits in a 180x180 square - transcoders.VideoThumbnailerMarkII( - queued_filename, - tmp_thumb.name, - 180) - - # Push the thumbnail to public storage - _log.debug('Saving thumbnail...') - mgg.public_store.copy_local_to_storage(tmp_thumb.name, thumbnail_filepath) - entry.media_files['thumb'] = thumbnail_filepath + tmp_thumb = os.path.join(workbench.dir, thumbnail_basename) + + # Create a thumbnail.jpg that fits in a 180x180 square + transcoders.VideoThumbnailerMarkII( + queued_filename, + tmp_thumb, + 180) + + # Push the thumbnail to public storage + _log.debug('Saving thumbnail...') + mgg.public_store.copy_local_to_storage(tmp_thumb, thumbnail_filepath) + entry.media_files['thumb'] = thumbnail_filepath # save the original... but only if we did a transcoding # (if we skipped transcoding and just kept the original anyway as the main diff --git a/mediagoblin/notifications/__init__.py b/mediagoblin/notifications/__init__.py index 4b7fbb8c..ed9f8d78 100644 --- a/mediagoblin/notifications/__init__.py +++ b/mediagoblin/notifications/__init__.py @@ -18,7 +18,6 @@ import logging from mediagoblin.db.models import Notification, \ CommentNotification, CommentSubscription -from mediagoblin.notifications.task import email_notification_task from mediagoblin.notifications.tools import generate_comment_message _log = logging.getLogger(__name__) @@ -50,6 +49,7 @@ def trigger_notification(comment, media_entry, request): media_entry, request) + from mediagoblin.notifications.task import email_notification_task email_notification_task.apply_async([cn.id, message]) diff --git a/mediagoblin/static/images/home_goblin.png b/mediagoblin/static/images/home_goblin.png Binary files differnew file mode 100644 index 00000000..5ba9afeb --- /dev/null +++ b/mediagoblin/static/images/home_goblin.png diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js index c5ccee66..df3c1093 100644 --- a/mediagoblin/static/js/comment_show.js +++ b/mediagoblin/static/js/comment_show.js @@ -15,12 +15,25 @@ * 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/>. */ +var content=""; +function previewComment(){ + if ($('#comment_content').val() && (content != $('#comment_content').val())) { + content = $('#comment_content').val(); + $.post($('#previewURL').val(),$('#form_comment').serialize(), + function(data){ + preview = JSON.parse(data) + $('#comment_preview').replaceWith("<div id=comment_preview><h3>" + $('#previewText').val() +"</h3><br />" + preview.content + + "<hr style='border: 1px solid #333;' /></div>"); + }); + } +} $(document).ready(function(){ $('#form_comment').hide(); $('#button_addcomment').click(function(){ $(this).fadeOut('fast'); $('#form_comment').slideDown(function(){ + setInterval("previewComment()",1000); $('#comment_content').focus(); }); }); diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index 1fc4467c..65dbebc0 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -60,13 +60,13 @@ {%- if request.user %} {% if request.user and request.user.status == 'active' %} - {% set notification_count = request.notifications.get_notification_count(request.user.id) %} + {% set notification_count = get_notification_count(request.user.id) %} {% if notification_count %} - <a href="#notifications" class="notification-gem button_action" title="Notifications"> - {{ notification_count }}</a> + <a href="#notifications" class="notification-gem button_action" title="Notifications"> + {{ notification_count }}</a> {% endif %} - <div class="button_action header_dropdown_down">▼</div> - <div class="button_action header_dropdown_up">▲</div> + <a href="#header" class="button_action header_dropdown_down">▼</a> + <a href="#no_header" class="button_action header_dropdown_up">▲</a> {% elif request.user and request.user.status == "needs_email_verification" %} {# the following link should only appear when verification is needed #} <a href="{{ request.urlgen('mediagoblin.user_pages.user_home', diff --git a/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html b/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html index 9ef28a4d..e2463328 100644 --- a/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html +++ b/mediagoblin/templates/mediagoblin/bits/frontpage_welcome.html @@ -19,8 +19,8 @@ {% if request.user %} <h1>{% trans %}Explore{% endtrans %}</h1> {% else %} + <img class="right_align" src="{{ request.staticdirect('/images/home_goblin.png') }}" /> <h1>{% trans %}Hi there, welcome to this MediaGoblin site!{% endtrans %}</h1> - <img class="right_align" src="{{ request.staticdirect('/images/frontpage_image.png') }}" /> <p>{% trans %}This site is running <a href="http://mediagoblin.org">MediaGoblin</a>, an extraordinarily great piece of media hosting software.{% endtrans %}</p> {% if auth %} <p>{% trans %}To add your own media, place comments, and more, you can log in with your MediaGoblin account.{% endtrans %}</p> @@ -33,7 +33,7 @@ {% endif %} {% endif %} {% trans %} - <a class="button_action" href="http://wiki.mediagoblin.org/HackingHowto">Set up MediaGoblin on your own server</a> + <a class="button_action" href="http://mediagoblin.readthedocs.org/">Set up MediaGoblin on your own server</a> {%- endtrans %} <div class="clear"></div> diff --git a/mediagoblin/templates/mediagoblin/fragments/header_notifications.html b/mediagoblin/templates/mediagoblin/fragments/header_notifications.html index 613100aa..70d7935a 100644 --- a/mediagoblin/templates/mediagoblin/fragments/header_notifications.html +++ b/mediagoblin/templates/mediagoblin/fragments/header_notifications.html @@ -1,4 +1,4 @@ -{% set notifications = request.notifications.get_notifications(request.user.id) %} +{% set notifications = get_notifications(request.user.id) %} {% if notifications %} <div class="header_notifications"> <h3>{% trans %}New comments{% endtrans %}</h3> diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index c16e4c78..39935b40 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -90,7 +90,8 @@ {% if app_config['allow_comments'] %} <a {% if not request.user %} - href="{{ request.urlgen('mediagoblin.auth.login') }}" + href="{{ request.urlgen('mediagoblin.auth.login') }}?next={{ + request.base_url|urlencode }}" {% endif %} class="button_action" id="button_addcomment" title="Add a comment"> {% trans %}Add a comment{% endtrans %} @@ -107,7 +108,10 @@ <input type="submit" value="{% trans %}Add this comment{% endtrans %}" class="button_action" /> {{ csrf_token }} </div> + <input type="hidden" value="{{ request.urlgen('mediagoblin.user_pages.media_preview_comment') }}" id="previewURL" /> + <input type="hidden" value="{% trans %}Comment Preview{% endtrans %}" id="previewText"/> </form> + <div id="comment_preview"></div> {% endif %} <ul style="list-style:none"> {% for comment in comments %} diff --git a/mediagoblin/templates/mediagoblin/utils/comment-subscription.html b/mediagoblin/templates/mediagoblin/utils/comment-subscription.html index bd367e80..75da5e89 100644 --- a/mediagoblin/templates/mediagoblin/utils/comment-subscription.html +++ b/mediagoblin/templates/mediagoblin/utils/comment-subscription.html @@ -16,8 +16,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. #} {%- if request.user %} - {% set subscription = request.notifications.get_comment_subscription( - request.user.id, media.id) %} + {% set subscription = get_comment_subscription(request.user.id, media.id) %} {% if not subscription or not subscription.notify %} <a type="submit" href="{{ request.urlgen('mediagoblin.notifications.subscribe_comments', user=media.get_uploader.username, diff --git a/mediagoblin/tests/test_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py index 2fc4c043..3d67fdf6 100644 --- a/mediagoblin/tests/test_sql_migrations.py +++ b/mediagoblin/tests/test_sql_migrations.py @@ -58,6 +58,10 @@ class Level1(Base1): SET1_MODELS = [Creature1, Level1] +FOUNDATIONS = {Creature1:[{'name':u'goblin','num_legs':2,'is_demon':False}, + {'name':u'cerberus','num_legs':4,'is_demon':True}] + } + SET1_MIGRATIONS = {} ####################################################### @@ -542,7 +546,6 @@ def _insert_migration3_objects(session): session.commit() - def create_test_engine(): from sqlalchemy import create_engine engine = create_engine('sqlite:///:memory:', echo=False) @@ -572,7 +575,7 @@ def test_set1_to_set3(): printer = CollectingPrinter() migration_manager = MigrationManager( - u'__main__', SET1_MODELS, SET1_MIGRATIONS, Session(), + u'__main__', SET1_MODELS, FOUNDATIONS, SET1_MIGRATIONS, Session(), printer) # Check latest migration and database current migration @@ -585,11 +588,13 @@ def test_set1_to_set3(): assert result == u'inited' # Check output assert printer.combined_string == ( - "-> Initializing main mediagoblin tables... done.\n") + "-> Initializing main mediagoblin tables... done.\n" + \ + " + Laying foundations for Creature1 table\n" ) # Check version in database assert migration_manager.latest_migration == 0 assert migration_manager.database_current_migration == 0 + # Install the initial set # ----------------------- @@ -597,8 +602,8 @@ def test_set1_to_set3(): # Try to "re-migrate" with same manager settings... nothing should happen migration_manager = MigrationManager( - u'__main__', SET1_MODELS, SET1_MIGRATIONS, Session(), - printer) + u'__main__', SET1_MODELS, FOUNDATIONS, SET1_MIGRATIONS, + Session(), printer) assert migration_manager.init_or_migrate() == None # Check version in database @@ -639,6 +644,20 @@ def test_set1_to_set3(): # Now check to see if stuff seems to be in there. session = Session() + # Check the creation of the foundation rows on the creature table + creature = session.query(Creature1).filter_by( + name=u'goblin').one() + assert creature.num_legs == 2 + assert creature.is_demon == False + + creature = session.query(Creature1).filter_by( + name=u'cerberus').one() + assert creature.num_legs == 4 + assert creature.is_demon == True + + + # Check the creation of the inserted rows on the creature and levels tables + creature = session.query(Creature1).filter_by( name=u'centipede').one() assert creature.num_legs == 100 @@ -679,7 +698,7 @@ def test_set1_to_set3(): # isn't said to be updated yet printer = CollectingPrinter() migration_manager = MigrationManager( - u'__main__', SET3_MODELS, SET3_MIGRATIONS, Session(), + u'__main__', SET3_MODELS, FOUNDATIONS, SET3_MIGRATIONS, Session(), printer) assert migration_manager.latest_migration == 8 @@ -706,7 +725,7 @@ def test_set1_to_set3(): # Make sure version matches expected migration_manager = MigrationManager( - u'__main__', SET3_MODELS, SET3_MIGRATIONS, Session(), + u'__main__', SET3_MODELS, FOUNDATIONS, SET3_MIGRATIONS, Session(), printer) assert migration_manager.latest_migration == 8 assert migration_manager.database_current_migration == 8 @@ -772,6 +791,15 @@ def test_set1_to_set3(): # Now check to see if stuff seems to be in there. session = Session() + + + # Start with making sure that the foundations did not run again + assert session.query(Creature3).filter_by( + name=u'goblin').count() == 1 + assert session.query(Creature3).filter_by( + name=u'cerberus').count() == 1 + + # Then make sure the models have been migrated correctly creature = session.query(Creature3).filter_by( name=u'centipede').one() assert creature.num_limbs == 100.0 diff --git a/mediagoblin/tools/session.py b/mediagoblin/tools/session.py index d79afb66..a57f69cc 100644 --- a/mediagoblin/tools/session.py +++ b/mediagoblin/tools/session.py @@ -17,7 +17,7 @@ import itsdangerous import logging -import crypto +from mediagoblin.tools import crypto _log = logging.getLogger(__name__) diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py index 615ce129..fa290611 100644 --- a/mediagoblin/tools/template.py +++ b/mediagoblin/tools/template.py @@ -32,7 +32,6 @@ from mediagoblin.tools.timesince import timesince from mediagoblin.meddleware.csrf import render_csrf_form_token - SETUP_JINJA_ENVS = {} @@ -50,6 +49,12 @@ def get_jinja_env(template_loader, locale): if locale in SETUP_JINJA_ENVS: return SETUP_JINJA_ENVS[locale] + # The default config does not require a [jinja2] block. + # You may create one if you wish to enable additional jinja2 extensions, + # see example in config_spec.ini + jinja2_config = mg_globals.global_config.get('jinja2', {}) + local_exts = jinja2_config.get('extensions', []) + # jinja2.StrictUndefined will give exceptions on references # to undefined/unknown variables in templates. template_env = jinja2.Environment( @@ -57,7 +62,7 @@ def get_jinja_env(template_loader, locale): undefined=jinja2.StrictUndefined, extensions=[ 'jinja2.ext.i18n', 'jinja2.ext.autoescape', - TemplateHookExtension]) + TemplateHookExtension] + local_exts) template_env.install_gettext_callables( mg_globals.thread_scope.translations.ugettext, @@ -84,6 +89,16 @@ def get_jinja_env(template_loader, locale): template_env.globals = hook_transform( 'template_global_context', template_env.globals) + #### THIS IS TEMPORARY, PLEASE FIX IT + ## Notifications stuff is not yet a plugin (and we're not sure it will be), + ## but it needs to add stuff to the context. This is THE WRONG WAY TO DO IT + from mediagoblin import notifications + template_env.globals['get_notifications'] = notifications.get_notifications + template_env.globals[ + 'get_notification_count'] = notifications.get_notification_count + template_env.globals[ + 'get_comment_subscription'] = notifications.get_comment_subscription + if exists(locale): SETUP_JINJA_ENVS[locale] = template_env diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index 9a193680..ac8084c5 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -23,7 +23,7 @@ class MediaCommentForm(wtforms.Form): _('Comment'), [wtforms.validators.Required()], description=_(u'You can use ' - u'<a href="http://daringfireball.net/projects/markdown/basics">' + u'<a href="http://daringfireball.net/projects/markdown/basics" target="_blank">' u'Markdown</a> for formatting.')) class ConfirmDeleteForm(wtforms.Form): @@ -47,5 +47,5 @@ class MediaCollectForm(wtforms.Form): collection_description = wtforms.TextAreaField( _('Description of this collection'), description=_("""You can use - <a href="http://daringfireball.net/projects/markdown/basics"> + <a href="http://daringfireball.net/projects/markdown/basics" target="_blank"> Markdown</a> for formatting.""")) diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index 9cb665b5..b1dde397 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -32,6 +32,10 @@ add_route('mediagoblin.user_pages.media_post_comment', '/u/<string:user>/m/<int:media_id>/comment/add/', 'mediagoblin.user_pages.views:media_post_comment') +add_route('mediagoblin.user_pages.media_preview_comment', + '/ajax/comment/preview/', + 'mediagoblin.user_pages.views:media_preview_comment') + add_route('mediagoblin.user_pages.user_gallery', '/u/<string:user>/gallery/', 'mediagoblin.user_pages.views:user_gallery') diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 596d4c20..91ea04b8 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -16,19 +16,20 @@ import logging import datetime +import json from mediagoblin import messages, mg_globals from mediagoblin.db.models import (MediaEntry, MediaTag, Collection, CollectionItem, User) from mediagoblin.tools.response import render_to_response, render_404, \ redirect, redirect_obj +from mediagoblin.tools.text import cleaned_markdown_conversion from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.pagination import Pagination from mediagoblin.user_pages import forms as user_forms from mediagoblin.user_pages.lib import add_media_to_collection from mediagoblin.notifications import trigger_notification, \ add_comment_subscription, mark_comment_notification_seen - from mediagoblin.decorators import (uses_pagination, get_user_media_entry, get_media_entry_by_id, require_active_login, user_may_delete_media, user_may_alter_collection, @@ -36,6 +37,7 @@ from mediagoblin.decorators import (uses_pagination, get_user_media_entry, from werkzeug.contrib.atom import AtomFeed from werkzeug.exceptions import MethodNotAllowed +from werkzeug.wrappers import Response _log = logging.getLogger(__name__) @@ -166,6 +168,7 @@ def media_post_comment(request, media): comment = request.db.MediaComment() comment.media_entry = media.id comment.author = request.user.id + print request.form['comment_content'] comment.content = unicode(request.form['comment_content']) # Show error message if commenting is disabled. @@ -193,6 +196,18 @@ def media_post_comment(request, media): return redirect_obj(request, media) + +def media_preview_comment(request): + """Runs a comment through markdown so it can be previewed.""" + # If this isn't an ajax request, render_404 + if not request.is_xhr: + return render_404(request) + + comment = unicode(request.form['comment_content']) + cleancomment = { "content":cleaned_markdown_conversion(comment)} + + return Response(json.dumps(cleancomment)) + @get_media_entry_by_id @require_active_login def media_collect(request, media): |