Merge branch 'media_panel'

This commit is contained in:
Boris Bobrov 2016-02-05 04:33:05 +03:00
commit 3b6b009077
11 changed files with 233 additions and 87 deletions

View File

@ -57,4 +57,5 @@ base_url = /mgoblin_media/
[plugins]
[[mediagoblin.plugins.geolocation]]
[[mediagoblin.plugins.basic_auth]]
[[mediagoblin.plugins.processing_info]]
[[mediagoblin.media_types.image]]

View File

@ -0,0 +1,5 @@
==============
sampleplugin
==============
A plugin to insert some useful information about processing to templates

View File

@ -0,0 +1,50 @@
# 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/>.
import logging
import os
from mediagoblin.tools.pluginapi import get_config
from mediagoblin.db.models import MediaEntry
from mediagoblin.tools import pluginapi
_log = logging.getLogger(__name__)
PLUGIN_DIR = os.path.dirname(__file__)
def setup_plugin():
pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates'))
pluginapi.register_template_hooks(
{'header_left': 'mediagoblin/processing_info/header_left.html'})
return
def make_stats(context):
request = context['request']
user = request.user
num_queued = MediaEntry.query.filter_by(
actor=user.id, state=u'processing').count()
context['num_queued'] = num_queued
num_failed = MediaEntry.query.filter_by(
actor=user.id, state=u'failed').count()
context['num_failed'] = num_failed
return context
hooks = {
'setup': setup_plugin,
'template_context_prerender': make_stats
}

View File

@ -0,0 +1,32 @@
{#
# 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/>.
#}
{#This injects some information about entries in processing #}
{% if request.user and request.user.has_privilege('active') %}
{% if num_queued is defined and num_queued != 0 %}
<span class="num_queued status_icon">
<a href="{{ request.urlgen('mediagoblin.user_pages.processing_panel',
user=request.user.username, state="processing") }}">&#9203; {{ num_queued }}</a>
</span>
{% endif %}
{% if num_failed is defined and num_failed != 0 %}
<span class="num_failed status_icon">
<a href="{{ request.urlgen('mediagoblin.user_pages.processing_panel',
user=request.user.username, state="failed") }}">&#9785; {{ num_failed }}</a>
</span>
{% endif %}
{% endif %}

View File

@ -325,14 +325,13 @@ def mark_entry_failed(entry_id, exc):
u'fail_metadata': exc.metadata})
else:
_log.warn("No idea what happened here, but it failed: %r", exc)
# Looks like no, so just mark it as failed and don't record a
# failure_error (we'll assume it wasn't handled) and don't record
# metadata (in fact overwrite it if somehow it had previous info
# here)
# Looks like no, let's record it so that admin could ask us about the
# reason
atomic_update(mgg.database.MediaEntry,
{'id': entry_id},
{u'state': u'failed',
u'fail_error': None,
u'fail_error': u'Unhandled exception: {0}'.format(
six.text_type(exc)),
u'fail_metadata': {}})
@ -410,8 +409,11 @@ class BaseProcessingFail(Exception):
return u"%s:%s" % (
self.__class__.__module__, self.__class__.__name__)
def __init__(self, **metadata):
self.metadata = metadata or {}
def __init__(self, message=None, **metadata):
if message is not None:
super(BaseProcessingFail, self).__init__(message)
metadata['message'] = message
self.metadata = metadata
class BadMediaFail(BaseProcessingFail):
"""

View File

@ -171,6 +171,26 @@ header {
a.logo {
color: #fff;
font-weight: bold;
text-decoration: none;
}
.status_icon {
border-radius: 2px;
padding: 4px;
margin: 0px 4px;
}
.num_queued {
background: #56446F;
}
.num_failed {
background: #87453B;
}
.status_icon a {
display: inline-block;
color: #C3C3C3;
}
.logo img {
@ -754,6 +774,42 @@ table.media_panel th {
padding-bottom: 4px;
text-align: left;
}
.thumb-overlay-status {
position: absolute;
margin: auto;
top: 0; bottom: 0; left: 0; right: 0;
width: 180px;
height: 20px;
display: inline;
text-align: center;
background-color: rgba(255, 255, 255, 0.8);
}
.thumb-processing {
color: black;
font-weight: bold;
}
.thumb-failed {
color: red;
font-weight: bold;
}
.thumb-wrapper {
position: relative;
/* for proportional thumb resizing */
width: auto;
height: auto;
display: inline-block;
}
.thumb-wrapper img {
max-height: 180px;
max-width: 180px;
}
.media_panel td {
vertical-align: middle;
}
/* moderator panels */

View File

@ -72,6 +72,7 @@
<div class="row foot">
<div class="header_left">
{%- include "mediagoblin/bits/logo.html" -%}
{% template_hook("header_left") %}
{% block mediagoblin_header_title %}{% endblock %}
</div>
<div class="header_right">

View File

@ -43,8 +43,18 @@
</tr>
{% for media_entry in processing_entries %}
<tr>
<td>
<div class="thumb-wrapper">
<img src="{{ media_entry.thumb_url }}" alt="{{ media_entry.title }}" />
<div class="thumb-overlay-status thumb-processing">Processing...</div>
</div>
</td>
<td>{{ media_entry.id }}</td>
<td>{{ media_entry.get_actor.username }}</td>
<td>
<a href="{{ request.urlgen('mediagoblin.moderation.users_detail', user=media_entry.get_actor.username) }}">
{{ media_entry.get_actor.username }}
</a>
</td>
<td>{{ media_entry.title }}</td>
<td>{{ media_entry.created.strftime("%F %R") }}</td>
{% if media_entry.transcoding_progress %}

View File

@ -17,6 +17,8 @@
#}
{% extends "mediagoblin/base.html" %}
{% from "mediagoblin/utils/pagination.html" import render_pagination %}
{% block title -%}
{% trans %}Media processing panel{% endtrans %} &mdash; {{ super() }}
{%- endblock %}
@ -28,20 +30,53 @@
<p>
{% trans %}You can track the state of media being processed for your gallery here.{% endtrans %}
</p>
<h2>{% trans %}Media in-processing{% endtrans %}</h2>
{% if processing_entries.count() %}
<p>
Show:
<a href="{{ request.urlgen('mediagoblin.user_pages.processing_panel',
user=request.user.username) }}">All</a>,
<a href="{{ request.urlgen('mediagoblin.user_pages.processing_panel',
user=request.user.username, state="processing") }}">In processing</a>,
<a href="{{ request.urlgen('mediagoblin.user_pages.processing_panel',
user=request.user.username, state="failed") }}">Failed</a>,
<a href="{{ request.urlgen('mediagoblin.user_pages.processing_panel',
user=request.user.username, state="processed") }}">Succesful</a>
</p>
{% if entries.count() %}
{{ render_pagination(request, pagination) }}
<table class="media_panel processing">
<tr>
<th>ID</th>
<th width="210">Thumbnail</th>
<th>Title</th>
<th>When submitted</th>
<th>Transcoding progress</th>
<th width="20%">When submitted</th>
<th width="200">Transcoding progress</th>
</tr>
{% for media_entry in processing_entries %}
{% for media_entry in entries %}
<tr>
<td>{{ media_entry.id }}</td>
{% if media_entry.state == 'processed' %}
{% set entry_url = media_entry.url_for_self(request.urlgen) %}
<td>
<div class="thumb-wrapper">
<a href="{{ entry_url }}">
<img src="{{ media_entry.thumb_url }}" alt="{{ media_entry.title }}" />
</a>
</div>
</td>
<td><a href="{{ entry_url }}">{{ media_entry.title }}</a></td>
<td>{{ media_entry.created.strftime("%F %R") }}</td>
<td>Ready</td>
{% else %}
<td>
<div class="thumb-wrapper">
<img src="{{ media_entry.thumb_url }}" alt="{{ media_entry.title }}" />
{% if media_entry.state == 'processing' %}
<div class="thumb-overlay-status thumb-processing">Processing...</div>
{% elif media_entry.state == 'failed' %}
<div class="thumb-overlay-status thumb-failed">Failed!</div>
{% endif %}
</div>
</td>
<td>{{ media_entry.title }}</td>
<td>{{ media_entry.created.strftime("%F %R") }}</td>
{% if media_entry.transcoding_progress %}
@ -49,61 +84,12 @@
{% else %}
<td>Unknown</td>
{% endif %}
{% endif %}
</tr>
{% endfor %}
</table>
{{ render_pagination(request, pagination) }}
{% else %}
<p><em>{% trans %}No media in-processing{% endtrans %}</em></p>
<p><em>{% trans %}You have not uploaded anything yet!{% endtrans %}</em></p>
{% endif %}
<h2>{% trans %}These uploads failed to process:{% endtrans %}</h2>
{% if failed_entries.count() %}
<table class="media_panel failed">
<tr>
<th>ID</th>
<th>Title</th>
<th>When submitted</th>
<th>Reason for failure</th>
<th>Failure metadata</th>
</tr>
{% for media_entry in failed_entries %}
<tr>
<td>{{ media_entry.id }}</td>
<td>{{ media_entry.title }}</td>
<td>{{ media_entry.created.strftime("%F %R") }}</td>
{% if media_entry.get_fail_exception() %}
<td>{{ media_entry.get_fail_exception().general_message }}</td>
<td>{{ media_entry.fail_metadata }}</td>
{% else %}
<td>&nbsp;</td>
<td>&nbsp;</td>
{% endif %}
</tr>
{% endfor %}
</table>
{% else %}
<p><em>{% trans %}No failed entries!{% endtrans %}</em></p>
{% endif %}
<h2>{% trans %}Your last 10 successful uploads{% endtrans %}</h2>
{% if processed_entries.count() %}
<table class="media_panel processed">
<tr>
<th>ID</th>
<th>Title</th>
<th>Submitted</th>
</tr>
{% for entry in processed_entries %}
<tr>
<td>{{ entry.id }}</td>
<td><a href="{{ entry.url_for_self(request.urlgen) }}">{{ entry.title }}</a></td>
<td>{{ entry.created.strftime("%F %R") }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p><em>{% trans %}No processed entries, yet!{% endtrans %}</em></p>
{% endif %}
{% endblock %}

View File

@ -97,6 +97,11 @@ add_route('mediagoblin.user_pages.processing_panel',
'/u/<string:user>/panel/',
'mediagoblin.user_pages.views:processing_panel')
add_route('mediagoblin.user_pages.processing_panel',
'/u/<string:user>/panel/<any(processed, processing, failed):state>/',
'mediagoblin.user_pages.views:processing_panel')
# Stray edit routes
add_route('mediagoblin.edit.edit_media',
'/u/<string:user>/m/<int:media_id>/edit/',

View File

@ -637,8 +637,10 @@ def collection_atom_feed(request):
return feed.get_response()
@active_user_from_url
@uses_pagination
@require_active_login
def processing_panel(request):
def processing_panel(request, page, url_user):
"""
Show to the user what media is still in conversion/processing...
and what failed, and why!
@ -653,33 +655,29 @@ def processing_panel(request):
return redirect(
request, 'mediagoblin.user_pages.user_home',
user=user.username)
# Get media entries which are in-processing
processing_entries = MediaEntry.query.\
filter_by(actor = user.id,
state = u'processing').\
order_by(MediaEntry.created.desc())
entries = (MediaEntry.query.filter_by(actor=user.id)
.order_by(MediaEntry.created.desc()))
# Get media entries which have failed to process
failed_entries = MediaEntry.query.\
filter_by(actor = user.id,
state = u'failed').\
order_by(MediaEntry.created.desc())
try:
state = request.matchdict['state']
# no exception was thrown, filter entries by state
entries = entries.filter_by(state=state)
except KeyError:
# show all entries
pass
processed_entries = MediaEntry.query.\
filter_by(actor = user.id,
state = u'processed').\
order_by(MediaEntry.created.desc()).\
limit(10)
pagination = Pagination(page, entries)
pagination.per_page = 30
entries_on_a_page = pagination()
# Render to response
return render_to_response(
request,
'mediagoblin/user_pages/processing_panel.html',
{'user': user,
'processing_entries': processing_entries,
'failed_entries': failed_entries,
'processed_entries': processed_entries})
'entries': entries_on_a_page,
'pagination': pagination})
@allow_reporting
@get_user_media_entry